【问题标题】:In ElasticSearch, how do I filter the nested documents in my result?在 ElasticSearch 中,如何过滤结果中的嵌套文档?
【发布时间】:2017-08-08 14:57:55
【问题描述】:

假设,在 ElasticSearch 5 中,我有如下嵌套的数据:

{"number":1234, "names": [ 
  {"firstName": "John", "lastName": "Smith"}, 
  {"firstName": "Al", "lastName": "Jones"}
]},  
...

我想查询编号为 1234 的匹配,但仅返回匹配“lastName”的名称:“Jones”,以便我的结果省略不匹配的名称。换句话说,我只想取回匹配文档的一部分,基于术语查询或类似内容。

一个简单的嵌套查询是行不通的,因为它会过滤顶级结果。有什么想法吗?

{ "query" : { "bool": { "filter":[
    { "term": { "number":1234} },
    ????  something with "lastName": "Jones" ????
] } } }

我要回来:

hits: [
   {"number":1234, "names": [ 
     {"firstName": "Al", "lastName": "Jones"}
   ]},  
   ...
]

【问题讨论】:

  • 第二个答案应该可以满足您的需求,对吧?
  • 您是否找到了适合您的目的的好解决方案?接受的答案似乎不是解决方案,因为您还在下面评论。我还需要对嵌套对象进行完全相同的过滤,但这些内部匹配项会单独返回,并且还会返回整个嵌套对象列表。嵌套对象甚至不可能吗?你最后是亲子了吗?也可以在这里查看我的问题stackoverflow.com/questions/48750696/…
  • 我没有找到我想要的东西。如果我负责弹性,我可能会添加这个功能!
  • @Phillip Baumann 的答案就是您所需要的。请检查它和我的评论。
  • @Algorini 请阅读上面 Emil 的评论,如果我在 es 文档中对同一个数组使用 must 运算符进行多个嵌套查询,则单独返回内部命中,如何获得常见的组合内部命中。请对此提供帮助,如果您需要更多详细信息,请告诉我。

标签: elasticsearch


【解决方案1】:

hits 部分返回 _source - 这与您索引的文档完全相同。

你是对的,嵌套查询过滤顶级结果,但是使用inner_hits,它会显示哪些内部嵌套对象导致这些顶级文档被返回,而这正是你所需要的。

names 字段可以使用_source 参数从顶级匹配中排除。

{
   "_source": {
      "excludes": ["names"]
   },
   "query":{
      "bool":{
         "must":[
            {
               "term":{
                  "number":{
                     "value":"1234"
                  }
               }
            },
            {
               "nested":{
                  "path":"names",
                  "query":{
                     "term":{
                        "names.lastName":"Jones"
                     }
                  },
                  "inner_hits":{
                  }
               }
            }
         ]
      }
   }
}

因此,现在返回的顶级文档没有 names 字段,并且您还有一个额外的 inner_hits 部分,其名称匹配。
您应该将嵌套对象视为顶级文档的一部分。 如果你真的需要它们分开 - 考虑parent/child relations.

【讨论】:

  • 这个答案是错误的,原因很简单,顶级命中的 _source 字段仍然会包含所有嵌套文档。是的,您将在 inner_hits 中获得匹配的嵌套文档,但您的响应会膨胀,因为它仍然包含原始 _source 字段中的所有嵌套命中。正确的方法是通过 source_filtering 排除“名称”,并使用 inner_hits 仅保留匹配的嵌套文档。有关正确查询,请参阅下面的@Phillip Baumann 的答案。
  • @user2076066 很好,我已经用源过滤更新了我的答案。
【解决方案2】:

试试这样的

{
   "query": {
      "filtered": {
         "query": {
            "match_all": {}
         },
         "filter": {
            "bool": {
               "must": [
                  {
                     { "term": { "number":1234} }
                  },
                  {
                     "nested": {
                        "path": "something",
                        "query": {
                           "term": {
                              "something.lastName": "Jones"
                           }
                        },
                        "inner_hits" : {}
                     }
                  }
               ]
            }
         }
      }
   }
}

我用过这个Refrence

【讨论】:

  • 不错的尝试,但它会根据嵌套内容过滤文档,因此我的结果中仍然会同时得到这两个名称。 (另外,您忘记了 nested 中的中间 "query" : { "bool": {。)我想在文档中进行过滤,以便我只得到一个数字 1234 的名称。
  • 在您编写时运行它会导致第 3 行出现 parsing_exception no [query] registered for [filtered]。我不确定如何修复您的查询以尝试它。我猜你在"nested" 中忘记了中间的"query" : { "bool": {。我还认为您不需要"filtered",也不需要"bool" 之外的"filter"。继续努力,谢谢!
  • 阅读 inner_hits 文档并尝试它,我认为它对我没有帮助。 inner_hits 可以在单独的部分中为您提供不同的分页或汇总内部元素的方式,但我想将其中一些从结果中完全过滤掉。如我错了请纠正我。另见:elastic.co/guide/en/elasticsearch/reference/current/…
【解决方案3】:

类似但有点不同,使用 should 参数,然后查看名称的内部匹配项。这将返回顶级文档,然后 inner_hits 将有任何命中。

   { 
      "_source": {
        "excludes": ["names"]
      },
       "query":{
          "bool":{
             "must":[
                {
                   "term":{
                      "number":{
                         "value":"1234"
                      }
                   }
                }
             ],
             should: [
             {
                "nested":{
                   "path":"names",
                   "query":{
                      "term":{
                         "names.lastName":"Jones"
                      }
                   },
                   "inner_hits":{
                   }
                }
             }

             ]
          }
       }
    }

【讨论】:

  • 这是正确的答案。原因是它排除了嵌套的“名称”字段,内部匹配只会显示匹配的内部匹配。这意味着您需要重新组装您的文档(客户端)。在选择为“正确”的答案中,最初的目的被破坏了,因为顶级命中的 _source 仍然会携带所有嵌套文档,并且您的响应实际上更加膨胀。
  • 排除部分是正确的,虽然嵌套过滤器必须在must部分,而不是在should之一。
猜你喜欢
  • 1970-01-01
  • 2015-05-06
  • 1970-01-01
  • 1970-01-01
  • 2021-01-21
  • 2021-10-18
  • 2015-03-03
  • 2018-05-10
  • 1970-01-01
相关资源
最近更新 更多