【问题标题】:Elasticsearch - search wildcards (contains in strings) and tf-idf scoresElasticsearch - 搜索通配符(包含在字符串中)和 tf-idf 分数
【发布时间】:2020-10-11 02:06:17
【问题描述】:

如何制作搜索通配符和 tf-idf 分数。 例如当我这样搜索时,

GET /test_es/_search?explain=true // return idf / dt scores
{
  "explain":true,
  "query": {
    "query_string": {
      "query": "bar^5",
      "fields"  : ["field"]
    }
  }
}

它返回 idf 和 td 分数, 但是当我使用通配符(包含)进行搜索时。

GET /test_es/_search?explain=true  // NOT RETURN idf/td score
{
   "explain":true,
  "query": {
    "query_string": {
      "query": "b*",
      "fields"  : ["field"]
    }
  }
}

如何使用通配符进行搜索(在字符串中使用 contains)并包含 IDF-TD 分数?

例如,我有 3 个文档 “foo”、“foo bar”、“foo baz” 当我这样搜索时

GET /foo2/_search?explain=true
{
   "explain":true,
  "query": {
    "query_string": {
      "query": "fo *",
      "fields"  : ["field"]
    }
  }
}

弹性搜索结果

    "hits" : [
  {
    "_shard" : "[foo2][0]",
    "_node" : "z8bjI0T1T8Oq6Z2OwFyIKw",
    "_index" : "foo2",
    "_type" : "_doc",
    "_id" : "3",
    "_score" : 1.0,
    "_source" : {
      "field" : "foo bar"
    },
    "_explanation" : {
      "value" : 1.0,
      "description" : "sum of:",
      "details" : [
        {
          "value" : 1.0,
          "description" : "*:*",
          "details" : [ ]
        }
      ]
    }
  },
  {
    "_shard" : "[foo2][0]",
    "_node" : "z8bjI0T1T8Oq6Z2OwFyIKw",
    "_index" : "foo2",
    "_type" : "_doc",
    "_id" : "2",
    "_score" : 1.0,
    "_source" : {
      "field" : "foo"
    },
    "_explanation" : {
      "value" : 1.0,
      "description" : "sum of:",
      "details" : [
        {
          "value" : 1.0,
          "description" : "*:*",
          "details" : [ ]
        }
      ]
    }
  },
  {
    "_shard" : "[foo2][0]",
    "_node" : "z8bjI0T1T8Oq6Z2OwFyIKw",
    "_index" : "foo2",
    "_type" : "_doc",
    "_id" : "1",
    "_score" : 1.0,
    "_source" : {
      "field" : "foo baz"
    },
    "_explanation" : {
      "value" : 1.0,
      "description" : "sum of:",
      "details" : [
        {
          "value" : 1.0,
          "description" : "*:*",
          "details" : [ ]
        }
      ]
    }
  }
]

但我认为“foo”应该是第一个得分最高的结果,因为它匹配 %100,我错了吗?

【问题讨论】:

  • 令人困惑。您希望idf-td 出现在结果中还是希望获得特定的分数?

标签: elasticsearch wildcard tf-idf elasticsearch-query


【解决方案1】:

由于您没有提及任何有关您获取的数据的信息,因此我对以下数据进行了索引:

索引数据:

{
    "message": "A fox is a wild animal."
}
{
    "message": "That fox must have killed the hen."
}
{
    "message": "the quick brown fox jumps over the lazy dog"
}

搜索查询:

GET/{{index-name}}/_search?explain=true 

{
  "query": {
    "query_string": {
      "fields": [
        "message"                       ---> You can add more fields here
      ],
      "query": "quick^2 fox*"
    }
  }
}

上面的查询搜索所有包含fox的文档,但是这里由于boost应用于quick,所以包含quick fox的文档与其他文档相比得分会更高.

此查询将返回 tf-IDF 分数。 boost 运算符用于使一个术语比另一个术语更相关。

要了解更多信息,请参阅"Boosting" in dsl-query-string上的官方文档

想了解更多关于tf-IDF算法的信息可以参考这个blog

如果要跨多个领域进行搜索,可以提升某个领域的分数

