如何在Elasticsearch中聚合指定用户的关联角色并筛选对应Workshop?
Elasticsearch嵌套聚合与筛选问题
数据映射
"properties": { "day": { "type": "date", "format": "yyyy-MM-dd" }, "persons": { "type": "nested", "properties": { "id": { "type": "integer" }, "name": { "type": "text", "analyzer": "final", "fields": { "raw": { "type": "keyword", "index": true } } }, "role": { "type": "keyword" } } } }
存储的数据
{ "workshops": [ { "day": "2023-12-01", "persons": [ { "name": "Max", "role": "infrastructure" }, { "name": "Sam", "role": "infrastructure" }, { "name": "Sam", "role": "database" }, { "name": "Peter", "role": "network" }, { "name": "Peter", "role": "infrastructure" } ] }, { "day": "2023-12-02", "persons": [ { "name": "George", "role": "infrastructure" }, { "name": "Michael", "role": "database" }, { "name": "Michael", "role": "network" }, { "name": "Sam", "role": "administration" } ] } ] }
原聚合语句
{ "aggregations": [ { "persons": { "nested": { "path": "persons" }, "aggs": { "nestedData": { "terms": { "field": "persons.name.raw" }, "aggs": { "name": { "terms": { "field": "persons.name.raw" } } } } } } }, { "persons_role_de_de": { "nested": { "path": "persons" }, "aggs": { "nestedData": { "terms": { "field": "persons.role" }, "aggs": { "name": { "terms": { "field": "persons.role" } } } } } } } ] }
当前查询语句(筛选含Sam的文档)
{ "query": { "bool": { "must": [ { "nested": { "path": "persons", "query": { "bool": { "must": [ { "match": { "persons.name": "sam" } } ] } } } } ] } } }
问题现象
执行match_all查询时聚合结果符合预期,但用上述查询筛选含Sam的文档后,角色聚合统计的是文档内所有人员的角色,而非仅Sam的角色(预期结果:infrastructure(1)、database(1)、administration(1))。最终目标是找到Sam担任database角色的workshop,但当前聚合和查询配置无法实现。
解决方案
1. 仅统计Sam的角色
嵌套查询仅筛选出包含Sam的文档,但聚合会遍历文档内所有persons嵌套对象。需在聚合的嵌套层级内添加过滤器,仅针对Sam的记录做统计:
{ "query": { "bool": { "must": [ { "nested": { "path": "persons", "query": { "match": { "persons.name": "sam" } } } } ] } }, "aggs": { "persons": { "nested": { "path": "persons" }, "aggs": { "only_sam": { "filter": { "match": { "persons.name": "sam" } }, "aggs": { "sam_roles": { "terms": { "field": "persons.role" } } } } } } } }
此语句会在聚合中先过滤出Sam的记录,再统计其角色分布,得到预期结果。
2. 找到Sam担任database角色的workshop
直接使用嵌套查询同时匹配name=Sam和role=database,即可定位目标workshop:
{ "query": { "nested": { "path": "persons", "query": { "bool": { "must": [ { "match": { "persons.name": "sam" } }, { "match": { "persons.role": "database" } } ] } }, "inner_hits": { "size": 10 } } } }
查询结果会返回包含Sam且角色为database的workshop文档,inner_hits字段会显示匹配的具体persons对象。
内容的提问来源于stack exchange,提问作者Carsten
相关产品推荐
相关产品推荐

