Norikraで以下の様な感じの、GROUP BYして、SELECTの中でjavaメソッドを使うようなクエリを登録していたのだけど、なんか生成されるイベントが多い、というのが発端で調べてみた.
1
|
|
上記のクエリを登録した状態で、以下のようにイベントを投入する.
1 2 3 |
|
と、こんな感じで同じようなレコードが重複して生成される. count(*)
は正しくカウントされているのだが、GROUP BYしているので1レコードになってて欲しい.
1 2 3 4 |
|
Norikraではなく、Esperで同じことを実験してみても発生するので、Esperの事象っぽい.公式ドキュメントの”3.7.2. Output for Aggregation and Group-By”を見ると、以下の様な記述がある。 GROUP BYの中に無いフィールドをSELECTすると、入力イベントと同じ数の出力イベントが発生するよ、という話.
If your statement selects non-aggregated properties and aggregation values, and groups only some properties using the group by clause, your statement may look as below:
select account, accountName, sum(amount) from Withdrawal.win:time_batch(1 sec) group by account
At the end of a time interval, the engine posts to listeners one row per event. The aggregation result aggregates per unique account.
とは言え、GROUP BYの中にstr.split(",")
を入れても同じ. 値は同じでも、Stringクラスのオブジェクトは別になってしまうからなのかなぁ. 一応、回避策としてはfirsteverという、イベントの中で最初の値だけを取る関数があるので、firstever(str.split(","))
のようにすると1レコードに集約できた.
Issueで聞いてみた. https://github.com/espertechinc/esper/issues/18
若干うまく伝わらなかった気がするけど、javaメソッドではなく同等の機能を持つUDFを作ればうまくいくよ、ということらしい。実際、EsperのUDFを作ってみたら、ちゃんと集約された。
ちなみに、EsperのUDFを作るのは簡単で、以下のようにstaticなメソッドを持つクラスを作って
1 2 3 4 5 |
|
ConfigurationクラスのaddPlugInSingleRowFunctionメソッドで、function名、クラス名、メソッド名を渡してやれば良い。
1
|
|
まあ、都度UDF作るのも面倒なので、firsteverで回避出来る場合はそうするかなぁ.
そんな話でした.