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

时间:2015-09-16 12:43:55

标签: arrays elasticsearch nested

TL; DR - 如何检查一个全部嵌套数组是否符合指定条件?

我有document。每个document都有一个嵌套的outer对象数组,这些对象本身有一个嵌套的inner对象列表。我需要对至少一个文档的outer嵌套对象匹配的所有文档执行过滤。当我说匹配时,我的意思是所有 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",那么inner对象将被视为匹配,如果match是指定的国家/地区代码,例如ES。文档可能包含innertype个不同的对象,并且不保证存在特定类型。

来自命令式(Java)编程背景我在弄清楚如何实现这种过滤方面遇到了令人难以置信的麻烦。没有什么我能想到甚至模糊地匹配这种行为。到目前为止,我所拥有的只是过滤后的查询;

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

所以,问题是......

如何过滤到至少一个 outer对象的文档,该对象具有基于{{1}匹配的所有 inner个对象} type对象?

进一步详情请求 -

示例文档JSON

inner

如果我们要提供{ "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中还有一个type。这导致如果类型存在然后它需要匹配 else 它不需要匹配的情况因为它不存在

2 个答案:

答案 0 :(得分:15)

嵌套数组之一

一个符合某些条件的嵌套数组变得非常简单。如果任何嵌套对象数组与指定的内部过滤器匹配,则nested filter求值为匹配/ true。例如,给定一组outer个对象,其中一个对象的字段match的值为"matching",则以下内容将被视为真。

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

如果其中一个嵌套outer对象的字段名为match且值为"matching",则上述内容将被视为真/匹配。

所有嵌套数组

如果全部数组匹配中的嵌套对象更有趣,则只能将嵌套过滤器视为匹配。事实上,这是不可能的。但是,如果只有一个嵌套对象与过滤器匹配,则认为它是匹配的,我们可以反转逻辑并说“如果嵌套对象匹配”实现我们的需要。例如,给定一组嵌套的outer.inner对象,其中所有这些对象的字段match的值为"matching",以下内容将被视为真。

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

上述内容将被视为真/匹配,因为嵌套outer.inner对象的 (双重否定)有一个名为{{1的字段值match。当然,这与所有具有值"matching"的字段inner的嵌套match对象相同。

缺少任何嵌套对象

使用传统的missing filter无法检查是否缺少包含嵌套对象的字段。这是因为嵌套对象实际上不是文档中,它们存储在其他地方。因此missing filters将始终被视为真实。但是,您可以检查"matching"过滤器是否返回没有这样的结果;

match_all

如果"not": { "nested": { "path": "outer", "filter": { "match_all": {} } } } 未找到任何结果,则视为真/匹配。

答案 1 :(得分:3)

嗯,这很麻烦,但这个查询似乎可以做你想要的:

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

如果您需要对逻辑进行一些解释,请告诉我。它有点牵扯。