Esper解析

最近在看論文,發現文中有些語言自己未曾見過,經過一番搜索,才發覺是自己接觸到了新知識。 官網: http://esper.codehaus.org/about/esper/esper.html Esper爲一款開源的實時分析引擎。是一個強大的支持ESP(Event Stream Process)和CEP(Complex Event Process)分析的引擎,其EPL解析語言可以通過簡單的寫一條類似SQL一樣的語句完成統計。 說到Esper,不得不說一下CEP。CEP即Complex Event Process,中文意思就是“複雜事件處理”。聽起來好像很複雜,實際上就是基於事件流進行數據處理,把要分析的數據抽象成事件,然後將數據發送到CEP引擎,引擎就會根據事件的輸入和最初註冊的處理模型,得到事件處理結果。 CEP是一種標準,Esper只是對這個標準的一種開源實現。除了Esper,很多大公司也有類似的商業軟件,比如IBM,Sybase等等,聽說巨貴無比。CEP的一個重要特點就是他是一個內存計算工具和類SQL語句。內存計算可以說是一把雙刃劍。好處自不必說,一個字:快!壞處也顯而易見,數據有丟失的風險,而且還有容量的限制(實時計算其實並不受制於內存大小,而是得看如何對實時進行定義,也就是具體的業務來決定了)。所以如果業務不能容忍數據丟失,那麼高可用方案就必須做好,不過Esper的高可用很不好做。 CEP的類SQL語句,可以理解爲處理模型的定義與描述。這是運行在CEP引擎中的特殊語句,之所以叫他類SQL,是因爲它和SQL確實很像,除了select,insert,delete,update,而且也有avg,count等函數。所以對於會SQL的人來說,他的語法結構大致還是能猜出一二的。在Esper中,這個句子叫做EPL,即Event Process Language。作爲Esper的核心內容,對於它的講解有三四百頁的英文文檔。 相比之下,storm,twitter做的,大公司大品牌,完全開源,看上去的確不錯。但是看了一下功能,相當於是一個實時Hadoop,只能幫你計算,但是怎麼算還得你自己寫程序,離我想要的功能上有一些距離。目前想使用實時分析的產品一大堆,大部分產品數據量都不大,每個都給他們寫段分析代碼,加上調試,能累死人,維護代價高。首先介紹一下ESPER的大體結構,esper從內容上分爲兩塊,esper的核心esper-4.x.x.jar和esper-io。 (1)esper的核心包包含了EPL語法解析引擎,事件監聽機制,事件處理等核心模塊。 (2)esper的io包含從各種數據源讀取數據以及將輸出結果寫入各種數據源,包括excel,database,JMS,http,socket,XML。1. Event對象:ESPER處理的事件的最小單位,一個任意的JavaBean對象,屬性支持簡單的Java類型、數組、map、以及嵌套JavaBean,很靈活,下面是一個簡單的Event對象:public class OrderEvent {private String itemName;private double price;public OrderEvent(String itemName, double price) {this.itemName = itemName;this.price = price;}public String getItemName() {return itemName;}public double getPrice() {return price;}} 2.EPL:EPL是ESPER的核心,它類似於SQL,但是和SQL的執行方式不同。SQL是數據在那裏,你每次執行SQL就會觸發一次查詢;而EPL是查詢在這裏,數據輸入達到一定條件即可觸發查詢。 這個條件可以有多種: a).每個event對象來就觸發一次查詢,並只處理當前對象select * from OrderEvent這個EPL語句會在每個OrderEvent對象到達後,並將該event交給後續的Listener進行處理。但是這種用法不多見,意義不大。 b).窗口處理模式: EPL最大的特色就是這個窗口處理模式,有兩種窗口,時間窗口和長度窗口。 時間窗口:大家想一下,如果有一個場景,要獲取最近3秒內OrderEvent的price的平均值,那該怎麼做呢?一般的做法需要做個後臺線程來做3秒的時間統計,時間到了再做後續處理,雖然不復雜,但是也挺繁瑣的。來看看EPL是怎麼做的:select avg(price) from test.OrderEvent.win:time(3 sec)win:time(3sec)就是定義了3秒的時間窗口,avg(price)就是統計了3秒內的OrderEvent對象的price的平均值。 長度窗口:長度窗口和時間窗口比較類似select avg(price) from test.OrderEvent.win:length(100) win:length(10)就是定義了10個Event的,avg(price)就是統計了最近10個的OrderEvent對象的price的平均值。EPL語法 EPL,全稱Event Processing Language,是一種類似SQL的語言,包含了SELECT, FROM, WHERE, GROUP BY, HAVING 和 ORDER BY子句,同時用事件流代替了table作爲數據源,並且能像SQL那樣join,filtering和aggregation。所以如果各位有SQL基礎的話,簡單的EPL很容易掌握。除了select,EPL也有insert into,update,delete,不過含義和SQL並不是很接近。另外還有pattern和output子句,這兩個是SQL所沒有的。EPL還定義了一個叫view的東西,類似SQL的table,來決定哪些數據是可用的,Esper提供了十多個view,並且保證這些view可以被重複使用。而且用戶還可以擴展view成爲自定義view來滿足需求。在view的基礎上,EPL還提供了named window的定義,作用和view類似,但是更加靈活。。。 Select Clause和From Clause。這個兩個可以說是寫EPL必備,要想得到事件流的處理結果,基本上就靠他們倆了(Pattern除外)。Select Clause1.查詢事件流的所有屬性及特定屬性EPL的select和SQL的select很相近,SQL用*表示查詢表的所有字段,而EPL用*表示查詢事件流的所有屬性值。SQL查詢某個字段名,直接在select後跟字段名就ok,EPL也是將要查詢的屬性名放在select之後。若查多個屬性值,則用逗號分割。和SQL一樣,EPL查詢屬性也可以設置別名。示例如下:// EPL:查詢完整的User對象select * from User// 獲取User對象User u = newEvent.getUnderlying(); // EPL:查詢User的name和id,id別名爲iselect name, id as i from User// 獲取name和idString name = (String)newEvent.get("name");int id = (Integer)newEvent.get("i");這裏要注意,如果查詢的是一個完整對象,需要調用getUnderlying()方法,而get方法是針對確定的屬性名或者別名。另外*是不能設置別名的。2.insert和remove事件流Esper對於事件流分輸入和移出兩種,分別對應監聽器的兩個參數newEvents和oldEvents,關於監聽器的內容可參看《Esper學習之三:進程模型》。newEvents通常對應事件的計算結果,oldEvents可以理解過上一次計算結果。默認情況下,只有newEvents有值,oldEvents爲null。如果需要查看oldEvents,則需要使用一個參數。例如:select rstream * from User如果使用了該參數,則會將上一次計算結果放入newEvents內,而不是oldEvents。並且無法獲得當前的計算結果。select irstream * from User如果使用了該參數,則會將當前的計算結果放入newEvents內,上一次的計算結果放入oldEvents內。3.Aggregation 和SQL一樣,EPL也有Aggregation,即聚合函數。語法如下:aggregate_function([all|distinct] expression) aggregate_function就是聚合函數的名字,比如avg,sum等。expression通常是事件流的某個屬性,也可以是不同事件流的多個屬性,或者是屬性和常量、函數之間的運算。舉例如下。// 查詢最新5秒的Apple的平均價格 select avg(price) as aPrice from Apple.win:time(5 sec) // 查詢最新10個Apple的價格總和的兩倍 select sum(price*2) as sPrice from Apple.win:length(10) // 查詢最新10個Apple的價格,並用函數計算後再算平均值 select avg(Compute.getResult(price)) from Apple.win:length(10) 以上就是聚合函數的使用方法,除此之外需要注意以下幾點:1.聚合函數能用於Select和Having,但是不能用於Where2.sum,avg,media,stddev,avedev只能計算數值,至於media,stddev和avedev代表什麼意思,請自行百度。3.Esper會忽略expression爲null不讓參與聚合運算,但是count函數除外,即使是null也認爲是一個事件。如果事件流集合中沒有包含任何事件,或者包含的事件中用於聚合計算的expression都是null(比如收集5秒內進入的事件即爲一個事件流集合),則所有聚合函數都返回null。4.Insert into4.1 簡單用法EPL的Insert into和SQL的有比較大的區別。SQL是往一張表裏插入數據,而EPL是把一個事件流的計算結果放入另一個事件流,然後可以對這個事件流進行別的計算。所以Insert into的一個好處就是可以將是事件流的計算結果不斷級聯,對於那種需要將上一個業務的結果數據放到下一個業務處理的場景再適合不過了。除此之外,Insert into還有合併多個計算結果的作用。到這裏相信大家已經對他越來越好奇了,不急,咱們先來看看語法:insert [istream | irstream | rstream] into event_stream_name [ (property_name [, property_name] ) ] event_stream_name定義了事件流的名稱,在執行完insert的定義之後,我們可以使用select對這個事件流進行別的計算。istream | irstream | rstream表示該事件流允許另一個事件的輸入/輸入數據和輸出/輸出數據能夠進入(解釋好像很繞。。一會兒看例子就能明白了)property_name表示該事件流裏包含的屬性名稱,多個屬性名之間用逗號分割,並且用小括號括起來。上面的說明可能不是很好理解,咱們先看個例子://將新進入的Asus事件傳遞到Computer,且Asus的id,size和Computer的cid,csize對應 insert into Computer(cid,csize) select id,size from Asus // 第二種寫法 insert into Computer select id as cid, size as csize Asus 從例子中可以看到,insert into需要配合select進行使用,以表明前一個事件流有哪些計算結果將進入insert into定義的事件流。並且在select中的字段要和insert裏的事件流的屬性要對應(這裏指的對應是數據類型對應,而且屬性數量也必須一樣)。如果說insert定義的事件流名稱在之前已經定義過(insert into中定義的除外),重名是不允許的。我個人推薦第二種寫法,通過as設置的別名即爲insert定義的事件流的屬性,這樣可以避免屬性的個數不一致的錯誤。 參考博文:http://blog.csdn.net/luonanqin/article/details/9900295
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章