首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >按下一个/前一个数组项进行Elasticsearch筛选/聚合

按下一个/前一个数组项进行Elasticsearch筛选/聚合
EN

Stack Overflow用户
提问于 2018-04-03 11:27:44
回答 1查看 460关注 0票数 1

假设这三个文档是这三个文档,需要编写一个elasticsearch查询,该查询获取一个项名参数,并在出现的情况下返回下一个项(使用顺序计算)。

itemArray被定义为nestedObject,但不需要嵌套。我有点迷上文件了。任何帮助都将不胜感激。

数据示例:

doc-1

代码语言:javascript
复制
{
  "id" : 0
  "itemArray": [
     {
        "name":"X",
        "order" : 0
     },
     {
        "name":"Y",
        "order" : 1
     },
     {
        "name":"Z",
        "order" : 2
     }
  ]
}

doc-2

代码语言:javascript
复制
{
  "id" : 1
  "itemArray": [
     {
        "name":"X",
        "order" : 0
     },
     {
        "name":"Y",
        "order" : 1
     },
     {
        "name":"T",
        "order" : 2
     }
  ]
}

doc-3

代码语言:javascript
复制
{
  "id" : 2
  "itemArray": [
     {
        "name":"X",
        "order" : 0
     },
     {
        "name":"Y",
        "order" : 1
     },
     {
        "name":"Z",
        "order" : 2
     }
  ]
}

响应示例用于输入"X",有三个文档包含Y;在其数组中按照顺序排列X之后:

代码语言:javascript
复制
{
    "Y": 3
}

响应示例用于输入"Y“有两个文档包含Z和一个文档包含T;在YE 231之后,按顺序排列在其数组中:

代码语言:javascript
复制
{
    "Z": 2,
    "T": 1
}

ElasticSearch版本:6.2

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-04-03 21:49:12

如果您考虑一下去角色化数据,这是非常可行的。

如何实现“数组中的下一个元素”聚合?

考虑一下,您的映射应该如下所示:

代码语言:javascript
复制
PUT nextval
{
  "mappings": {
    "item": {
      "properties": {
        "id": {
          "type": "long"
        },
        "itemArray": {
          "type": "nested",
          "properties": {
            "name": {
              "type": "keyword"
            },
            "nextName": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

在这里,我们显式地存储在数组的nested下一个值中。现在让我们插入数据:

代码语言:javascript
复制
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的结果

代码语言:javascript
复制
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"
              }
            }
          }
        }
      }
    }
  }
}

输出将如下所示:

代码语言:javascript
复制
{
  ...,
  "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执行查询,输出将是:

代码语言:javascript
复制
{
  ...,
  "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
            }
          ]
        }
      }
    }
  }
}

它怎麽工作?

关于嵌套对象,需要了解的一件重要事情是:

每个嵌套对象都被索引为一个隐藏的单独文档。

我推荐阅读指南的此页,它们提供了很好的解释和例子。

因为这些对象是分开的,所以我们失去了关于它们在数组中的位置的信息。这就是你把order放在第一位的原因。

这就是为什么我们将nextName字段放在嵌套对象中的原因:因此对象本身知道哪个是它的邻居。

好吧,但是为什么聚合如此复杂呢?

让我们重温一下。在我们的查询中,基本上有四个要点:

  1. itemArray.name==X查询
  2. 1级聚合,nested
  3. 2级聚合,filter
  4. 三级聚合,terms

这是相当明显的:我们只需要与我们的请求相对应的文档。2)也很简单:因为itemArraynested,所以我们只能在nested上下文中进行聚合。

其中一个很棘手。让我们返回到查询的输出:

代码语言:javascript
复制
{
  ...,
  "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_count是9,为什么是9?因为这是与搜索查询匹配的文档中嵌套对象的数量。

这就是为什么我们需要聚合:从所有项中只选择那些有itemArray.name==X的。

其中一个同样很简单:只需计算字段itemArray.nextName的每个项满足多少次即可。

有没有更好的方法?

可能是的。这取决于您的数据和您的需求,以及您是否可以自由地更改映射。例如,如果您只是在探索您的数据,那么脚本聚合的潜力是巨大的。

希望这能帮上忙!

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/49628926

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档