Norikraを支える謎技術:Esper EPLっておもしろ。
Norikra使ってますかー? もちろん使ってますよね!
Norikraって内部ではEsperTech Inc.がオープンソース公開しているEsperというJavaベースのガチなCEP (Complex Event Processing)エンジンを利用していて、そのクエリ言語であるEPL (Event Processing Language)を用いることで、
a highly scalable, memory-efficient, in-memory computing, SQL-standard, minimal latency, real-time streaming-capable Big Data processing engine for historical data, or medium to high-velocity data and high-variety data.
ーーすなわちインメモリのSQL処理によるスケーラブルで低遅延のリアルタイムストリーミング処理ーーが実現できています。
From Esper: Event Processing for Java
このEPLのように、ストリームデータに継続的に適用されるクエリのことを継続クエリ(Continuous Query)と言ったりしますが、CQの世界ってとっても奥が深くて、私なんかがちょろっとNorikraクエリを書いた程度では全然分かった気になりません。CQは、SQLの皮を被った、しかしまったく異なる何かです。
例えば、EPLドキュメントのSolutions Patternsページを見ると、こんな例があったりしますよ(ただし、NorikraでサポートされているのはEPLの一部です):
select count(*) from MyEvent.win:time(3 min)
まあ、これはCQにおけるhello worldレベルです。過去3分間に飛んできたMyEventの数を数えます。もちろん、指定したスライディングウィンドウ内で集約関数使ったりできます:
select e, max(e), avg(e), select (max(local.e) as localMax, avg(local.e) as localAvg from MyEvent.win:time(10)) from MyEvent
では、もうちょっと複雑な例:
select * from Event(conditions).std:unique(id).win:time(5 min) as s1, Event(conditions).std:unique(id).win:time(5 min) as s2, Event(conditions).std:unique(id).win:time(5 min) as s3 where s1.id = s2.id and s1.id = s3.id
これはJOINです。しかしテーブル同士のJOINではありません。「過去5分間に飛んできたs1, s2, s3イベントのすべてを相互にJOINして、IDが一致する組み合わせを出力する」ってクエリになります。文法的にも、そろそろSQL宇宙から離脱しつつありますね。これは何に使えるでしょうか? 例えば、異なるシステムに同時にアクセスしてきているユーザーIDをリアルタイムに検出、とかですかね。
では次:
select * from AlertEventStream match_recognize ( partition by origin measures a1.alarmNumber as alarmNumber1, a1.alarmNumber as alarmNumber2, a1.origin as origin pattern (a1 a2) define a1 as a1.picked = false a2 as a2.picked = true )
このmatch_recognize節って、DWH系のDBではサポートされているSQL構文らしいです。EPLではイベントストリームに対して適用され、上記クエリは「アラームイベントをorigin(発生源)ごとにグループ化した後、任意の連続したペアa1とa2について、a1.picked=falseでa2.picked=trueというパターンにマッチするものを抽出する」という意味...らしいです。a1の次にa2もしくはa3が発生した場合、等々、いろいろ複雑なパターンを表現できるとのこと。
似たような例では、「来るべきイベントが届いてない、または遅れて届いた」というクエリはこうなります:
select * from pattern [ every down=MyEvent(text='down') -> ( (timer:interval(1 min) and not up=MyEvent(text='Up', equipmentId=down.equipmentId)) or ( (timer:interval(30 sec) and not MyEvent(text='Up', equipmentId=down.equipmentId)) -> up=MyEvent(text='Up', equipmentId=down.equipmentId) where timer:within(30 seconds) ) )]
もはやSQLとはあまり関係なくなってますね! ここいらへんの未開拓でQiitaにもまだ載ってなさげな謎技術を使いこなせれば、スパム検知や異常検知にかぎらず、ゲームのKPI等もNorikra使ってリアルタイムに取れちゃうかもしれなくて素敵すぎます。E・P・L! E・P・L!
Esper EPL Onlineでクエリを試す
EPLの構文や概念を理解するのも難しいのだけど、ストリームに対する継続クエリというものはデバッグも難しい。ストリームを流してみないことには、クエリが実際にどう動くかよくわからないからです(これってイベントドリブン系に共通しそう)。
そんなEPLのとっつきにくさを緩和するためか、EsperTechではEPLクエリをその場で試せるEsper EPL Onlineを公開しています。
From Esper EPL Online
(ところでこのサイトってappspot.comドメインなのでGoogle App Engineで動いてるってことですね!)
Esper EPL Onlineを使うと、EPLクエリを書いてみて、その場でお試しイベントを流して結果を見ることができます。上図の例では、画面左に書いた「select * from StockTick」というクエリに{symbol='YHOO', price=65}といったイベントを流して、結果が右側に表示されてるのがわかります。
Norikraのクエリがどう動くかわからん! という人は、このサイトを使うと便利と思いますよー。