【问题标题】:Searching Nested Document搜索嵌套文档
【发布时间】:2018-03-15 21:21:15
【问题描述】:

我在 Python 中使用 elasticsearch_dslelasticsearch 库搜索嵌套文档时遇到问题。

我可以成功地对文档的顶级(即非嵌套)部分执行搜索,但我所有搜索嵌套部分的尝试都因某种原因而失败。

我已经在 StackOverflow 和网络上搜索了一份使用 Python 搜索嵌套文档的权威指南,但总是很短。

这是我正在使用的示例文档:

{"username": "nancy",
"codeData": [
 {"code": "B1", "order": "2"}, 
 {"code": "L4", "order": "1"}
  ] 
}

我在索引中有 7 个文档,我已将其映射如下:

request_body = {
    "settings" : {
        "number_of_shards": 5,
        "number_of_replicas": 1
    },

    'mappings': {
        'testNesting': {
            'properties': {
                'username': {'type': 'text'},
                'codeData': {'type': 'nested',
                                  'properties' :{
                                      "code" : {"type":"text"},
                                      "order" :{"type":"text"}
                                      }
                                    }
                                 }
            }
        }
    }
es.indices.create(index = "nest-test6", body = request_body)

执行以下搜索可以正常工作:

s = Search(using = es).query("match", username = "nancy")
response = s.execute()
print(response.to_dict())

现在,我想尝试在“codeData”中搜索代码 =“B1”的文档。

我在这个问题的底部列出了我尝试使用的来源。我希望这可以成为人们在尝试使用 Python 查询嵌套文档时可以参考的权威指南。

这是我迄今为止尝试过的:

q = Q("match", code = "L4")
s = Search(using = es, index = "nest-test6").query("nested", path = "codeData", query = q)

上面会导致传输错误(400,未能创建查询),然后列出查询本身,并在每个项目后加上一堆 \n。

q = Q("match", **{"codeData.code"" : "L4"})
s = Search(using = es, index = "nest-test6").query("nested", path = "codeData", query = q)

上面会导致第 1 行出现语法错误。

s = Search(using = es, index = "nest-test6").query("nested", path = "lithologyData", query = **Q{"match":{ "lithology":"L4"}})

以上也会导致语法错误。

我尝试了其他几种方法 - 但更改了我的数据结构,因此在此处列出它们在上述文档的上下文中没有意义。

我不知道如何查询这些嵌套对象。我觉得我缺少几条信息:

  1. 什么是 Q/F 关键字,如何使用它们?
  2. 我知道我必须使用 level1.nameOfObjectBeingQueried 指定查询词的路径 - 鉴于这不是 Python 库中的合适关键字,我该如何处理?

如果我还缺少任何其他来源,我将非常感谢有人将我指向他们!

其他失败的尝试

s1 = Search(using = es).query("match", username = "nancy")
q1 = Q("match", lithologyData__lithology = "L4")
q2 = Q("match", **{"lithologyData.lithology":"L4"})
s2 = Search(using = es, index = "nest-test6").query("nested", path = "lithologyData", query = Q("match",lithologyData__lithology="L4"))
s3 = Search(using = es, index = "nest-test6").query("nested", path = "lithologyData", query = q1)
s4 = Search(using = es, index = "nest-test6").query("nested", path = "lithologyData", query = q2)
response = s1.execute()
response2 = s2.execute()
response3 = s3.execute()
response4 = s4.execute()

响应 1:有效

响应 2:失败:

TransportError(400, u'search_phase_execution_exception', u'failed to create query: {\n  "nested" : {\n    "query" : {\n      "match" : {\n        "codeData.code" : {\n          "query" : "L4",\n          "operator" : "OR",\n          "prefix_length" : 0,\n          "max_expansions" : 50,\n          "fuzzy_transpositions" : true,\n          "lenient" : false,\n          "zero_terms_query" : "NONE",\n          "auto_generate_synonyms_phrase_query" : true,\n          "boost" : 1.0\n        }\n      }\n    },\n    "path" : "codeData",\n    "ignore_unmapped" : false,\n    "score_mode" : "avg",\n    "boost" : 1.0\n  }\n}')

响应 3:失败:

TransportError(400, u'search_phase_execution_exception', u'failed to create query: {\n  "nested" : {\n    "query" : {\n      "match" : {\n        "codeData.code" : {\n          "query" : "L4",\n          "operator" : "OR",\n          "prefix_length" : 0,\n          "max_expansions" : 50,\n          "fuzzy_transpositions" : true,\n          "lenient" : false,\n          "zero_terms_query" : "NONE",\n          "auto_generate_synonyms_phrase_query" : true,\n          "boost" : 1.0\n        }\n      }\n    },\n    "path" : "codeData",\n    "ignore_unmapped" : false,\n    "score_mode" : "avg",\n    "boost" : 1.0\n  }\n}')

响应 4:失败: TransportError(400, u'search_phase_execution_exception', u'failed to create query: {\n "nested" : {\n "query" : {\n "match" : {\n "codeData.code" : {\n "query" : "L4",\n "operator" : "OR",\n "prefix_length" : 0,\n "max_expansions" : 50,\n "fuzzy_transpositions" : true,\n "lenient" : false,\n "zero_terms_query" : "NONE",\n "auto_generate_synonyms_phrase_query" : true,\n "boost" : 1.0\n }\n }\n },\n "path" : "codeData",\n "ignore_unmapped" : false,\n "score_mode" : "avg",\n "boost" : 1.0\n }\n}')

检查的其他资源

ElasticSearch Nested Query Reference

  • 这里的问题是它只描述了如何使用 REST API 来做这个查询。在关于为什么创建 elasticsearch_dsl 和 elasticsearch Python 库的描述中,他们特别提到了直接发送 JSON 结构的困难。尽管他们经常提到用户错误的可能性,但我认为还有一些我不理解的其他方面。

Github Issue on ElasticSearch_DSL py

  • 这里他们建议解包字典,因为您不能使用“level1.level2”作为参数。然而,创作者同意这远非理想。这个问题来自 2014 年,根据其他答案,现在似乎有更好的方法,但我找不到详细信息

ElasticSearch_DSL Python Documentation - 尽管这很有用,但文档中没有一个嵌套搜索/查询的示例。

【问题讨论】:

    标签: python elasticsearch elasticsearch-dsl


    【解决方案1】:

    要查询嵌套字段,您似乎有正确的方法:

    q = Q("match", codeData__code="L4")
    s = Search(using=es, index="nest-test6").query("nested", path="codeData", query=q)
    

    传递给Q 的kwarg 中的任何__ 都将在内部转换为.。或者,您始终可以依赖 python kwarg 扩展:

    q = Q('match', **{"codeData.code": "L4"})
    

    应该也可以,您的示例中只是有一个额外的",这就是它被python拒绝的原因。

    【讨论】:

    • 您好 Honza - 非常感谢您的回复。在我提出这个问题并更正之后,我注意到了额外的 ",但是我仍然遇到同样的问题。
    • 我刚刚将我在编辑中尝试过的 4 个查询添加到主要问题,但无济于事。我也不确定如何解释错误:(。
    • HI Honza,您知道如何使用多码查询吗?我尝试像Q("match", codeData__code=["L4", "L6"]) 那样做某事,但没有成功
    • @eduzen 您可以同时使用两个查询 OR'd - q = Q("match", codeData__code="L4") | Q("match", codeData__code="L6") 或者您可以使用可以处理多个值的特殊查询,例如 terms
    猜你喜欢
    • 2011-05-24
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多