当前位置: 首页 > 面试题库 >

在Elasticsearch中正确排序以进行完全匹配和“开头为”(前缀)

漆雕正奇
2023-03-14
问题内容

我需要使用Elasticsearch改进搜索结果列表。

假设我们有3个文档,其中包含单个字段和内容,如下所示:

  • “苹果”
  • “青苹果”
  • “苹果树”

如果我搜索“苹果”,可能会发生这样的情况:我得到的排序结果如下:

  • “青苹果”
  • “苹果树”
  • “苹果”

但是我想要的是具有最高分数的精确匹配项,这里是带有“ apple”的文档。

下一个最高分应该是搜索词开头的条目,这里是“ apple tree”,其余按默认方式排序。

所以我想要这个:

  • “苹果”
  • “苹果树”
  • “青苹果”

我试图通过使用rescore实现它:

curl -X GET "http://localhost:9200/my_index_name/_search?size=10&pretty" -H 'Content-Type: application/json' -d'
{
   "query": {
      "query_string": {
          "query": "apple"
      }
   },
   "rescore": {
      "window_size": 500,
      "query": {
         "score_mode": "multiply",
         "rescore_query": {
            "bool": {
               "should": [
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple",
                           "boost": 4
                        }
                     }
                  },
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple*",
                           "boost": 2
                        }
                     }
                  }
               ]
            }
         },
         "query_weight": 0.7,
         "rescore_query_weight": 1.2
      }
   }
}'

但这并不是真的有效,因为Elasticsearch似乎用空格将所有单词分隔开。例如,搜索“ apple *”也将提供“ green
apple”。这似乎是recore无法为我工作的原因。

可能还有其他字符,例如点“。”,“-”,“;” 等等,Elasticsearch用来拆分和弄乱我的排序。

我还在“ rescore_query”中使用了“ match_phrase”,而不是“ bool”,但是没有成功。

我也尝试过只有一场比赛:

curl -X GET "http://localhost:9200/my_index_name/_search?size=10&pretty" -H 'Content-Type: application/json' -d'
{
   "query": {
      "query_string": {
          "query": "apple"
      }
   },
   "rescore": {
      "window_size": 500,
      "query": {
         "score_mode": "multiply",
         "rescore_query": {
            "bool": {
               "should": [
                  {
                     "match": {
                        "my_field1": {
                           "query": "apple*",
                           "boost": 2
                        }
                     }
                  }
               ]
            }
         },
         "query_weight": 0.7,
         "rescore_query_weight": 1.2
      }
   }
}'

它似乎可行,但我仍然不确定。这是正确的html" target="_blank">方法吗?

EDIT1:对于其他查询,一个匹配重新评分无法正常工作。


问题答案:

您唯一需要在分数上进行操作的地方是完全匹配,否则按词条位置的顺序将为您提供正确的顺序。让我们通过以下内容了解这一点:

首先创建一个映射,如下所示:

PUT test
{
  "mappings": {
    "_doc": {
      "properties": {
        "my_field1": {
          "type": "text",
          "analyzer": "whitespace",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

我已经创建了my_field1带有whitespace分析器的字段,以确保通过仅将空格用作定界符来创建令牌。其次,我创建了一个名为keywordtype
的子字段keywordkeyword将保存输入字符串的非分析值,我们将使用它进行精确匹配。

让我们向索引添加一些文档:

PUT test/_doc/1
{
  "my_field1": "apple"
}

PUT test/_doc/2
{
  "my_field1": "apple tree"
}

PUT test/_doc/3
{
  "my_field1": "green apple"
}

如果使用以下查询搜索术语apple,则文档的顺序将为2、1、3。

POST test/_doc/_search
{
  "explain": true,
  "query": {
    "query_string": {
      "query": "apple",
      "fields": [
        "my_field1"
      ]
    }
  }
}

"explain": true在上面的查询中,在输出中给出分数计算步骤。阅读本文将使您了解文档的评分方式。

我们需要做的就是提高得分以实现完全匹配。我们将对场进行精确匹配my_field1.keyword。您可能有一个问题,为什么不这样呢my_field1。这样做的原因是因为my_field1经过分析,当为3个文档的输入字符串生成令牌时,都会针对此字段存储一个令牌(术语)apple(以及其他术语(例如,tree对于doc
2和greendoc 3,如果存在其他术语))
。当我们在此字段上对术语进行完全匹配时,apple所有文档都会匹配,并且对每个文档的得分都会产生相似的影响,因此得分没有变化。由于只有一个文档具有applemy_field1.keyword该文档(文档1)相对的确切值,因此可以匹配精确查询,因此我们将对其进行增强。因此查询将是:

{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "apple",
            "fields": [
              "my_field1"
            ]
          }
        },
        {
          "query_string": {
            "query": "\"apple\"",
            "fields": [
              "my_field1.keyword^2"
            ]
          }
        }
      ]
    }
  }
}

