Edited at

[elasticsearch2.0] Pipeline Aggregationを試す -Bucket Script Aggregation

More than 3 years have passed since last update.


テーマ

「期間Aと期間Bで単語の出現頻度の差を算出する」


  • if-idf的なことをやるためのお試しといった感じです

  • 出現頻度:その単語を含む記事数


方針


  1. terms aggregation → 単語毎の出現頻度を数える

  2. filter aggregation → 期間Aと期間Bに分割


  3. bucket script aggregation → 期間Aと期間Bを比較


設定


elasticsearch.yml

script.engine.groovy.inline.aggs: on



query


bucket-script-agg.json

GET _search?search_type=count

{
"query": {
"match_all": {}
},
"aggs": { // 1.terms aggregation
"term": {
"terms": {
"field": "text",
"size": 5
},
"aggs": { // 2.filter aggregation
"dateRange1": { // 期間A
"filter": {
"range": {
"datetime": {
"gte": "2014-04-01T00:00:00+0900",
"lte": "2014-04-10T23:59:59+0900"
}
}
}
},
"dateRange2": { // 期間B
"filter": {
"range": {
"datetime": {
"gte": "2014-04-11T00:00:00+0900",
"lte": "2014-04-20T23:59:59+0900"
}
}
}
},
"tf-idf": { // 語弊あり
"bucket_script": { // 3.bucket script aggregation
"buckets_path": {
"range1": "dateRange1._count", //doc_countを取り出す
"range2": "dateRange2._count"
},
"script": "range2 - range1" //簡単なscript
}
}
}
}
}
}


結果


response.json

{

"took": 133,
"timed_out": false,
"_shards": {
"total": 7,
"successful": 7,
"failed": 0
},
"hits": {
"total": 48762,
"max_score": 0,
"hits": []
},
"aggregations": {
"term": {
"doc_count_error_upper_bound": 6688,
"sum_other_doc_count": 904138,
"buckets": [
{
"key": "い", // term(analyzerの設定が適当なので変な感じ)
"doc_count": 23490, // hits全体での件数
"dateRange2": {
"doc_count": 7642 // 期間Aでの件数
},
"dateRange1": {
"doc_count": 8270 // 期間Bでの件数
},
"if-idf": {
"value": -628 // 期間B - 期間A の結果
}
}
...
]
}
}
}



まとめと感想


  • かなり柔軟に処理を書けそう

  • scriptで扱うbucketの数が特定できないと使えないような気が

  • bucketからドキュメント件数を取り出すには{backet_path}._countを使う

  • ひとまず思ったとおりのことができた

  • bucketを任意の条件でfilterするaggregationの構想もあるらしいので期待


    • (20151112追記) bucket selector aggregationと言うのがそれらしい



  • Senseが超便利


課題


  • 期間Aと期間Bそれぞれの全ドキュメント数で正規化するような処理を入れたい

  • terms aggregationとfilter aggregationの順序を逆に出来るだろうか


参考