Esper学习之十四:Pattern(一)

转载请注明出处:http://blog.csdn.net/luonanqin



       前述的几篇关于EPL语法的文章,如果各位都掌握得很好,那基本上应付不少业务场景应该说是轻轻松松。但是总有那么些复杂场景只靠那点基础语法还是搞不定,比如说:某个用户在请求登录服务时,n秒内连续m次未登录成功,可视为该ip在暴力破解密码。又或者:用户在页面上的操作间隔超过n秒即认为该用户已关闭该网页。也许上面的几个例子不够好或者已经有别的方式实现,但是Esper确实能够将其抽象成多个关联的事件进行处理。像这类具有关联性事件的处理,即是本篇的中心内容——Pattern,它就像一个我们自定的模板,如果事件按照模板进入引擎,就会触发监听器,我们就能捕捉到信号并进行接下来的处理。

       今天这篇主要讲讲一些基础知识以便领大家入门,具体的语法下篇会有详细说明。


1. Pattern Atoms and Pattern operators
Pattern是通过原子事件和操作符组合在一起构成模板。原子事件有3类,操作符有4类,具体如下:

原子事件:
1). 普通事件:包括POJO,Map,Array,XML
2). 时间事件:包括间隔n个时间单位、crontab
3). 自定义插件:用于观察特定事件的发生

操作符:
1). 重复操作符:every, every-distinct, [num] and until
2). 逻辑操作符:and, or, not
3). 顺序操作符:->(Followed by)
4). 事件生命周期操作符:timer:within, timer:withinmax, while-expression, 自定义插件

关于操作符,自然会有优先级,具体如下:

Precedence Operator Description Example
1

guard postfix

where timer:within and while (expression) (incl. withinmax and plug-in pattern guard)

MyEvent where timer:within(1 sec)

2

unary

every, not every, distinct

every MyEvent
timer:interval(5 min) and not MyEvent

3 repeat [num], until

[5] MyEvent

[1..3] MyEvent until MyOtherEvent

4 and and every (MyEvent and MyOtherEvent)
5 or or every (MyEvent or MyOtherEvent)
6 followed by -> every (MyEvent -> MyOtherEvent)




















上面的内容各位可以先有个印象,方便理解之后的详解。


2. Pattern Filter Expression
Pattern的Filter表达式和普通的表达式没有区别,我就不展开讲解了,各位看看下面几个例子就好,除了Filter之外的东西暂时不用关心是什么意思。

1). every e1=RfidEvent -> e2=RfidEvent(assetId=e1.assetId)
2). every e1=RfidEvent -> e2=RfidEvent(MyLib.isInRadius(e1.x, e1.y, x, y) and zone in (1, e1.zone))
3). every (RfidEvent(zone > 1) and RfidEvent(zone < 10))

3. Controlling Event Consumption
       上面说到了Filter,因为Pattern可以由多个原子事件组成,那么Filter自然也会有多个,正常情况下,所有的Filter都会对进入引擎的事件进行判定,但是我们也有只需要判定一次的时候,只要满足了某个Filter,那么其他的Filter就不用管这个事件了。Esper考虑到了这个需求,我们只需要在Filter表达式后面加个@consume注解即可,此注解可以跟随数字,表示过滤的优先级。默认优先级为1,数值越大优先级越高。

为了结合上面几节的知识,我给了个完整的实例:

package example;

import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPRuntime;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;
import com.espertech.esper.client.EPStatement;
import com.espertech.esper.client.EventBean;
import com.espertech.esper.client.UpdateListener;

/**
 * Created by Luonanqin on 8/11/14.
 */
class ConsumeEvent {

	private int id;
	private String name;
	private int age;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String toString() {
		return "ConsumeEvent{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
	}
}

class PatternConsumeListener1 implements UpdateListener {

	public void update(EventBean[] newEvents, EventBean[] oldEvents) {
		if (newEvents != null) {
			for (int i = 0; i < newEvents.length; i++) {
				System.out.println("a: " + newEvents[i].get("a"));
				System.out.println("b: " + newEvents[i].get("b"));
			}
		}
	}
}

class PatternConsumeListener2 implements UpdateListener {

	public void update(EventBean[] newEvents, EventBean[] oldEvents) {
		if (newEvents != null) {
			for (int i = 0; i < newEvents.length; i++) {
				System.out.println("a: " + newEvents[i].get("a"));
				System.out.println("b: " + newEvents[i].get("b"));
				System.out.println("c: " + newEvents[i].get("c"));
			}
		}
	}
}

public class PatternConsumeTest {

