如何获取包含多个字段的 Elasticsearch 聚合
How to get an Elasticsearch aggregation with multiple fields
我正在尝试查找与当前正在查看的标签相关的标签。我们索引中的每个文档都被标记了。每个标签由两部分组成 - ID 和文本名称:
{
...
meta: {
...
tags: [
{
id: 123,
name: 'Biscuits'
},
{
id: 456,
name: 'Cakes'
},
{
id: 789,
name: 'Breads'
}
]
}
}
要获取相关标签,我只是查询文档并获取其标签的集合:
{
"query": {
"bool": {
"must": [
{
"match": {
"item.meta.tags.id": "123"
}
},
{
...
}
]
}
},
"aggs": {
"baked_goods": {
"terms": {
"field": "item.meta.tags.id",
"min_doc_count": 2
}
}
}
}
这非常有效,我得到了我想要的结果。但是,我需要标签 ID 和 名称来做任何有用的事情。我已经探索了如何实现这一点,解决方案似乎是:
- 索引时合并字段
- 将字段组合在一起的脚本
- 嵌套聚合
选项一和选项二对我不可用,所以我一直在使用选项 3,但它没有以预期的方式响应。给定以下查询(仍在搜索也标记为 'Biscuits' 的文档):
{
...
"aggs": {
"baked_goods": {
"terms": {
"field": "item.meta.tags.id",
"min_doc_count": 2
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.name"
}
}
}
}
}
}
我会得到这个结果:
{
...
"aggregations": {
"baked_goods": {
"buckets": [
{
"key": "456",
"doc_count": 11,
"name": {
"buckets": [
{
"key": "Biscuits",
"doc_count": 11
},
{
"key": "Cakes",
"doc_count": 11
}
]
}
}
]
}
}
}
嵌套聚合包括搜索词和我要查找的标签(按字母顺序返回)。
我试图通过向嵌套聚合添加 exclude
来缓解这种情况,但这会使查询速度减慢太多(500000 个文档大约减慢 100 倍)。到目前为止,最快的解决方案是手动对结果进行重复数据删除。
在响应中获取包含标签 ID 和标签名称的标签聚合的最佳方法是什么?
感谢你走到这一步!
看起来,你的 tags
不是 nested
。
you need it nested
要使此聚合起作用,以便 id
和 name
之间存在关联。如果没有 nested
,id
的列表只是一个数组,name
的列表是另一个数组:
"item": {
"properties": {
"meta": {
"properties": {
"tags": {
"type": "nested", <-- nested field
"include_in_parent": true, <-- to, also, keep the flat array-like structure
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
此外,请注意,我已将此行添加到映射中 "include_in_parent": true
,这意味着您的 nested
标签的行为也将类似于 "flat" 数组结构。
因此,您到目前为止在查询中所做的一切都将在不对查询进行任何更改的情况下继续工作。
但是,对于您的这个特定查询,聚合需要更改为如下所示:
{
"aggs": {
"baked_goods": {
"nested": {
"path": "item.meta.tags"
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.id"
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.name"
}
}
}
}
}
}
}
}
结果是这样的:
"aggregations": {
"baked_goods": {
"doc_count": 9,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 123,
"doc_count": 3,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "biscuits",
"doc_count": 3
}
]
}
},
{
"key": 456,
"doc_count": 2,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "cakes",
"doc_count": 2
}
]
}
},
.....
我正在尝试查找与当前正在查看的标签相关的标签。我们索引中的每个文档都被标记了。每个标签由两部分组成 - ID 和文本名称:
{
...
meta: {
...
tags: [
{
id: 123,
name: 'Biscuits'
},
{
id: 456,
name: 'Cakes'
},
{
id: 789,
name: 'Breads'
}
]
}
}
要获取相关标签,我只是查询文档并获取其标签的集合:
{
"query": {
"bool": {
"must": [
{
"match": {
"item.meta.tags.id": "123"
}
},
{
...
}
]
}
},
"aggs": {
"baked_goods": {
"terms": {
"field": "item.meta.tags.id",
"min_doc_count": 2
}
}
}
}
这非常有效,我得到了我想要的结果。但是,我需要标签 ID 和 名称来做任何有用的事情。我已经探索了如何实现这一点,解决方案似乎是:
- 索引时合并字段
- 将字段组合在一起的脚本
- 嵌套聚合
选项一和选项二对我不可用,所以我一直在使用选项 3,但它没有以预期的方式响应。给定以下查询(仍在搜索也标记为 'Biscuits' 的文档):
{
...
"aggs": {
"baked_goods": {
"terms": {
"field": "item.meta.tags.id",
"min_doc_count": 2
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.name"
}
}
}
}
}
}
我会得到这个结果:
{
...
"aggregations": {
"baked_goods": {
"buckets": [
{
"key": "456",
"doc_count": 11,
"name": {
"buckets": [
{
"key": "Biscuits",
"doc_count": 11
},
{
"key": "Cakes",
"doc_count": 11
}
]
}
}
]
}
}
}
嵌套聚合包括搜索词和我要查找的标签(按字母顺序返回)。
我试图通过向嵌套聚合添加 exclude
来缓解这种情况,但这会使查询速度减慢太多(500000 个文档大约减慢 100 倍)。到目前为止,最快的解决方案是手动对结果进行重复数据删除。
在响应中获取包含标签 ID 和标签名称的标签聚合的最佳方法是什么?
感谢你走到这一步!
看起来,你的 tags
不是 nested
。
you need it nested
要使此聚合起作用,以便 id
和 name
之间存在关联。如果没有 nested
,id
的列表只是一个数组,name
的列表是另一个数组:
"item": {
"properties": {
"meta": {
"properties": {
"tags": {
"type": "nested", <-- nested field
"include_in_parent": true, <-- to, also, keep the flat array-like structure
"properties": {
"id": {
"type": "integer"
},
"name": {
"type": "string"
}
}
}
}
}
}
}
此外,请注意,我已将此行添加到映射中 "include_in_parent": true
,这意味着您的 nested
标签的行为也将类似于 "flat" 数组结构。
因此,您到目前为止在查询中所做的一切都将在不对查询进行任何更改的情况下继续工作。
但是,对于您的这个特定查询,聚合需要更改为如下所示:
{
"aggs": {
"baked_goods": {
"nested": {
"path": "item.meta.tags"
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.id"
},
"aggs": {
"name": {
"terms": {
"field": "item.meta.tags.name"
}
}
}
}
}
}
}
}
结果是这样的:
"aggregations": {
"baked_goods": {
"doc_count": 9,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": 123,
"doc_count": 3,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "biscuits",
"doc_count": 3
}
]
}
},
{
"key": 456,
"doc_count": 2,
"name": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "cakes",
"doc_count": 2
}
]
}
},
.....