一尘不染

Elasticsearch中的组合非嵌套查询和嵌套查询

elasticsearch

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

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

我不明白的是:如何构造搜索查询,以便在搜索“一二”时仅找到第二本书,而在搜索“二三”时什么也找不到,而在搜索“一”时所有图书呢?


阅读 381

收藏
2020-06-22

共1个答案

一尘不染

也许是这样的?

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

该查询基本上说一个文件必须有author: oneand books.title: two。您可以轻松地重新配置该查询。例如,如果您只想搜索作者,请删除嵌套部分。如果您想要另一本书,请更改嵌套等。

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

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

{
  "query" : {
    "term" : {
      "author_book" : "one two"
    }
  }
}
2020-06-22