首页 > 解决方案 > ElasticSearch:在属性和嵌套对象上使用 query_string 的多字段查询

问题描述

我正在尝试解决以下高级要求:

我创建了以下索引。

{
    "settings": {
        "index" : {
            "number_of_shards" : 3, 
            "number_of_replicas" : 1
        }
    },
    "mappings": {
        "_doc": {
            "dynamic": "strict",
            "properties": {
                "name": {
                    "type": "text",
                    "analyzer": "german",
                },
                "description": {
                    "type": "text",
                    "analyzer": "german"
                },
                "attributes": {
                    "type": "nested",
                    "properties": {
                        "key": { "type": "text" },
                        "val_bool":   { "type": "boolean" },
                        "val_int":    { "type": "integer" },
                        "val_float":  { "type": "float" },
                        "val_string": { "type": "text" },
                        "val_geo":    { "type": "geo_point" },
                        "val_date":   { "type": "date" }
                    }
                }
            }
        }
    }
}

我们使用嵌套对象来保存每个文档的键值对列表。每个键值对使用一个类型化的 val_* 属性来持久化类型化的值。从而启用对特殊类型的特殊搜索,例如 Range-Query。

为了在文档中搜索,我们使用 query_string 查询来允许用户在搜索中非常具体。例如。搜索名称:foo 和描述:bar 的文档。(按预期工作)

键值对应该可以实现相同的场景。例如:attributes.key:someKey AND attributes.val_string:someStringValue。这种情况需要我们使用并按预期工作的嵌套查询。

什么不起作用: 如果我们搜索 name:foo AND attributes.key:someKey 我们没有得到任何结果。

似乎不支持“嵌套查询字符串查询”和“仅查询字符串查询”的组合。真的吗?实现所述要求的可行解决方法是什么?

查询如下所示:

{
    "query": {
        "bool": {
            "should": [
                {
                    "query_string": {
                        "query": "attributes.key:someKey AND name:foo",
                        "default_operator": "and",
                        "fields": [
                            "name",
                            "description"
                        ]
                    }
                },
                {
                    "nested": {
                        "query": {
                            "query_string": {
                                "query": "attributes.key:someKey AND name:foo",
                                "default_operator": "and",
                                "fields": [
                                    "attributes.key",
                                    "attributes.val_string"
                                ]
                            }
                        },
                        "path": "attributes"
                    }
                }
            ]
        }
    }
}

任何帮助是极大的赞赏。先感谢您。

标签: elasticsearch

解决方案


嵌套对象被索引为单独的文档。也就是说,您正在有效地查询两个文档,但它们都不匹配给定的查询:

_doc没有(不是嵌套的)字段attributes,并且attributes不包含字段name。由于查询中的两个词在逻辑上都用 AND 链接,因此搜索结果为零。

类似的问题出现在查询字符串中,例如attributes.key:someKey AND attributes.key:otherKey在尝试检索所有包含两个嵌套对象且具有指定键之一的根父文档时。因为两个嵌套对象彼此独立,所以此查询正在寻找具有两个键的嵌套对象 - 但每个对象只能有一个。

要解决这个问题,您必须以某种方式将查询拆分为与根父文档相关的部分和嵌套对象的部分。之后,您必须为引用嵌套对象的每个术语创建一个嵌套查询。换句话说,name:foo AND attributes.key:someKey必须最终看起来像这样:

{
    "query": {
        "bool": {
            "must": [
                {
                    "query_string": {
                        "query": "name:foo"       
                    }
                },
                {
                    "nested": {
                        "query": {
                            "query_string": {
                                "query": "attributes.key:someKey"
                            }
                        },
                        "path": "attributes"
                    }
                }
            ]
        }
    }
}

一种可能的解决方案是提供多个输入,一个用于查询根父文档本身,另一个用于查询嵌套对象。然后,您可以通过手动创建一个由嵌套部分和非嵌套部分组成的查询来组合这两个查询字符串。

或者,您可以考虑自己解析查询,每次遇到attributes.[field]时都会生成一个嵌套查询。


推荐阅读