原作者:CoffeeOneSugar

翻译:刘斌华

在我之前发表的文章中,我提到我最近热衷于Complex Event Processing (CEP) (复杂事件处理)。简单来说,CEP把数据流作为输入,根据一系列预定义的规则,把数据(或部分数据)重定向给监听者们;又或者是当发现数据中的隐含的模式(Pattern)时,触发事件。在大量数据被产生出来并需要进行实时地分析的场景下,CEP特别有用。

有一个很不错的软件项目,可以让你做到这一点,叫做ESPER。你可以在这里找到该项目的网站。Esper向程序员提供一个称为EPL的语言,有些类似于SQL语言,它可以很好地用于对规则和模式的配置,这些规则和模式将被应用到数据流上。

Esper附带的文档是相当完整的,但缺乏实际的例子,这使得它看起来难以被使用。所以这里给出一个Esper的5分钟指导。虽然下面的例子是用Java编写,但是其实Esper是同时支持Java和C#的。我这里假设你已经下载了Esper,如果没有,可以通过点击这个链接来完成。解压刚才下载的文件后,你应该在你磁盘的某个地方可以找到一个叫esper-3.1.0的文件夹。(译者:这篇文章比较早了,现在esper最新版本是5.2.0)

在开始前,你需要添加几个库文件到你的工程中,当然,esper-3.1.0.jar是其中之一,你也需要另外其他4个第三方的库文件,他们可以在esper-3.1.0.jar/esper/lib文件夹中找到。

现在开始我们的5分钟吧。在你把需要分析的数据丢到CEP引擎的管道中之前,需要把这些数据结构化到对象当中去。让我们用一个简单的例子,写一个类(或者叫它bean)来描述给定时间的某个股票的价格:

import java.util.Date;
public static class Tick {
String symbol;
Double price;
Date timeStamp; public Tick(String s, double p, long t) {
symbol = s;
price = p;
timeStamp = new Date(t);
}
public double getPrice() {return price;}
public String getSymbol() {return symbol;}
public Date getTimeStamp() {return timeStamp;} @Override
public String toString() {
return "Price: " + price.toString() + " time: " + timeStamp.toString();
}
}

它有3个属性:股票代码,价格和时间戳。在我们开始生成数以亿计的数据前,我们需要通知引擎它需要处理哪些对象,这是通过在实例化CEP引擎时,使用一个Configuration对象来实现的:

import com.espertech.esper.client.*;

public class main {

   public static void main(String [] args){

    //The Configuration is meant only as an initialization-time object.
Configuration cepConfig = new Configuration();
// We register Ticks as objects the engine will have to handle
cepConfig.addEventType("StockTick",Tick.class.getName()); // We setup the engine
EPServiceProvider cep = EPServiceProviderManager.getProvider("myCEPEngine",cepConfig);
}
}

作为测试目的,我们现在创建一个函数来生成随机的数据,并且把它们丢到CEP引擎当中,我们把这个函数叫做“GenerateRandomTick”,它把EPRuntime对象作为参数,这个对象用于把事件传递给CEP引擎:

import java.util.Random;
import com.espertech.esper.client.*; public class exampleMain {
private static Random generator=new Random(); public static void GenerateRandomTick(EPRuntime cepRT){
double price = (double) generator.nextInt();
long timeStamp = System.currentTimeMillis();
String symbol = "AAPL";
Tick tick= new Tick(symbol,price,timeStamp);
System.out.println("Sending tick:" + tick);
cepRT.sendEvent(tick);
} public static void main(String[] args) {
//The Configuration is meant only as an initialization-time object.
Configuration cepConfig = new Configuration();
cepConfig.addEventType("StockTick",Tick.class.getName()); EPServiceProvider cep=EPServiceProviderManager.getProvider("myCEPEngine",cepConfig); EPRuntime cepRT = cep.getEPRuntime();
}
}

现在,我们有了一个可以工作的CEP引擎,和不断输入的虚假的数据,是时候来创建我们的第一条规则了,用Esper的说法,我们的第一条EPL语句。要这么做,我们需要请引擎的管理员记录我们的语句。然后,CEP引擎会根据EPL语句的定义,过滤它收到的数据,当数据满足语句中的选择条件或者模式时,触发事件。

public static void main(String[] args) {
//The Configuration is meant only as an initialization-time object.
Configuration cepConfig = new Configuration();
cepConfig.addEventType("StockTick",Tick.class.getName());
EPServiceProvider cep = EPServiceProviderManager.getProvider("myCEPEngine",cepConfig);
EPRuntime cepRT = cep.getEPRuntime(); // We register an EPL statement
EPAdministrator cepAdm = cep.getEPAdministrator();
EPStatement cepStatement = cepAdm.createEPL("select * from " +
"StockTick(symbol='AAPL').win:length(2) " +
"having avg(price) > 6.0");
}

这里,我们的规则设置为:每当最近的2次数据的平均值大于6.0时,触发事件。

