escper的使用整理

本文介绍了CEP和ESP的概念,CEP用于从事件流中发现复杂模式,而ESP则从事件流中提取有用信息。适合场景如监控、犯罪预防等。文章详细讲解了使用Esper进行事件处理的步骤,包括创建EventClass、实现UpdateListener、配置、获取EPServiceProvider等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 一、CEP和ESP的概念

CEP:复杂事件处理,是一种新兴的基于事件流的技术,它用于处理事件、从事件流中发现复杂模式。它将系统数据看做不同类型的事件,通过分析事件间的关系,建立不同事件关系序列库,利用过滤、关联、聚合等技术,最终由简单事件产生高级事件或商业流程。

ESP:事件流处理,目的是从事件流中获得有用的事件,进而从中获得有用信息。

CEP/ESP适合的场景包括:监控、犯罪预防、网络攻击、市场趋势分析。

比如示例:

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;
/**
1. 这是一个EventClass对象
 */
public class Apple {
    private int id;
    private int price;

    public int getId()
    {
        return id;
    }

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

    public int getPrice()
    {
        return price;
    }

    public void setPrice(int price)
    {
        this.price = price;
    }
}

// 2. 创建一个class实现UpdateListener接口
class AppleListener implements UpdateListener
{

    public void update(EventBean[] newEvents, EventBean[] oldEvents)
    {
        if (newEvents != null)
        {
            Double avg = (Double) newEvents[0].get("avg(price)");
            System.out.println("Apple's average price is " + avg);
        }
    }

}


调用:

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;
/**
 */
public class Test {
    public static void main(String[] args) {
	// 创建一条语句(类似于JDBC里面的Statement的)
        EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();

        EPAdministrator admin = epService.getEPAdministrator();

        String product = Apple.class.getName();
	// 获取类SQL语句. 
        String epl = "select avg(price) from " + product + ".win:length_batch(3)";

        EPStatement state = admin.createEPL(epl);   
	// 添加一个监听器
        state.addListener(new AppleListener());

	// 发送事件
        EPRuntime runtime = epService.getEPRuntime();

        Apple apple1 = new Apple();
        apple1.setId(1);
        apple1.setPrice(5);
        runtime.sendEvent(apple1);	// 发送事件

        Apple apple2 = new Apple();
        apple2.setId(2);
        apple2.setPrice(2);
        runtime.sendEvent(apple2);      // 发送事件


        Apple apple3 = new Apple();
        apple3.setId(3);
        apple3.setPrice(5);
        runtime.sendEvent(apple3);    // 发送事件
    }
}

输出:4.0

使用Esper的基本步骤:

  1. 创建一个EventClass
  2. 创建一个class实现UpdateListener接口
  3. 创建一个Configuration实例
  4. 通过EPServiceProviderManager获得EPServiceProvider对象
  5. 通过EPServiceProder和EPL查询语句,创建EPStatement对象
  6. 将listener和EPStatement挂钩
  7. 使用epService.getEPRuntime().sendEvent(event)向引擎发送事件
我们要做的事情就是定义DSL语言,然后让它执行。

关于如何让EPS调用自定义函数?

二、关于EPL能够处理的事件类型
目前EPL能够处理的事件类型:POJO、MAP、ObjectArray、XML
2.1 POJO
Esper要求对每一个私有属性要有getter方法。不必按JavaBean规定的格式,但getter方法是必须的。也支持复杂的数据结构
比如如下的一个POJO对象
import java.util.List;
import java.util.Map;

public class Person
{
	String name;
	int age;
	List<Child> children;
	Map<String, Integer> phones;
	Address address;

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public List<Child> getChildren()
	{
		return children;
	}

	public Map<String, Integer> getPhones()
	{
		return phones;
	}

	public Address getAddress()
	{
		return address;
	}
	
}

class Child
{
	String name;
	int gender;
	// 省略getter方法
}

class Address
{
	String road;
	String street;
	int houseNo;
	// 省略getter方法
}
支持这样写类SQL语句:
#select age,children,address from Person where name=''张三'
这样得到的children是一个列表,如果不想要所有的,而是想要第二个,那Person需要改一下
import java.util.List;
import java.util.Map;

