Esper學習之三:進程模型

轉載請註明出處:http://blog.csdn.net/luonanqin



        上週末本來要更新第三篇的,但是因爲突發事情沒能完成。這周我會爭取更新兩篇,讓感興趣的同學一次看個夠。

       之前對Esper所能處理的事件結構進行了概述,並結合了例子進行講解,不清楚的同學請看Esper學習之二:事件類型。今天主要爲大家解釋一下Esper是怎麼處理事件的,即Esper的進程模型。

1.UpdateListener

UpdaterListener是Esper提供的一個接口,用於監聽某個EPL在引擎中的運行情況,即事件進入併產生結果後會通知UpdateListener。接口如下

[java] view plaincopy
  1. package com.espertech.esper.client;  
  2.   
  3. import com.espertech.esper.client.EventBean;  
  4.   
  5. public interface UpdateListener  
  6. {  
  7.     public void update(EventBean[] newEvents, EventBean[] oldEvents);  
  8. }  

接口很簡單,就一個update方法,其中包括兩個EventBean數組,至於兩個參數的含義稍後再說。EventBean中有一個最常用的get方法,是用來得到EPL中某個字段的值。例如:

  1. EPL:select name from User  
  2. //假設newEvents長度爲一  
  3. newEvents[0].get("name")能得到進入的User事件的name屬性值  
  4.   
  5. EPL:select count(*) from User.win:time(5 sec)  
  6. //假設newEvents長度爲一  
  7. newEvents[0].get("count(*))能得到5秒內進入引擎的User事件數量有多少  

get方法最常用,此外還有getUnderlying等方法,以後會專門寫一篇介紹EventBean的。


2.Insert and Remove Stream

Insert表示進入引擎,Remove表示移出引擎,事件在Esper中會因爲某類EPL纔會經歷這兩種狀態。對應於UpdateListener接口就是newEvents和oldEvents,因爲處於這兩種狀態的事件不一定只有一個,所以newEvents和oldEvents就是數組形式。舉個例子說明下

  1. EPL:select * from User  

從此圖可以看出,隨着時間推移,每個進入到引擎的W事件都是newEvents,即Insert Stream。W後括號裏的值爲屬性值,可忽略。

有人可能要問了,爲什麼這裏oldeEvents什麼都沒有。那是因爲EPL的關係。看下面的例子

  1. EPL:select * from User.win:length(5)  

注:win:length(5)是個view,詳細的後面會專門講解,這裏先暫時理解爲Esper開放一個空間並最多可同時存放5個事件(此空間其實就是大小爲5的數組)


       由圖可知,length window可存放w1,w2等事件,在w6事件進入之前,每個事件進入都屬於newEvents。直到w6進入後,length window不能容納w1~w6的事件,必須把w1事件移出,即w1爲oldEvents。length window就像一個隊列,每當事件進入隊列時,就會觸發updateListener並告知有新事件進入。當隊列滿了,再進入一個新事件時,Esper會觸發UpdateListener告知有新事件進入並且有舊事件移出,正如上圖所示的w6和w1。


實際上這個EPL觸發監聽器都只能看到newEvents,看不到oldEvents。如果想看到oldEvents,EPL要改寫一下:

  1. EPL:select irstream * from User.win:length(5)  

       默認情況下,Esper認爲你只想讓newEvents觸發監聽器,即istream(insert stream)。如果想讓oldEvents觸發監聽器,那麼爲rstream(remove stream)。如果兩個都想,那麼爲irstream。當然這個默認情況是可以配置的,以後會說到這個問題。

       不過對於rstream,在我看來他有個bug,因爲在運行時我發現,oldEvents觸發監聽器時,理論上應該是oldEvents這個參數有值,並且api裏也明確說明了這一點(就算他沒說明,按照常理推斷也應該是oldEvents有值),但是實際上是newEvents有值,oldEvents爲null。雖然說數據沒有錯,但是這個似乎不合常理。


3.Filter and Where-Clause

EPL有兩種過濾事件的方式,一種是過濾事件進入view(可以把view理解爲一個窗口),即Filter。另一種是讓事件都進入view,但不觸發UpdateListener,即Where子句。關於這兩種語法後面會詳細講解,這裏就只是簡單介紹。

Filter:

  1. // Apple事件進入Esper,只有amount大於200的才能進入win:length,並且length長度爲5  
  2. EPL:select * from Apple(amount>200).win:length(5)  

從圖上可以看出,只有amount大於200,Esper才允許Apple事件進入view,並且作爲一個newEvent觸發UpdateListener


Where-Clause:

  1. // Apple事件進入Esper並進入win:length(5),但是隻有amount大於200的才能觸發UpdateListener  
  2. EPL:select * from Apple.win:length(5) where amount>200  

由圖上可以看出,Apple事件先進入view,然後才被where子句過濾,以至於被過濾掉的事件不會作爲newEvent觸發UpdateListener

其實單看兩個EPL,就能發現一個過濾是在進入view前,一個過濾是在view後,所以大家在應用的時候要注意。PS:在我寫這段的時候才發現以前認爲這兩種是一樣的效果是錯誤滴- -!


4.Aggregation and Grouping

之前說過EPL是類SQL語法,所以也會有聚合和分組的功能。語法和SQL基本一樣,下面給大家展示一下:

  1. // 統計進入的5個Apple事件,amount的總數是多少  
  2. select sum(amount) from Apple.win:length_batch(5)  
  3.   
  4. // 統計進入的5個Apple事件,amount的總數是多少,並按照price分組  
  5. select price, sum(amount) from Apple.win:length_batch(5) group by price  
  6.   
  7. // 統計進入的5個Apple事件,amount的總數和name,並按照price分組  
  8. select price, namesum(amount) from Apple.win:length_batch(5) group by price  

       最後一個和前一個的區別在於name也在統計的範圍內,所以當name和price都一樣的兩個事件進入Esper,會有兩個一模一樣的事件作爲newEvent觸發UpdaterListener,即price,name,sum(amount)都一樣。當然要是group by name, price的話,就只會有一個事件觸發監聽器了。


       今天介紹了Esper處理事件時的一些基本知識,對以後的深入學習是必不可少的。明天會再寫一篇,內容是關於context,中文翻譯爲上下文我覺得不妥,我的理解是對EPL的運行增加了外在約束,想繼續學習的請繼續關注。

發佈了16 篇原創文章 · 獲贊 8 · 訪問量 11萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章