【问题标题】:Combined non-Nested and Nested Query in ElasticsearchElasticsearch 中的组合非嵌套和嵌套查询
【发布时间】:2014-03-07 22:51:16
【问题描述】:

我想使用 ES 进行图书搜索。所以我决定将作者姓名和标题(作为嵌套文档)放入索引中,如下所示:

curl -XPUT localhost:9200/library/search_books/1 -d'{
  "author": "one",
  "books": [
    {
      "title": "two",
    },
    {
      "title": "three",
    }
  ]
}'

我没有得到的是: 如何构建搜索查询结构,以在搜索“一二”时仅找到书二,在搜索“二三”时一无所获,在搜索“一”时查找所有书?

【问题讨论】:

    标签: elasticsearch


    【解决方案1】:

    也许是这样的?

    {
      "query":{
        "bool":{
          "must":[
            {
              "term":{
                "author":"one"
              }
            },
            {
              "nested":{
                "path":"books",
                "query":{
                  "term":{
                    "books.title":"two"
                  }
                }
              }
            }
          ]
        }
      }
    }
    

    该查询基本上表示文档必须具有author: onebooks.title: two。您可以轻松地重新配置该查询。例如,如果您只想搜索作者,请删除嵌套部分。如果您想要不同的书,请更改嵌套等。

    这假设您使用的是实际的Nested documents,而不是内部对象。对于内部对象,您可以只使用完全限定的路径,而无需特殊的嵌套查询。

    Edit1:您也许可以通过在索引时进行巧妙的提升来完成此操作,尽管这只是一个近似解决方案。如果“作者”被大幅提升,它的排序将高于仅与标题匹配,即使标题与查询的两个部分都匹配。然后,您可以使用 min_score 截止值来阻止显示。

    它只是一个松散的近似值,因为有些可能会通过。它还可能对“正确”匹配之间的一般排序产生奇怪的影响。

    Edit2:使用 query_string 更新以公开“单一输入”选项:

    
    {
      "query":{
        "query_string" : {
          "query" : "+author:one +books.title:two"
        }
      }
    }
    

    假设您使用的是默认的“内部对象”。如果你有真正的嵌套类型,query_string 会变得非常复杂:

    
    {
      "query":{
        "query_string" : {
          "query" : "+author:one +BlockJoinQuery (filtered(books.title:two)->cache(_type:__books))"
        }
      }
    }
    

    巨大的免责声明我没有测试这两个 query_strings 中的任何一个,所以它们可能并不完全正确。但它们表明 Lucene 语法并不过分友好。


    Edit3 - 这是我最好的主意:

    经过考虑,您最好的解决方案可能是索引一个连接作者和书名的特殊字段。像这样的:

    {
      "author": "one",
      "books": [
        {
          "title": "two",
        },
        {
          "title": "three",
        }
      ],
      "author_book": [ "one two", "one three" ]
    }
    

    然后在搜索时,您可以在 author_book 上进行精确的 Term 匹配:

    {
      "query" : {
        "term" : {
          "author_book" : "one two"
        }
      }
    }
    

    【讨论】:

    • 不是假设有两个搜索字段——一个用于作者,一个用于书籍吗?相反,我只有一个搜索字段。我确实使用嵌套文档来存放书籍。基本上我想找到作者和单本书的任意组合,但没有不同标题的组合。
    • 确实如此,是的。我已经用更多选项编辑了我的答案 - 在我看来,编辑 #3 是最好和最实用的。
    【解决方案2】:

    我在这篇文章中找到了答案:Fun With Elasticsearch's Children and Nested Documents。嵌套文档是关键。映射:

    {
      "book":{
        "properties": {
          "tags": { "type": "multi_field",
            "fields": {
                "tags": { "type": "string", "store":"yes", "index": "analyzed" },
                "facet": { "type": "string", "store":"yes", "index": "not_analyzed" }
            }
          },
          "editions": { "type": "nested", 
            "properties": {
              "title_author": { "type": "string", "store": "yes", "index": "analyzed" },
              "title": { "type": "string", "store": "yes", "index": "analyzed" }
            }
          }
        }
      }
    }
    

    文件:

    "tags": ["novel", "crime"],
      "editions": [
        {
          "title": "two",
          "title_author": "two one"
        },
        {
          "title": "three",
          "title_author": "three one"
        }
      ]
    

    现在我可以像这样搜索:

    {
    
      "query": {
        "bool": {
          "should": [
            {
              "nested": {
                "path": "editions",
                "query": {
                  "match": {
                    "editions.title_author": {
                      "query": "one two",
                      "operator": "and"
                    }
                  }
                }
              }
            }
          ]
        }
      }
    }
    

    如果搜索“二三”,我将找不到匹配项。我会得到一个“一二”或“一三”。在 1.1.0 版中,将有另一个带有 multi_match 查询和选项 cross_fields 的选项,允许不重复标题,只将作者姓名添加到每个嵌套文档中。这将使索引更小。

    【讨论】:

    • 这看起来不像是您的问题的解决方案?在您的问题中,您正在寻找根文档的部分匹配和内部匹配的部分匹配,并且您只想保持内部匹配匹配。在此解决方案中,您只查看内部匹配项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-08
    • 2018-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多