public class Person
{
	String name;
	int age;
	List<Child> children;
	Map<String, Integer> phones;
	Address address;

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}
        // 可以这样写get的方法
	public Child getChildren(int index)
	{
		return children.get(index);
	}

	public int getPhones(String name)
	{
		return phones.get(name);
	}

	public Address getAddress()
	{
		return address;
	}
	// Address,Child不变
}
对应的EPL如下:
#select children[1],phones('home'),address.road from Person where name='张三'
select 后面的这些列其实就是从POJo中的get方法拿数据的。

Esper支持事件更新,对此Esper需要提供setter方法。示例如下:

import java.util.List;
import java.util.Map;

public class Person
{
	String name;
	int age;
	List<Child> children;
	Map<String, Integer> phones;
	Address address;

	public String getName()
	{
		return name;
	}

	public int getAge()
	{
		return age;
	}

	public Child getChildren(int index)
	{
		return children.get(index);
	}
	
	// 此方法用于phones属性的更新  、 支持set方法
	public void setPhones(String name, Integer number){
		phones.put(name, number);
	}

	public int getPhones(String name)
	{
		return phones.get(name);
	}

	public Address getAddress()
	{
		return address;
	}
	// Address,Child不变
}
对应的EPL如下:
#update Person set  phones('home') = 123456789 where name='张三'

2. Map
Esper支持原生Java map结构的事件。相对POJO,Map结构更利于热加载。不需要重启JVM,如果系统对重启比较敏感,建议使用Map来定义事件结构。

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.espertech.esper.client.EPAdministrator;
import com.espertech.esper.client.EPServiceProvider;
import com.espertech.esper.client.EPServiceProviderManager;

public class PersonMap
{
	public static void main(String[] args)
	{
		EPServiceProvider epService = EPServiceProviderManager.getDefaultProvider();
		EPAdministrator admin = epService.getEPAdministrator();
		
		// Person定义
		Map<String,Object> person = new HashMap<String,Object>();
		person.put("name", String.class);
		person.put("age", int.class);
		person.put("children", List.class);
		person.put("phones", Map.class);
		
		// 注册Person到Esper
		admin.getConfiguration().addEventType("Person", person);
	}
}
对应的EPL跟POJO没有区别:
#select age,children from Person where name='张三'
3. Object Array
对象数组和Map很像,基本没有差别。只是定义方式不一样。

三、关于进程模型
Esper是怎么处理事件的,即Esper的进程模型。
3.1 UpdaterListener是Esper提供的一个接口,用于监听某个EPL在引擎中的运行情况,即事件进入并产生结果后会通知UpdateListener. 接口如下:
package com.espertech.esper.client;

import com.espertech.esper.client.EventBean;

public interface UpdateListener
{
    public void update(EventBean[] newEvents, EventBean[] oldEvents);
}
接口就很简单,就一个update方法,包括两个EventBean数组。
#EPL: select name from User
#newEvents[0].get("name")   能得到进入的User事件的name属性值

2. Insert and remove stream
Insert表示进入引擎,remove表示移出引擎。

3. Filter and where-clause
EPL有两种过滤事件的方式:一种是过滤事件进入view,即Filter, 另一种是让事件都进入view,但不触发UpdateListener,即where 子句。
// Apple事件进入Esper,只有amount > 200才进入win.length,并且length长度为5
EPL: select * from Apple(amount > 200).win:length(5)

4. 聚合与分组
类SQL里面的sum与group by 操作类似的。
// 统计进入的5个Apple事件,amount的总数是多少
select sum(amount) from Apple.win:length_batch(5)

四、关于context
4.1 context基本语法
create context context_name partition [by] event_property [and event_property [and ...]] from stream_def 
[, event_property [...] from stream_def] [, ...]
说明:
context_name: 为context的名字,并且唯一。如果重复,会说明已存在
event_property为事件的属性名,多个属性名之间用and连接,也可以用逗号连接。



参考文档:
http://blog.youkuaiyun.com/luonanqin/article/details/10946329












评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值