如何从Elasticsearch 6.1中排除搜索字段?

时间:2018-10-11 09:59:01

标签: elasticsearch elasticsearch-6

我有一个包含多个字段的索引。我想根据除一个- user_comments 以外的所有字段中搜索字符串的存在来过滤掉。 我正在做的查询搜索是

{
    "from": offset,
    "size": limit,
    "_source": [
      "document_title"
    ],
    "query": {
      "function_score": {
        "query": {
          "bool": {
            "must":
            {
              "query_string": {
                "query": "#{query}"
              }
            }
          }
        }
      }
    }
  }

尽管查询字符串正在所有字段中进行搜索,并且还在 user_comments 字段中为我提供了具有匹配字符串的文档。但是,我想对所有字段进行查询,而忽略了 user_comments 字段。  白名单是一个很大的列表,并且字段名称是动态的,因此使用fields参数(例如)来提及白名单字段列表是不可行的。

"query_string": {
                    "query": "#{query}",
                    "fields": [
                      "document_title",
                      "field2"
                    ]
                  }

有人可以提出一个关于如何排除搜索字段的想法吗?

2 个答案:

答案 0 :(得分:1)

有一种方法可以使它工作,虽然不漂亮,但可以完成工作。您可以使用query_stringboost查询的multifieldbool参数来组合分数并设置min_score

POST my-query-string/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "#{query}",
            "type": "most_fields",
            "boost": 1
          }
        },
        {
          "query_string": {
            "fields": [
              "comments"
            ],
            "query": "#{query}",
            "boost": -1
          }
        }
      ]
    }
  },
  "min_score": 0.00001
}

那在引擎盖下会发生什么?

假设您具有以下文档集:

PUT my-query-string/doc/1
{
  "title": "Prodigy in Bristol",
  "text": "Prodigy in Bristol",
  "comments": "Prodigy in Bristol"
}
PUT my-query-string/doc/2
{
  "title": "Prodigy in Birmigham",
  "text": "Prodigy in Birmigham",
  "comments": "And also in Bristol"
}
PUT my-query-string/doc/3
{
  "title": "Prodigy in Birmigham",
  "text": "Prodigy in Birmigham and Bristol",
  "comments": "And also in Cardiff"
}
PUT my-query-string/doc/4
{
  "title": "Prodigy in Birmigham",
  "text": "Prodigy in Birmigham",
  "comments": "And also in Cardiff"
}

在搜索请求中,您只想看到文档1和3,但是原始查询将返回1、2和3。

在Elasticsearch中,搜索结果按relevance _score排序,得分越大越好。

因此,让我们尝试将"comments"字段下移boost,以便忽略其对相关性得分的影响。我们可以通过将两个查询与一个should并使用一个否定的boost来做到这一点:

POST my-query-string/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "Bristol"
          }
        },
        {
          "query_string": {
            "fields": [
              "comments"
            ],
            "query": "Bristol",
            "boost": -1
          }
        }
      ]
    }
  }
}

这将为我们提供以下输出:

{
  "hits": {
    "total": 3,
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "my-query-string",
        "_type": "doc",
        "_id": "3",
        "_score": 0.2876821,
        "_source": {
          "title": "Prodigy in Birmigham",
          "text": "Prodigy in Birmigham and Bristol",
          "comments": "And also in Cardiff"
        }
      },
      {
        "_index": "my-query-string",
        "_type": "doc",
        "_id": "2",
        "_score": 0,
        "_source": {
          "title": "Prodigy in Birmigham",
          "text": "Prodigy in Birmigham",
          "comments": "And also in Bristol"
        }
      },
      {
        "_index": "my-query-string",
        "_type": "doc",
        "_id": "1",
        "_score": 0,
        "_source": {
          "title": "Prodigy in Bristol",
          "text": "Prodigy in Bristol",
          "comments": "Prodigy in Bristol",
          "discount_percent": 10
        }
      }
    ]
  }
}

文档2受到了处罚,但是文档1也受到了惩罚,尽管这对我们来说是理想的选择。为什么会发生?

在这种情况下,Elasticsearch计算_score的方式:

  

_score = max(标题:“布里斯托尔”,文字:“布里斯托尔”,评论:“布里斯托尔”)-评论:“布里斯托尔”

