Elasticsearch でつまづいた話 (2)
今日のテーマは複数の Nested Field があるときの Aggregations 。
Nested Field とは
日本語での説明は このあたり に譲るが、簡単に言うと親子関係が維持された Array である。データの見た目は Array と同じだ。
"user" : [ { "first" : "John", "last" : "Smith" }, { "first" : "Alice", "last" : "White" } ]
クエリはこんな感じになる。
{ "query" : { "nested" : { "path" : "user", "query" : { "match" : { "user.first" : "John" } } } } }
Array だったら↓で済むので少し複雑になっている。
{ "query" : { "match" : { "user.first" : "John" } } }
Aggregation ならこうなる。
{ "aggs" : { "nested_by_resellers" : { "nested" : { "path" : "resellers" }, "aggs" : { "aggs_by_resellers_id" : { "terms" : { "field" : "reseller.id" } } } } } }
Nested Field が複数ある場合もある。
{ "mappings": { "product" : { "properties" : { "resellers" : { "type" : "nested", "properties" : { "id" : { "type" : "keyword" }, "name" : { "type" : "text" }, "price" : { "type" : "double" } } }, "sources" : { "type" : "nested", "properties" : { "id" : { "type" : "keyword" }, "name" : { "type" : "text" } } } } } } }
このとき resellers
の id
で集約し、更に sources
の id
でも集約したい場合どうするか。
これが今回のつまづいた話だ。
たとえば↓のように書きたくなるが、これではうまくいかない。
{ "aggs" : { "nested_by_resellers" : { "nested" : { "path" : "resellers" }, "aggs" : { "aggs_by_resellers_id" : { "terms" : { "field" : "reseller.id" }, "aggs" : { "nested_by_sources" : { "nested" : { "path" : "sources" }, "aggs" : { "aggs_by_sources_id" : { "terms" : { "field" : "sources.id" } } } } } } } } } }
なぜか? reseller の下に sources がいないからだ。そりゃそうだ。
じゃどうするか。 reverse nested というものを使う。これによって nested を抜け出すことができる。
{ "aggs" : { "nested_by_resellers" : { "nested" : { "path" : "resellers" }, "aggs" : { "aggs_by_resellers_id" : { "terms" : { "field" : "reseller.id" }, "aggs" : { "reverse" : { "reverse_nested" : {}, "aggs" : { "nested_by_sources" : { "nested" : { "path" : "sources" }, "aggs" : { "aggs_by_sources_id" : { "terms" : { "field" : "sources.id" } } } } } } } } } } } }
reverse_nested を挟むことによって、 resellers
の下にいた状態から抜け出して、更に sources
の下に入ることができた。
めでたしめでたし。
... とはいえ、複雑な json だよなぁ。
参考 :
Reverse nested Aggregation | Elasticsearch Reference [6.0] | Elastic