Elasticsearch - 过滤其中(嵌套数组之一)和(所有嵌套数组)

Elasticsearch - Filter where (one of nested array) and (all of nested array)

TL;DR - 如何检查 one-ofall- of 个嵌套数组满足指定条件?

我有一个document。每个 document 都有一个嵌套的 outer 对象数组,它们本身有一个嵌套的 inner 对象列表。我需要对所有 至少有一个 文档的 outer 嵌套对象匹配的所有文档执行过滤器。当我说匹配时,我的意思是 all outer 嵌套对象的 inner 对象以某种方式匹配。这是一个示例映射供参考;

{ "document" : {
    "properties" : {
      "name" : {
        "type" : "string"
      },
      "outer" : {
        "type" : "nested",
        "properties" : {
          "inner" : {
            "type" : "nested",
            "properties" : {
              "match" : {
                "type" : "string",
                "index" : "not_analyzed"
              },
              "type" : {
                "type" : "string",
                "index" : "not_analyzed"
              }
    }}}}}}
}

如果文档没有 outer/inner 个对象,则认为它匹配。但更糟糕的是,内部对象需要考虑以一种条件逻辑方式根据 type 进行不同的匹配(例如 SQL 中的 CASE)。例如,如果 type 是术语 "Country",那么如果 match 是指定的国家/地区代码,例如 ES,则 inner 对象将被视为匹配。一个文档可能有 inner 个不同 type 的对象,并且不能保证特定类型将存在。

来自命令式 (Java) 编程背景,我在弄清楚如何实现这种过滤方面遇到了难以置信的麻烦。我能想到的任何东西甚至都模糊地符合这种行为。到目前为止,我只有过滤后的查询;

"filtered" : {
      "query" : {
        "match_all" : { }
      },
      "filter" : {
        "bool" : {
          "should" : {
            "missing" : {
              "field" : "outer.inner.type"
            }
    }}}}
}

那么,问题是……

我如何筛选出具有 至少一个 outer 对象且具有 all inner 的文档基于 inner object?

type 的对象匹配

根据要求提供更多详细信息 -

示例文档JSON

{
    "name":"First",
    "outer":[
        {
            "inner":[
                {"match":"ES","type":"Country"},
                {"match":"Elite","type":"Market"}
            ]
        },{
            "inner":[
                {"match":"GBR","type":"Country"},
                {"match":"1st Class","type":"Market"},
                {"match":"Admin","type":"Role"}
            ]
        }
    ],
    "lockVersion":0,"sourceId":"1"
}

如果我们要提供 "1st Class" 市场 国家 "GRB",上面的例子应该通过过滤器,因为两者中的第二个 outer 个对象将被视为匹配项,因为两个 inner 个对象都匹配。但是,如果我们提供国家 "GRB" 和市场 "Elite" 那么我们将不会返回此文档,因为 outer 对象都不会打扰它们的 inner对象完全匹配。如果我们希望第二个 outer 对象匹配,那么所有三个 inner 都需要匹配。注意第三个inner中多了一个type。这会导致 if 类型存在 then 它需要匹配 else它不需要匹配,因为它不存在。

好吧,这很傻,但这个查询似乎可以满足您的要求:

POST /test_index/_search
{
   "query": {
      "filtered": {
         "filter": {
            "nested": {
               "path": "outer",
               "filter": {
                  "bool": {
                     "must": [
                        {
                           "nested": {
                              "path": "outer.inner",
                              "filter": {
                                 "bool": {
                                    "must": [
                                       { "term": { "outer.inner.type": "Market" } },
                                       { "term": { "outer.inner.match": "1st Class" } }
                                    ]
                                 }
                              }
                           }
                        },
                        {
                           "nested": {
                              "path": "outer.inner",
                              "filter": {
                                 "bool": {
                                    "must": [
                                       { "term": { "outer.inner.type": "Country" } },
                                       { "term": { "outer.inner.match": "GBR" } }
                                    ]
                                 }
                              }
                           }
                        }
                     ]
                  }
               }
            }
         }
      }
   }
}

这是我用来测试它的一些代码:

http://sense.qbox.io/gist/f554c2ad2ef2c7e6f5b94b1ddb907813370f4edc

如果您需要一些逻辑解释,请告诉我;有点牵扯了。

嵌套数组之一

拥有其中一个嵌套数组匹配某些条件证明是非常简单的。如果嵌套对象数组中的任何一个与指定的内部过滤器匹配,则 nested filter 的计算结果为 matching/true。例如,给定一个包含 outer 个对象的数组,其中一个对象的字段 match 的值为 "matching",则以下内容将被视为 true。

"nested": {
   "path": "outer",
   "filter": {
       "term" : { "match" : "matching" } 
   }
}

如果 其中一个 嵌套 outer 对象具有名为 match 且值为 "matching".

所有嵌套数组

如果所有数组中的嵌套对象都匹配,则只有嵌套过滤器才被视为匹配更有趣。事实上,这是不可能的。但是考虑到如果只有一个嵌套对象匹配过滤器就被认为是匹配的,我们可以反转逻辑并说 "If none of the nested objects don't match" 来实现我们需要的。例如,给定一个嵌套 outer.inner 对象的数组,其中所有这些对象都有一个值为 "matching" 的字段 match,以下将被认为是正确的。

"not" : {
   "nested": {
      "path": "outer.inner",
      "filter": {
          "not" : {
              "term" : { "match" : "matching" } 
          }
      }
   }
}

以上将被视为 true/matching 因为嵌套 outer.inner 对象的 none (双重否定)有一个名为 match 的字段,其值为 "matching"。当然,这与 所有 嵌套 inner 对象具有字段 match 且值为 "matching".

缺少任何嵌套对象

您无法检查是否缺少包含嵌套对象的字段,使用传统的 missing filter. This is because nested objects aren't actually in the document at all, they are stored somewhere else. As such missing filters 将始终被视为 true。但是,您可以做的是检查 match_all 过滤器 returns 没有这样的结果;

"not": {
   "nested": {
      "path": "outer",
      "filter": {
          "match_all": {}
       }
    }
 }

如果 match_all 没有找到结果,这将被视为 true/matching。