ちょっと話題の記事

Norikraを支える謎技術:Esper EPLっておもしろ。

2015.01.27

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

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処理によるスケーラブルで低遅延のリアルタイムストリーミング処理ーーが実現できています。

products_esp_cep

 

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を公開しています。

Screen Shot 2015-01-27 at 5.22.10 PM

From Esper EPL Online

(ところでこのサイトってappspot.comドメインなのでGoogle App Engineで動いてるってことですね!)

Esper EPL Onlineを使うと、EPLクエリを書いてみて、その場でお試しイベントを流して結果を見ることができます。上図の例では、画面左に書いた「select * from StockTick」というクエリに{symbol='YHOO', price=65}といったイベントを流して、結果が右側に表示されてるのがわかります。

Norikraのクエリがどう動くかわからん! という人は、このサイトを使うと便利と思いますよー。