首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >精确匹配的正确排序和弹性搜索中的“开始”(前缀)

精确匹配的正确排序和弹性搜索中的“开始”(前缀)
EN

Stack Overflow用户
提问于 2019-02-05 10:54:23
回答 1查看 3.1K关注 0票数 5

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

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

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

如果我搜索“苹果”,它可能发生,我得到的结果如下:

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

但是我想要的是精确的匹配来获得最高的分数,这里是带有"apple“的文档。

接下来的最高分应该是以搜索词开头的条目,这里是“苹果树”和rest排序的默认方式。

所以我想要这个:

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

我试图通过使用rescore来实现这个目标:

代码语言:javascript
复制
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*“也会带来”绿色苹果“。这似乎就是rescore不适合我的原因。

可能还有其他字符,如点".“、"-”、“”、“”等等,这些字符是Elasticsearch用来分割和搞乱我的排序的。

我还在"rescore_query“中玩”rescore_query“而不是"bool",但没有成功。

我也试过只有一个匹配:

代码语言:javascript
复制
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
      }
   }
}'

看起来很管用,但我还是不确定。这是正确的方法吗?

EDIT1:对于其他查询,一个匹配的rescore不能正常工作。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2019-02-05 15:40:37

唯一需要在分数中进行操作的地方是精确匹配,否则按术语的位置排序就会给出正确的顺序。让我们通过以下几点来理解这一点:

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

代码语言:javascript
复制
PUT test
{
  "mappings": {
    "_doc": {
      "properties": {
        "my_field1": {
          "type": "text",
          "analyzer": "whitespace",
          "fields": {
            "keyword": {
              "type": "keyword"
            }
          }
        }
      }
    }
  }
}

我使用my_field1分析器创建字段whitespace,以确保只使用空格作为分隔符来创建令牌。其次,我创建了一个名为keywordkeyword类型的子字段。keyword将保存输入字符串的未分析值,我们将使用此值进行精确匹配。

让我们为索引添加几个文档:

代码语言:javascript
复制
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。

代码语言:javascript
复制
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用于Doc2,green用于Doc3)。当我们在这个字段上为术语apple运行完全匹配时,所有的文档都将匹配,并且对每个文档的得分有相似的影响,因此在分数上没有变化。由于只有一个文档具有精确的值作为applemy_field1.keyword的对应,所以该文档(doc 1)将与精确查询匹配,我们将对此进行改进。因此,查询将是:

代码语言:javascript
复制
{
  "query": {
    "bool": {
      "should": [
        {
          "query_string": {
            "query": "apple",
            "fields": [
              "my_field1"
            ]
          }
        },
        {
          "query_string": {
            "query": "\"apple\"",
            "fields": [
              "my_field1.keyword^2"
            ]
          }
        }
      ]
    }
  }
}

上面查询的输出:

代码语言:javascript
复制
{
  "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"
        }
      }
    ]
  }
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/54532813

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档