下一步,主要是创建一个监听者并把它和我们的选择规则产生的事件关联起来。可以这么做:

cepStatement.addListener(new CEPListener());

这里有不同的方式来实现监听者,下面的是其中最简单的一种。这里监听者只是简单地把它从引擎中收到的对象打印出来:

public static class CEPListener implements UpdateListener {
public void update(EventBean[] newData, EventBean[] oldData) {
System.out.println("Event received: "
+ newData[].getUnderlying());
}
}

到目前为止,看上去还不错。现在是测试我们的代码的时候了。让我们生成一些数据,看一切能否正常工作。可以在main函数中添加一下行来做到:

for(int i = ; i< ; i++)
GenerateRandomTick(cepRT);

现在所有的代码看上去如下所示(我把Tick类和入口函数放在一起,这样你就能把它们复制粘贴到一个文件并运行它们)

import com.espertech.esper.client.*;
import java.util.Random;
import java.util.Date; public class exampleMain { public static class Tick {
String symbol;
Double price;
Date timeStamp; public Tick(String s, double p, long t) {
symbol = s;
price = p;
timeStamp = new Date(t);
}
public double getPrice() {return price;}
public String getSymbol() {return symbol;}
public Date getTimeStamp() {return timeStamp;} @Override
public String toString() {
return "Price: " + price.toString() + " time: " + timeStamp.toString();
}
} private static Random generator = new Random(); public static void GenerateRandomTick(EPRuntime cepRT) { double price = (double) generator.nextInt();
long timeStamp = System.currentTimeMillis();
String symbol = "AAPL";
Tick tick = new Tick(symbol, price, timeStamp);
System.out.println("Sending tick:" + tick);
cepRT.sendEvent(tick); } public static class CEPListener implements UpdateListener { public void update(EventBean[] newData, EventBean[] oldData) {
System.out.println("Event received: " + newData[].getUnderlying());
}
} public static void main(String[] args) { //The Configuration is meant only as an initialization-time object.
Configuration cepConfig = new Configuration();
cepConfig.addEventType("StockTick", Tick.class.getName());
EPServiceProvider cep = EPServiceProviderManager.getProvider("myCEPEngine", cepConfig);
EPRuntime cepRT = cep.getEPRuntime(); EPAdministrator cepAdm = cep.getEPAdministrator();
EPStatement cepStatement = cepAdm.createEPL("select * from " +
"StockTick(symbol='AAPL').win:length(2) " +
"having avg(price) > 6.0"); cepStatement.addListener(new CEPListener()); // We generate a few ticks...
for (int i = ; i < ; i++) {
GenerateRandomTick(cepRT);
}
}
}

Output:

log4j:WARN No appenders could be found for logger (com.espertech.esper.epl.metric.MetricReportingPath).
log4j:WARN Please initialize the log4j system properly.
Sending tick:Price: 6.0 time: Tue Jul 21 01:11:15 CEST 2009
Sending tick:Price: 0.0 time: Tue Jul 21 01:11:15 CEST 2009
Sending tick:Price: 7.0 time: Tue Jul 21 01:11:15 CEST 2009
Sending tick:Price: 4.0 time: Tue Jul 21 01:11:15 CEST 2009
Sending tick:Price: 9.0 time: Tue Jul 21 01:11:15 CEST 2009
Event received: Price: 9.0 time: Tue Jul 21 01:11:15 CEST 2009

正如你看到的,只有最后两行数据平均值大于6,因此只有一个事件最终被引擎触发了。相当不错!

Oh,你或许担心输出中的第一行,是的,这里还有一点小问题。事实上,Esper使用的日志生成包log4j导致了这个警告。它是可以通过一个叫log4j.xml的文件来配置的,你可以在esper-3.1.0/examples下的某个例子中的/etc目录下找到它。我不认为给我们所有的程序都弄一个xml配置文件是个好主意,所以我们在以下代码中,用点技巧来配置我们的logger,在你的文件开始处加入些import和代码:

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.SimpleLayout;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
//and this in the main function before the rest of your code: public static void main(String [] args){ SimpleLayout layout = new SimpleLayout();
ConsoleAppender appender = new ConsoleAppender(new SimpleLayout());
Logger.getRootLogger().addAppender(appender);
Logger.getRootLogger().setLevel((Level) Level.WARN);
(...)

5分钟到此结束。

下一篇文章中,我将更深入一些来探索EPL语句,提供一些代码来连接两个引擎实现所谓的“事件精化”(event refinement)(译者:好像之后作者再也没有更新过了,所以,不要指望后续了:))

原文地址:https://coffeeonesugar.wordpress.com/2009/07/21/getting-started-with-esper-in-5-minutes/刘斌华原创翻译,转载请注明出处

