elasticsearch Elasticsearch按下一个/上一个数组项筛选/聚合
假设三个是这三个文档,需要编写一个elasticsearch查询,该查询获取一个item name参数,并返回它的下一个项(使用顺序计算) itemArray定义为nestedObject,但不必嵌套。我对文档有点迷糊了。任何帮助都将不胜感激 数据示例:
elasticsearch Elasticsearch按下一个/上一个数组项筛选/聚合,
elasticsearch,filter,aggregation-framework,bucket,
elasticsearch,Filter,Aggregation Framework,Bucket,假设三个是这三个文档,需要编写一个elasticsearch查询,该查询获取一个item name参数,并返回它的下一个项(使用顺序计算) itemArray定义为nestedObject,但不必嵌套。我对文档有点迷糊了。任何帮助都将不胜感激 数据示例: { "id" : 0 "itemArray": [ { "name":"X", "order" : 0 }, { "name":"Y", "o
{
"id" : 0
"itemArray": [
{
"name":"X",
"order" : 0
},
{
"name":"Y",
"order" : 1
},
{
"name":"Z",
"order" : 2
}
]
}
doc-1
{
"id" : 0
"itemArray": [
{
"name":"X",
"order" : 0
},
{
"name":"Y",
"order" : 1
},
{
"name":"Z",
"order" : 2
}
]
}
doc-2
{
"id" : 1
"itemArray": [
{
"name":"X",
"order" : 0
},
{
"name":"Y",
"order" : 1
},
{
"name":"T",
"order" : 2
}
]
}
doc-3
{
"id" : 2
"itemArray": [
{
"name":"X",
"order" : 0
},
{
"name":"Y",
"order" : 1
},
{
"name":"Z",
"order" : 2
}
]
}
响应示例对于输入“X”,有三个文档包含Y;按照顺序在其数组中的X之后:
{
"Y": 3
}
{
"Z": 2,
"T": 1
}
响应示例对于输入“Y”有两个文档包含Z,一个文档包含T;根据顺序在其数组中的Y之后:
{
"Y": 3
}
{
"Z": 2,
"T": 1
}
弹性搜索版本:<强> 6.2
如果你稍微考虑一下,这是非常可行的。
如何实现“数组中的下一个元素”聚合? 请考虑您的映射如下所示:PUT nextval
{
"mappings": {
"item": {
"properties": {
"id": {
"type": "long"
},
"itemArray": {
"type": "nested",
"properties": {
"name": {
"type": "keyword"
},
"nextName": {
"type": "keyword"
}
}
}
}
}
}
}
{
...,
"aggregations": {
"1. setup nested": {
"doc_count": 9,
"2. filter agg results": {
"doc_count": 3,
"3. aggregate by nextName": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Y",
"doc_count": 3
}
]
}
}
}
}
}
在这里,我们显式地存储在嵌套的数组的下一个值中。现在让我们插入数据:
POST nextval/item/0
{
"id" : 0,
"itemArray": [
{
"name":"X",
"nextName":"Y"
},
{
"name":"Y",
"nextName":"Z"
},
{
"name":"Z"
}
]
}
POST nextval/item/1
{
"id" : 1,
"itemArray": [
{
"name":"X",
"nextName":"Y"
},
{
"name":"Y",
"nextName":"T"
},
{
"name":"T"
}
]
}
POST nextval/item/2
{
"id" : 2,
"itemArray": [
{
"name":"X",
"nextName":"Y"
},
{
"name":"Y",
"nextName":"Z"
},
{
"name":"Z"
}
]
}
并使用类似这样的查询来获取输入的结果X
:
POST nextval/item/_search
{
"query": {
"nested": {
"path": "itemArray",
"query": {
"term": {
"itemArray.name": "X"
}
}
}
},
"aggs": {
"1. setup nested": {
"nested": {
"path": "itemArray"
},
"aggs": {
"2. filter agg results": {
"filter": {
"term": {
"itemArray.name": "X"
}
},
"aggs": {
"3. aggregate by nextName": {
"terms": {
"field": "itemArray.nextName"
}
}
}
}
}
}
}
}
输出如下所示:
PUT nextval
{
"mappings": {
"item": {
"properties": {
"id": {
"type": "long"
},
"itemArray": {
"type": "nested",
"properties": {
"name": {
"type": "keyword"
},
"nextName": {
"type": "keyword"
}
}
}
}
}
}
}
{
...,
"aggregations": {
"1. setup nested": {
"doc_count": 9,
"2. filter agg results": {
"doc_count": 3,
"3. aggregate by nextName": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Y",
"doc_count": 3
}
]
}
}
}
}
}
如果我们查询输入Y
,输出将是:
{
...,
"aggregations": {
"1. setup nested": {
"doc_count": 9,
"2. filter agg results": {
"doc_count": 3,
"3. aggregate by nextName": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Z",
"doc_count": 2
},
{
"key": "T",
"doc_count": 1
}
]
}
}
}
}
}
它是如何工作的?
关于嵌套对象,需要了解的一件重要事情是:
每个嵌套对象都作为隐藏的单独文档编制索引
我建议阅读指南,它们提供了很好的解释和示例
因为这些对象是分开的,所以我们会丢失它们在数组中的位置信息。这就是您首先在那里下订单的原因
这就是为什么我们把nextName
字段放在嵌套对象中:这样对象本身就知道哪个是它的邻居
好的,但是为什么聚合如此复杂呢?
让我们回顾一下。在我们的查询中,基本上有4个要点:
通过itemArray.name==X进行查询
一级聚合
二级聚合
三级聚合
问题1)非常明显:我们只需要符合我们要求的文档。2)也很简单:因为itemArray
是一个嵌套的,我们只能在嵌套的上下文中进行聚合
这个问题很棘手。让我们回到查询的输出:
{
...,
"aggregations": {
"1. setup nested": {
"doc_count": 9,
"2. filter agg results": {
"doc_count": 3,
"3. aggregate by nextName": {
"doc_count_error_upper_bound": 0,
"sum_other_doc_count": 0,
"buckets": [
{
"key": "Z",
"doc_count": 2
},
{
"key": "T",
"doc_count": 1
}
]
}
}
}
}
}
第一次聚合的doc\u count
为9。为什么是9?因为这是文档中与搜索查询匹配的嵌套对象的数量
这就是为什么我们需要聚合:从所有项目中只选择那些具有itemArray.name==X
的项目
其中一个也很简单:只需计算字段itemArray.nextName
的每个项满足多少次
有更好的方法吗?
可能是的。这取决于您的数据、需求以及更改映射的自由度。例如,如果你只是在探索你的数据,那么数据挖掘的潜力是巨大的
希望有帮助 谢谢你的回复,尼古拉。如果有一个条件,像前面的项目必须是“X”和“Y”连续。在这个问题上考虑相同的数据。回答必须是“T:1 Z:2”我们可以有这种类型的查询吗?我试图写一个过滤脚本,但没有得到成功的结果。实际上,在聚合之前无法访问筛选器脚本上的数组项。@GkhnSr我认为,如果您需要两个previous和第三个aggregate,则需要将它们添加到itemArray
中,如下所示:{“prevName”:“X”、“name”:“Y”、“nextName”:“Z”}
,并使用新条件更新查询和筛选器(prevName=X&&name=Y
)。实际上,我的意思是过滤器可能有多个连续的先前输入。根据您的建议,我需要为每个like(prevName=X,Y)将所有PrevyName设置为。必须有更好的方法来查找具有相同先前路径的项。示例数据:“X>Y>Z”,“X>Y>Z”,“X>Y>T”
按上一个过滤:“X>Y”
预期结果:“Z:2,T:1”
@GkhnSr您可以连接这些ID并查询整个前缀,直到开始:[{“name”:“X”},{“prefix”:“X”,“name”“Y”},{“prefix”:“X.Y”,“name”:“Z”}]
和查询部分:prefix=“X.Y”
。想法保持不变-将需要查询的所有内容放在一个项目中。@GkhnSr如果您能够将ID列表转换为字符串,您可能会受益于.Like“prefix”:{“userActions”:“login.selectItem.putensit.checkOut”}
。