【问题标题】:Elasticsearch - Filter where (one of nested array) and (all of nested array)Elasticsearch - 过滤位置(嵌套数组之一)和(所有嵌套数组)
【发布时间】:2015-12-13 01:29:10
【问题描述】:

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"
            }
    }}}}
}

所以,问题是……

如何根据innertype 匹配具有所有 inner 对象的至少一个 outer 对象的文档对象?

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

示例文档 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 它不需要匹配,因为它缺席。

【问题讨论】:

  • 您能否发布一些示例数据,可能是要点或其他内容?它需要包含足够的多样性来涵盖您的各种情况。我想我可能知道如何解决这个问题,但我不想整个上午都在构建虚拟数据来测试它。
  • @SloanAhrens - 我已经发布了一个包含一些详细信息的示例文档,如果这还不够,请告诉我,我会收集更多示例。我实际上并没有在上面的问题中使用生产数据/映射,所以我必须手动转换数据以匹配问题。
  • 不,我认为是这样做的。

标签: arrays elasticsearch nested


【解决方案1】:

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

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

如果您需要对逻辑进行一些解释,请告诉我;这有点涉及。

【讨论】:

  • 抱歉回复晚了,感谢您的帮助,但这不会找到没有任何外部对象的结果。另外,因为我们不能确定特定的type 肯定存在,所以如果Country 类型不存在,则不会找到任何文档。我想也许我需要在我的问题中加入更多澄清细节。不过,这确实对我有很大帮助。
  • +1 - 我最终确实想通了,但再次感谢您的所有帮助。我发布了一个包含我需要的详细信息的答案。
【解决方案2】:

嵌套数组之一

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

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

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

所有嵌套数组

只有当数组中的所有嵌套对象匹配更有趣时,才考虑使用嵌套过滤器进行匹配。事实上,这是不可能的。但是如果只有一个嵌套对象与过滤器匹配,则认为它被认为是匹配的,我们可以反转逻辑并说“如果嵌套对象中的 none 匹配”来实现我们所需要的。例如,给定一个嵌套的 outer.inner 对象数组,其中所有这些对象都有一个字段 match,其值为 "matching",以下将被视为 true。

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

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

缺少任何嵌套对象

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

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

如果match_all 没有找到结果,则认为这是真的/匹配。

【讨论】:

  • 谢谢,正是我要找的东西
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-08-25
  • 2012-08-07
相关资源
最近更新 更多