请参阅thisthis 了解更多信息。

更新 1:

索引数据:

{
  "title": "foo bar"
}
{
  "title": "foo baz"
}
{
  "title": "foo"
}

搜索查询:

{
  "query": {
    "query_string": {
      "query": "foo *"         --> You can just add a space between 
                                   foo and *
     }
  }
}

搜索结果:

"hits": [
         {
            "_index": "foo2",
            "_type": "_doc",
            "_id": "1",
            "_score": 1.9808292,       --> foo matches exactly, so the 
                                           score is maximum
            "_source": {
               "title": "foo"
            }
         },
         {
            "_index": "foo2",
            "_type": "_doc",
            "_id": "2",
            "_score": 1.1234324,
            "_source": {
               "title": "foo bar"
            }
         },
         {
            "_index": "foo2",
            "_type": "_doc",
            "_id": "3",
            "_score": 1.1234324,
            "_source": {
               "title": "foo baz"
            }
         }
      ]

【讨论】:

  • @你有没有机会仔细阅读我的回答,期待得到你的反馈,如果有帮助,请不要忘记点赞并接受:)
  • 感谢您的回复,但可能我无法清楚地解释我的问题,例如,当我像这样搜索“foo”时,我有 3 个文档“foo”“foo bar”“foo baz” *”它给了我类似“foo baz”、“foo”、“foo bar”的结果,其中三个分数相同,但我希望“foo”文档应该是第一个结果,因为它匹配 %100。跨度>
  • @y 请仔细阅读我的更新答案,如果这是您的问题,请告诉我
  • 谢谢,如果我搜索“foo *”是正确的,但如果我搜索“fo *”,我仍然希望“foo”应该是第一个结果,我错了吗? ,elasticsearch再次返回“foo bar”第一个结果
  • 如果我搜索“fo *”,我仍然希望“foo”应该是第一个结果,因为匹配百分比高于其他结果
【解决方案2】:

更新 2:

通配符查询基本上属于术语级查询,并且通过 默认使用 constant_score_boolean 方法来匹配术语。

通过更改rewrite parameter 的值,您可以影响搜索性能和相关性。它有多种评分选项,您可以根据需要选择其中任何一种。

但是根据你的用例,你也可以使用 edge_ngram 过滤器。 Edge N-Grams 对于搜索即键入查询很有用。想了解更多关于这个和下面使用的映射请参考这个官方documentation

索引映射:

{
  "settings": {
    "analysis": {
      "analyzer": {
        "autocomplete": {
          "tokenizer": "autocomplete",
          "filter": [
            "lowercase"
          ]
        },
        "autocomplete_search": {
          "tokenizer": "lowercase"
        }
      },
      "tokenizer": {
        "autocomplete": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 10,
          "token_chars": [
            "letter"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "autocomplete",
        "search_analyzer": "autocomplete_search"
      }
    }
  }
}

索引样本数据:

{ "title":"foo" }
{ "title":"foo bar" }
{ "title":"foo baz" }

搜索查询:

{
  "query": {
    "match": {
      "title": {
        "query": "fo"
      }
    }
  }
}

搜索结果:

"hits": [
            {
                "_index": "foo6",
                "_type": "_doc",
                "_id": "1",
                "_score": 0.15965709,        --> Maximum score
                "_source": {
                    "title": "foo"
                }
            },
            {
                "_index": "foo6",
                "_type": "_doc",
                "_id": "2",
                "_score": 0.12343237,
                "_source": {
                    "title": "foo bar"
                }
            },
            {
                "_index": "foo6",
                "_type": "_doc",
                "_id": "3",
                "_score": 0.12343237,
                "_source": {
                    "title": "foo baz"
                }
            }
        ]

要了解更多关于在 Elasticsearch 中使用 Ngram 的基础知识,您可以参考this

【讨论】:

  • @y 请仔细阅读我的更新答案,如果这是您的问题,请告诉我
  • @e y 谢谢你接受这个答案,如果你也能投票给答案就好了:)
猜你喜欢
  • 2018-08-08
  • 2021-07-09
  • 2021-06-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-15
  • 2015-03-15
  • 1970-01-01
相关资源
最近更新 更多