以上查询的输出:

{
  "took": 9,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": 3,
    "max_score": 1.7260925,
    "hits": [
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "1",
        "_score": 1.7260925,
        "_source": {
          "my_field1": "apple"
        }
      },
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "2",
        "_score": 0.6931472,
        "_source": {
          "my_field1": "apple tree"
        }
      },
      {
        "_index": "test3",
        "_type": "_doc",
        "_id": "3",
        "_score": 0.2876821,
        "_source": {
          "my_field1": "green apple"
        }
      }
    ]
  }
}


 类似资料:
  • 问题内容: 我正在使用Elasticsearch,但有一段时间魔鬼般地要进行精确匹配。我已经尝试过match,query_string等的各种组合,但是我什么也没得到,或者得到了不好的结果。查询看起来像这样: 排序结果 我当然知道“狗”,“那只狗”和“狗”的得分相同,但是我需要弄清楚如何提高得分“狗”的精确匹配度。 我也试过 但这仍然给我 问题答案: 默认情况下,使用标准分析仪分析字段。如果您想检

  • 问题内容: 我对使用ngram的单词有部分匹配。如何修改映射以始终偏爱精确匹配而不是ngram令牌?我不想修改查询。一个搜索框将搜索多种类型,每种类型都有各自的字段。 例如,假设我正在搜索职位,一个人的标题为“现场工程师”,另一个人的标题为“引擎技术员”。如果用户搜索“引擎”,我希望ES将后者返回为更相关。 我几乎逐字使用此映射:例外:我使用的ngram的最小值为3,最大值为11,而不是边缘ngr

  • 问题内容: 我正在尝试将字段映射为nGram和“精确”匹配,并使精确匹配首先出现在搜索结果中。这是对类似问题的解答,但我正努力使其工作。 无论我为“精确”字段指定什么提升值,每次都会得到相同的结果顺序。这是我的字段映射的外观: 这就是查询的样子: 问题答案: multi_field映射是正确的,但是搜索查询需要像这样更改: 现在,结果将“精确”匹配考虑在内,并加总得分。

  • 问题内容: 我看过每一篇文章,发现可以执行精确匹配,不区分大小写的查询,但是在实现时,它们并不能满足我的要求。 在将此问题标记为重复之前,请阅读整篇文章。 给定一个用户名,我想查询我的Elasticsearch数据库以仅返回一个与该用户名完全匹配但不区分大小写的文档。 我尝试为属性指定分析器,并使用查询来实现此行为。虽然这解决了区分大小写的匹配问题,但在精确匹配时失败了。 我考虑使用规范化程序,但

  • 问题内容: 这是一个分为两个部分的问题。 我的文档如下所示: 我的第一个问题是如何检索“ title” 恰好是 “ No Title”的所有文档。我不希望出现标题为“此文档没有标题”的文档。 我的第二个问题是如何检索“ URL” 恰好 出现在一长串URL中的所有文档。 我正在使用pyelasticsearch,但是在curl中使用通用答案也可以。 问题答案: 如果您存储了源代码(这是默认设置),则

  • 问题内容: 目前,我正在执行搜索功能。可以说在我的数据库中,我有以下数据: 关键字1 关键字2 关键字3 关键的东西 钥匙 然后用户输入:“ Key”作为要搜索的关键字。这是我当前的查询: 基本上,我有2个问题: 如何按相似性排序(排序)。从上面的示例中,我希望“ Key”作为我的第一个结果。我当前的结果是:Keyword1,Keyword2,Keyword3,Keysomething和Key 我