全文検索エンジンとして名高いElasticsearchですが、昨今はログの蓄積先として利用されていることも多いように思われます。
今回そんなログの中で特定のワードを含む場合を集計したい、というニーズが発生しました。
その中でwildcard, filter, aggsをどのように組み合わせるのかについて調査したので、備忘録としてまとめます。
wildcardクエリとは
wildcardはsqlではlikeに相当するクエリで、
GET /hoge/_search
{
"query": {
"wildcard": {
"name": {
"value": "ta*"
}
}
}
}
と
SELECT * FROM hoge WHERE name LIKE 'ta%'
が同義となるようなものです。
この際*
の位置や個数はLIKE句の%
同様に、任意の場所に対し挿入することが可能です。
また、*
では0文字以上の文字列にヒットしますが、?
を用いることで1文字にのみヒットさせることも可能となります。
パターン | 該当する文字列 |
---|---|
ta* | ta, tao, taro, taros, ... |
ta? | tao, tas, ... |
aggregationとfilterの組み合わせ
次に集計関数であるaggsとfilterの組み合わせです。
aggsが2重に書かれていますが、こちらは公式のドキュメントにを参考に書いています。
GET /hoge/_search
{
"aggs": {
"group_by_name": {
"aggs": {
"aggregation": {
"terms": {
"field": "name"
}
}
},
"filter": {
"range": {
"created_at": {
"gte": 20190401,
"lt": 20190501
}
}
}
}
},
"size": 0
}
ここで、検索パラメータにsize:0
を指定していますが、これはaggs句を実行した際に、hitしたドキュメントが戻り値として与えられる為で、今回のケースでは集計結果のみ必要な為指定しています。
aggregation + filter + wildcard
今回の本題である、これら三つを組み合わせた集計です。
GET /hoge/_search
{
"aggs": {
"group_by_name": {
"aggs": {
"aggregation": {
"terms": {
"field": "name"
}
}
},
"filter": {
"wildcard": {
"name": {
"value": "ta*"
}
}
}
}
},
"size": 0
}
これで、名前の前方がtaに一致するデータの集計を取ることができました。
おまけ: aggregation + filter(wildcard AND range)
また、これに先ほどのrange等のフィルタを加えたい場合は、
GET /hoge/_search
{
"aggs": {
"group_by_name": {
"aggs": {
"aggregation": {
"terms": {
"field": "name"
}
}
},
"filter": {
"bool": {
"must":[
{
"wildcard": {
"name": {
"value": "ta*"
}
}
},
{
"range": {
"created_at": {
"gte": 20190401,
"lt": 20190501
}
}
}
]
}
}
}
},
"size": 0
}
とすることで集計可能です。
さらに、複数区間rangeを用いて指定したい場合は
GET /hoge/_search
{
"aggs": {
"group_by_timestamp": {
"aggs": {
"aggregation": {
"terms": {
"field": "name"
}
}
},
"filter": {
"bool": {
"must":[
{
"wildcard": {
"name": {
"value": "ta*"
}
}
},
{
"bool":{
"should":[
{
"range": {
"created_at": {
"gte": 20190401,
"lt": 20190501
}
}
},
{
"range": {
"created_at": {
"gte": 20180401,
"lt": 20180501
}
}
}
]
}
}
]
}
}
}
},
"size": 0
}