文档1与comments:"Bristol"部分匹配,它也恰好是最好的分数。根据我们的公式,得分为0。

我们实际上想做的是,如果匹配更多字段,则增强第一个子句(带有“所有”字段)更多

我们可以提高query_string匹配更多字段吗?

我们可以在multifield模式下使用query_string的{​​{1}}参数来做到这一点。查询将如下所示:

type

这将为我们提供以下输出:

POST my-query-string/doc/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "type": "most_fields",
            "query": "Bristol"
          }
        },
        {
          "query_string": {
            "fields": [
              "comments"
            ],
            "query": "Bristol",
            "boost": -1
          }
        }
      ]
    }
  }
}

如您所见,不希望有的文档2位于底部,得分为0。这是这次得分的计算方式:

  

_score = sum(标题:“布里斯托尔”,文字:“布里斯托尔”,评论:“布里斯托尔”)-评论:“布里斯托尔”

因此选择了与任何字段中的{ "hits": { "total": 3, "max_score": 0.57536423, "hits": [ { "_index": "my-query-string", "_type": "doc", "_id": "1", "_score": 0.57536423, "_source": { "title": "Prodigy in Bristol", "text": "Prodigy in Bristol", "comments": "Prodigy in Bristol", "discount_percent": 10 } }, { "_index": "my-query-string", "_type": "doc", "_id": "3", "_score": 0.2876821, "_source": { "title": "Prodigy in Birmigham", "text": "Prodigy in Birmigham and Bristol", "comments": "And also in Cardiff" } }, { "_index": "my-query-string", "_type": "doc", "_id": "2", "_score": 0, "_source": { "title": "Prodigy in Birmigham", "text": "Prodigy in Birmigham", "comments": "And also in Bristol" } } ] } } 相匹配的文档。 "Bristol"的相关性得分被消除,只有匹配comments:"Bristol"title:"Bristol"的文档的text:"Bristol"> 0。

我们可以过滤掉那些分数不合要求的结果吗?

是的,我们可以使用min_score

_score

(在我们的示例中)这是可行的,因为仅当POST my-query-string/doc/_search { "query": { "bool": { "should": [ { "query_string": { "query": "Bristol", "type": "most_fields", "boost": 1 } }, { "query_string": { "fields": [ "comments" ], "query": "Bristol", "boost": -1 } } ] } }, "min_score": 0.00001 } 仅与字段"Bristol"相匹配且不与任何其他字段相匹配时,文档的分数才为0。

输出将是:

"comments"

可以用其他方式完成吗?

好的。我实际上不建议进行{ "hits": { "total": 2, "max_score": 0.57536423, "hits": [ { "_index": "my-query-string", "_type": "doc", "_id": "1", "_score": 0.57536423, "_source": { "title": "Prodigy in Bristol", "text": "Prodigy in Bristol", "comments": "Prodigy in Bristol", "discount_percent": 10 } }, { "_index": "my-query-string", "_type": "doc", "_id": "3", "_score": 0.2876821, "_source": { "title": "Prodigy in Birmigham", "text": "Prodigy in Birmigham and Bristol", "comments": "And also in Cardiff" } } ] } } 调整,因为这是一件非常复杂的事情。

我建议获取现有映射并构造一个字段列表以预先针对该字段运行查询,这将使代码更加简单明了。

希望有帮助!

答案中提出的原始解决方案(保留历史记录)

最初,建议使用与上述解决方案完全相同的意图进行此类查询:

_score

唯一的问题是,如果索引包含任何数值,则此部分:

POST my-query-string/doc/_search
{
  "query": {
    "function_score": {
      "query": {
        "bool": {
          "must": {
            "query_string": {
              "fields" : ["*", "comments^0"],
              "query": "#{query}"
            }
          }
        }
      }
    }
  },
  "min_score": 0.00001
}

引发错误,因为文本查询字符串不能应用于数字。


希望有帮助!

答案 1 :(得分:0)

ES的搜索方式将在_all字段中查找匹配项。要排除一个字段,可以为用户评论禁用_all字段。

参考- https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping-all-field.html#enabling-all-field

对于ES 6.x,可以使用copy_to

复制它

https://www.elastic.co/guide/en/elasticsearch/reference/current/copy-to.html