小试 S4

S4 很早的时候就听说了,这次接触了一个实际的应用问题,于是正式开始学习使用 S4。

安装

这个过程官方的文档里面有说法,大概是 git clone 需要的 source code tree,然后用 gradle 完成编译。个人觉得要了解 S4 其实是要搞清楚它处理问题的方法。所谓 stream processing,其实就是一个类似 event driven 的程序:我们知道写一个 GUI,一般都是通过对一些 event 进行 dispatch,然后每个部分分别处理,然后继续 propogate。问题是 S4 定义好了一系列的 abtraction 封装了类似的过程(s4-core),它还需要与外部的数据交互,这就需要对应的 adaptor,同时产生数据的程序需要与 adaptor 通讯。这就是那个文档中三个程序分别的作用。

用 iPad 上的 mindnode 画的,画到一半发现可以导出为 pdf 就转帖了过来。其实后面还有几个 point 没写上去。发现其实这个东西做笔记还不错。

核心技术

在 S4 实现里面一个核心的技术是利用了 Spring 这个 framework 来“动态”的从配置文件生成需要的对象(wiki 链接),这是所谓的 inversion of controldependency injection 思想的推广)的一种体现。这解决的是 “main” 的抽象问题。为什么这么说呢?我们知道 OOP 原则之一 operate on interfaces,为此我们将不同的对象之间的关系通过 interface 的抽象,使得他们之间并不直接相互作用,而是建立在 interface 所规定的少数一两个函数上;另外为很多同类对象我们建立 abstract class,让 abstract class 作为整个 object hierarchical 的 interface 与别的类发生关系。这样理论上我们创建一个“可执行文件”就应该使用这些高度抽象的 interface 完成我们的业务逻辑,但事实上我们可能常通过命令行参数之类的决定产生什么具体的类(违背了 OOP 原则 DIP)。一种可能性就是应该通过某种方式读取相关的 configuration,然后自动的创建具体的对象,并放在合适的接口上,main 里面就只是完成抽象接口上的业务逻辑。

这就是 spring 或者更 heavy 一些 J2EE 的 beans 所要解决的问题之一。spring 作为一个稍微轻量级一些的解决方案也不仅仅只包括这样一个功能:通过 xml 文件描述对象的构造(包括对 constructor 的 injection、setter 的 injection 乃至 reference 都能做),然后动态的载入该文件进行 parsing 和 generation 生成需要的对象(完成这一任务的一般称为 assembler,它将静态的对象转换成 dynamic binding)。可想而知这一过程大量使用了 java 自己的 reflection。

实现这样一个任务对 C++ 来说也并不是不可能。可以参看 autumn framework(别人叫春天,我就叫秋天,好无聊啊好无聊 -,-)。但是这种可能对类似 Java 通过 dynamic binding 生成的类有效,对 template 获得的 concept 的实现不大可行。

先看例程

我们先看看一个只有一个 PE 的例子。事实上,数据里面含有三类:对应于 Speech、Sentence 和 Highlight 这三个类,数据文件第一行为三类给出了对应的 index 编号,定义了 named stream 名称,这种 stream 可以通过 S4 自带的 generate-load.sh 发送到 S4 adaptor。数据格式是按行分割的 JSON,

{"io.s4.example.speech01.Speech":{"classIndex":0,"streamName":"RawSpeech"},"io.s4.example.speech01.Sentence":{"classIndex":1,"streamName":"RawSentence"},"io.s4.example.speech01.Highlight":{"classIndex":2,"streamName":"RawHighlight"}}
{"_index":0,"id":12000000,"location":"gettysburg, pa, us","speaker":"abraham lincoln","time":1242799200000}
{"_index":1,"id":12000001,"speechId":12000000,"text":"Four score and seven years ago our fathers brought forth on this continent a new nation, conceived in liberty and dedicated to the proposition that all men are created equal.","time":1242799205000}

由此,我们不难发现,我们只需要提供前三个类(都是 POJO)的实现,然后提供对应 PE 就行了,简单的来说我们提供一个 SentenceReceiverPE 的话如下

package io.s4.example.speech01;

import io.s4.processor.AbstractPE;

public class SentenceReceiverPE extends AbstractPE {
  public void processEvent(Sentence sentence) {
    System.out.printf("Sentence is '%s', location %s\n",
                      sentence.getText(), sentence.getLocation());
  }
  @Override
  public void output() {
    // not called in this example
  }
}

对应的 Sentence 如下,

public class Sentence {
  private long id;
  private long speechId;
  private String text;
  private long time;
  private String location;
  // more...
}

值得注意的是,这里的数据里面产生 Sentence 的时候并没有 location,而仅仅有其他的一些内容,因此前面的 PE 并不能正确输出 location。下面是 PE 的相关配置。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans             http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

  <bean id="eventCatcher" class="io.s4.example.speech01.SentenceReceiverPE">
    <property name="keys">
      <list>
        <value>RawSentence *</value>
      </list>
    </property>
  </bean>

</beans>

OK,后面我们有时间搭一个 S4 的单机实验…

——————
And you shall go to your fathers in peace; you shall be buried in a good old age.

Advertisements
小试 S4

发表评论

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / 更改 )

Twitter picture

You are commenting using your Twitter account. Log Out / 更改 )

Facebook photo

You are commenting using your Facebook account. Log Out / 更改 )

Google+ photo

You are commenting using your Google+ account. Log Out / 更改 )

Connecting to %s