5分钟开启Esper之旅的更多相关文章

  1. Win从环境变量开启MySQL之旅

    Win通过环境变量开启MySQL之旅 这篇文章主要介绍了Windows7下如何在命令行使用MySQL的相关资料,需要的朋友可以参考下 我在Win7下安装的MySQL版本是mysql-5.0.22-wi ...

  2. 开启RxSwift之旅——开篇

    开启RxSwift之旅——开篇 RxSwift 是 ReactiveX 在 Swift 下的实现.ReactiveX 是一个通过使用可观察序列来组合异步和基于事件的程序的库. 很多地方通常把 Reac ...

  3. Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅

    原文:Android零基础入门第7节:搞定Android模拟器,开启甜蜜之旅 在前几期中总结分享了Android的前世今生.Android 系统架构和应用组件那些事.带你一起来聊一聊Android开发 ...

  4. SpringBoot:1.开启SpringBoot之旅

    什么是 Spring Boot Spring Boot是Spring团队设计用来简化Spring应用的搭建和开发过程的框架.该框架对第三方库进行了简单的默认配置,通过Spring Boot构建的应用程 ...

  5. 开启Github之旅

    在那个远古时代,我以为可以用GoogleCode干点事,结果啥也没干好.如今,Github已经成为了业界标杆,就连Google.微软.Facebook的开源项目都往Github搬.Github作为全球 ...

  6. (一)C#编程基础复习——开启编程之旅

    回想当年学习编程,刚开始学习是非常艰苦的,可能是因为文科生原因,刚开始接触工科类的知识不是很擅长,上去大学第一年基本没有好好学习编程,入门C#编程基础一窍不通,也许那时年少无知,第二学期开始奋发图强, ...

  7. 一分钟开启Tomcat https支持

    1.修改配置文件 打开tomcat/conf/server.xml配置文件,把下面这段配置注释取消掉,keystorePass为证书密钥需要手动添加,创建证书时指定的. <Connector p ...

  8. 开启Java之旅

    学习应用系统的服务器开发,也许并不算什么“旅行”,也不会那么‘愉快’.但是,我希望这次能够同以往有所不同,更加努力地学习J2EE. 从2月份开始,从事web前端开发,并在公司的的项目中,独立完成了4个 ...

  9. 开启Laravel之旅的标准姿势

    1.github下载最新的laravel https://github.com/laravel/laravel 2.下载到本地,改名,composer install,安装项目的依赖包 compose ...

随机推荐

  1. brew

    brew 又叫Homebrew,是Mac OSX上的软件包管理工具,能在Mac中方便的安装软件或者卸载软件, 只需要一个命令, 非常方便 brew类似ubuntu系统下的apt-get的功能. 安装下 ...

  2. Selenium2学习-042-Selenium3启动Firefox Version 48.x浏览器(ff 原生 geckodriver 诞生)

    今天又被坑了一把,不知谁把 Slave 机的火狐浏览器版本升级为了 48 的版本,导致网页自动化测试脚本无法启动火狐的浏览器,相关的网页自动化脚本全线飘红(可惜不是股票,哈哈哈...),报版本不兼容的 ...

  3. CMake的一些使用

    1. 使用QT加载CMake工程 打开QT,"文件"->"打开文件或项目"->选中CMakeLists.txt文件,出现对话框,单击下一步,点击&q ...

  4. inotify监控目录变化重启服务器tornado项目

    pycharm 配置了提交服务器项目每次pycharm修改后,虽然保存到服务器但是项目还得自己去服务器kill再启动.就花几分钟写了shell脚本用于监控项目目录变化并重启tornado项目的脚本 如 ...

  5. 创建redis集群

    假设你已经安装好了redis ,如果还没有请安装 将多个实例跑起来 创建一个目录,比如 redis-cluster 把redis-server拷贝到这个目录下 在目录下为每一个实例创建一个文件夹 在每 ...

  6. python-study1 in hubei

    1.安装好python后要配置环境变量(C:\Python27\Scripts---能找到pip.exe和easy_install.exe和C:\Python27---能找到python.exe) 2 ...

  7. Oracle 正则表达式函数-REGEXP_INSTR 使用例子

    原文在这 戳 REGEXP_INSTR 6个参数 第一个是输入的字符串 第二个是正则表达式 第三个是标识从第几个字符开始正则表达式匹配.(默认为1) 第四个是标识第几个匹配组.(默认为1) 第五个是指 ...

  8. PO VO BO DTO POJO DAO(转)

    2EE开发中大量的专业缩略语很是让人迷惑, 特别是对于刚毕业的新人来说更是摸不清头脑.若与公司大牛谈技术人家出口就是PO VO BO DTO POJO DAO 等,让新人们无比仰慕大牛. PO(bea ...

  9. WIN10 多用户登录

    WIN10 多用户登录 参考下面链接 http://www.mysysadmintips.com/windows/clients/545-multiple-rdp-remote-desktop-ses ...

  10. Centos下安装nginx rpm包

    1 在nginx官方网站下载一个rpm包,下载地址是:http://nginx.org/en/download.html wget http://nginx.org/packages/centos/6 ...