	public static void main(String[] args) {
		EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
		EPAdministrator admin = epService.getEPAdministrator();
		EPRuntime runtime = epService.getEPRuntime();

		String consume = ConsumeEvent.class.getName();

		String epl1 = "every (a=" + consume + "(id = 1)@consume and b=" + consume + "(name = 'luonq'))";
		System.out.println("EPL1: " + epl1 + "\n");

		EPStatement stat1 = admin.createPattern(epl1);
		stat1.addListener(new PatternConsumeListener1());

		ConsumeEvent ce1 = new ConsumeEvent();
		ce1.setId(1);
		ce1.setName("luonq");
		System.out.println("Send Event: " + ce1);
		runtime.sendEvent(ce1);

		System.out.println();

		ConsumeEvent ce2 = new ConsumeEvent();
		ce2.setId(2);
		ce2.setName("luonq");
		System.out.println("Send Event: " + ce2);
		runtime.sendEvent(ce2);

		stat1.destroy();
		System.out.println();

		String epl2 = "every (a=" + consume + "(id = 1)@consume(2) or b=" + consume + "(name = 'luonq')@consume(3) or c=" + consume + "(age > 2))";
		System.out.println("EPL2: " + epl2 + "\n");

		EPStatement stat2 = admin.createPattern(epl2);
		stat2.addListener(new PatternConsumeListener2());

		ConsumeEvent ce3 = new ConsumeEvent();
		ce3.setId(1);
		ce3.setName("luonq");
		ce3.setAge(3);
		System.out.println("Send Event: " + ce3);
		runtime.sendEvent(ce3);

		ConsumeEvent ce4 = new ConsumeEvent();
		ce4.setId(1);
		ce4.setName("luonqin");
		ce4.setAge(1);
		System.out.println("Send Event: " + ce4);
		runtime.sendEvent(ce4);

		ConsumeEvent ce5 = new ConsumeEvent();
		ce5.setId(3);
		ce5.setName("luonqin");
		ce5.setAge(5);
		System.out.println("Send Event: " + ce5);
		runtime.sendEvent(ce5);
	}
}

执行结果:

EPL1: every (a=example.ConsumeEvent(id = 1)@consume and b=example.ConsumeEvent(name = 'luonq'))

Send Event: ConsumeEvent{id=1, name='luonq', age=0}

Send Event: ConsumeEvent{id=2, name='luonq', age=0}
a: ConsumeEvent{id=1, name='luonq', age=0}
b: ConsumeEvent{id=2, name='luonq', age=0}

EPL2: every (a=example.ConsumeEvent(id = 1)@consume(2) or b=example.ConsumeEvent(name = 'luonq')@consume(3) or c=example.ConsumeEvent(age > 2))

Send Event: ConsumeEvent{id=1, name='luonq', age=3}
a: null
b: ConsumeEvent{id=1, name='luonq', age=3}
c: null
Send Event: ConsumeEvent{id=1, name='luonqin', age=1}
a: ConsumeEvent{id=1, name='luonqin', age=1}
b: null
c: null
Send Event: ConsumeEvent{id=3, name='luonqin', age=5}
a: null
b: null
c: ConsumeEvent{id=3, name='luonqin', age=5}
这里先简单说明下,every关键字表示引擎把每个事件都进行Pattern的匹配,而不管上一个匹配是否完成。or和and就是或和且的意思,表示满足某个以及满足所有。

去掉consume的执行结果:

EPL1: every (a=example.ConsumeEvent(id = 1) and b=example.ConsumeEvent(name = 'luonq'))

Send Event: ConsumeEvent{id=1, name='luonq', age=0}
a: ConsumeEvent{id=1, name='luonq', age=0}
b: ConsumeEvent{id=1, name='luonq', age=0}

Send Event: ConsumeEvent{id=2, name='luonq', age=0}

EPL2: every (a=example.ConsumeEvent(id = 1) or b=example.ConsumeEvent(name = 'luonq') or c=example.ConsumeEvent(age > 2))

Send Event: ConsumeEvent{id=1, name='luonq', age=3}
a: ConsumeEvent{id=1, name='luonq', age=3}
b: null
c: null
Send Event: ConsumeEvent{id=1, name='luonqin', age=1}
a: ConsumeEvent{id=1, name='luonqin', age=1}
b: null
c: null
Send Event: ConsumeEvent{id=3, name='luonqin', age=5}
a: null
b: null
c: ConsumeEvent{id=3, name='luonqin', age=5}
上面的例子可能看得不是很懂,不过没关系,等到后面讲操作符进行详解后再来回顾就很简单了。



本篇内容较少,主要是将一些必备的基础知识跟各位说说,下一篇会对围绕操作符展开,如果篇幅过长,可能会分成两篇为大家献上。敬请期待……




你可能感兴趣的:(数据,开源,Esper,CEP)