Elasticsearch - 在文档中比较一个嵌套字段和另一个字段

7

我需要比较同一文档中的2个字段,实际值并不重要。考虑以下文档:

_source: {
    id: 123,
    primary_content_type_id: 12,
    content: [
        {
            id: 4,
            content_type_id: 1
            assigned: true
        },
        {
            id: 5,
            content_type_id: 12,
            assigned: false
        }
    ]
}

我需要找到所有未分配主要内容的文档。 我无法找到一种方法来比较primary_content_type_id和嵌套的content.content_type_id以确保它们具有相同的值。 这是我使用脚本尝试过的方法。 我不认为我理解脚本,但这可能是解决此问题的一种方法:

{
    "filter": {
        "nested": {
            "path": "content",
            "filter": {
                "bool": {
                    "must": [
                        {
                            "term": {
                                "content.assigned": false
                            }
                        },
                        {
                            "script": {
                                "script": "primary_content_type_id==content.content_type_id"
                            }
                        }
                    ]
                }
            }
        }
    }
}

请注意,如果我删除过滤器部分并将其替换为另一个术语过滤器,则正常工作。其中content_type_id = 12,并且添加另一个过滤器,其中primary_content_id = 12。问题是我不知道(对我的用例也没有影响)primary_content_type_idcontent.content_type_id的值是什么,只有在content_type_idprimary_content_type_id匹配的内容中分配了假内容才很重要。
Elasticsearch是否支持此检查?
1个回答

7

对于嵌套搜索,您正在搜索没有父级的嵌套对象。不幸的是,您无法通过 nested 对象应用隐藏的连接。

至少目前为止,这意味着您在脚本中无法同时接收“父级”和嵌套文档。您可以通过替换脚本并测试结果来确认这一点:

# Parent Document does not exist
"script": {
  "script": "doc['primary_content_type_id'].value == 12"
}

# Nested Document should exist
"script": {
  "script": "doc['content.content_type_id'].value == 12"
}

你可以通过循环遍历对象来完成此操作,但这种方法性能较差(而不是使用嵌套让ES自动完成)。这意味着你需要重新索引文档和嵌套文档以便它们作为单个文档工作。考虑到你想使用的方式,这可能并没有太大区别,甚至可能表现更好(特别是因为没有其他选择)。
# This assumes that your default scripting language is Groovy (default in 1.4)
# Note1: "find" will loop across all of the values, but it will
#  appropriately short circuit if it finds any!
# Note2: It would be preferable to use doc throughout, but since we need the
#  arrays (plural!) to be in the _same_ order, then we need to parse the
#  _source. This inherently means that you must _store_ the _source, which
#  is the default. Parsing the _source only happens on the first touch.
"script": {
  "script": "_source.content.find { it.content_type_id == _source.primary_content_type_id && ! it.assigned } != null",
  "_cache" : true
}

我缓存了结果,因为这里没有发生任何动态情况(例如不与现在的日期进行比较),所以它非常适合进行缓存,从而使未来的查找速度更快。大多数过滤器默认都会被缓存,但是脚本是少数例外之一
由于它必须比较两个值才能确定是否找到了正确的内部对象,因此您正在重复执行某些工作,但这几乎是不可避免的。拥有term过滤器很可能比没有它进行此检查要好。

it 是 Groovy Closure 的隐含第一个参数。因此,在通过 find 循环遍历 content 对象(在本例中)时,it 是实际的元素。 - pickypg
啊,我对Groovy了解得很少,it是一种类似对象的东西,我可以在其上调用参数。顺便说一下,我有点困扰于这个问题https://dev59.com/IZLea4cB1Zd3GeqP1Fp8,你有什么指导吗? - brupm
基本上,it 是传递到函数中的字段。想象一下 Closure(大括号内的所有内容)是 for 循环的一部分。它将是 for (int i = 0; i < _source.content.size(); ++i) { def it = _source.content[i]; callClosure(it); }。这就是实际发生的事情。现在,显然它必须与响应等一起工作,但这是特定于函数(find)的。 - pickypg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接