ElasticSearch:在属性和嵌套对象上使用带有query_string的多字段查询

时间:2018-07-10 08:28:51

标签: elasticsearch

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

  • 在已经具有属性:名称和描述的文档上保存任意数量的键值对
  • 值可以是应该可以“范围内搜索”的数字
  • 值可以包含需要“可地理搜索”的geo_points

我创建了以下索引。

{
    "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_ *属性来保留该类型化的值。这样就可以对特殊类型进行特殊搜索,例如范围查询。

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

键-值对应该有相同的情况,例如: attribute.key:someKey和attribute.val_string:someStringValue。 这种情况需要我们使用嵌套查询并按预期工作。

什么不起作用: 如果我们搜索name:foo和attribute.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"
                    }
                }
            ]
        }
    }
}

任何帮助将不胜感激。预先谢谢你。

1 个答案:

答案 0 :(得分:1)

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

_doc 没有(未嵌套的)字段属性,并且属性不包含字段 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]

时都会生成嵌套查询。