gpt4 book ai didi

elasticsearch - Elasticsearch看似随机得分和匹配

转载 作者:行者123 更新时间:2023-12-02 23:35:43 26 4
gpt4 key购买 nike

我正在使用bool搜索来匹配多个字段。在索引时间使用多个过滤器对字段进行了分析,但主要使用edge_ngram

我遇到的问题是评分似乎悬而未决。我希望对savvas的搜索首先与first_nameSavvas字段之一匹配,但它们的得分要晚得多。例如,对savvas的搜索按得分顺序返回:

First name | Last name       | Email
___________|_________________|________________________
------ | Sav--- | ---@sa-------------.com
-----s | Sa---- | sa----------s@-----.com
Sa---- | ---- | sa---------@-------.com
Sa---- | -------- | sa-------@---------.com
sa- | ----- | sa----------@------.com
Sa-- | ----s-----s | sa------s-----s@---.com
Sa---- | ----------- | sa-----@-----------.com
Savvas | -------s | ----------@--------.com
Savvas | -------s | --------@----------.com
Sa- | ---s----S------ | sa------s-----@----.com

我用 -替换了字段中搜索词的边缘n-gram以外的其他字符,并修改了电子邮件的长度以保护身份。

实际上搜索 ssssssssssssssss(尽管我的数据中不存在)会返回其中 s字符数最多的项目。我没有为搜索做任何手动ngram,所以我不希望发生这种事情。

当我尝试搜索电话号码时,也会出现此问题,当通过 78作为精确ngram的电话号码搜索 782时,我匹配包含字符 782的所有电子邮件。

似乎elasticsearch也在对我的搜索查询执行ngram,而不仅仅是在字段上进行比较,并且将两者进行了比较,并以某种方式倾向于较短的匹配更大。

这是我的查询:
{
'bool': {
'should': [ // Any one of these matches will return a result
{
'match': {
'phone': {
'query': $searchString,
'fuzziness': '0',
'boost': 3 // If phone matches give it precedence
}
}
},
{
'match': {
'email': {
'query': $searchString,
'fuzziness': '0'
}
}
},
{
'multi_match': {
'query': $searchString,
'type': 'cross_fields', // Match if any term is in any of the fields
'fields': ['name.first_name', 'name.last_name'],
'fuzziness': '0'
}
}
],
'minimum_should_match': 1
}
}

以及与此相关的索引设置(为冗长而道歉,但我不想排除任何可能很重要的内容):
{
"settings":{
"analysis":{
"char_filter":{
"trim":{
"type":"pattern_replace",
"pattern":"^\\s*(.*)\\s*$",
"replacement":"$1"
},
"tel_strip_chars":{
"type":"pattern_replace",
"pattern":"^(\\(\\d+\\))|^(\\+)|\\D",
"replacement":"$1$2"
},
"tel_uk_exit_coded":{
"type":"pattern_replace",
"pattern":"^00(\\d+)",
"replacement":"+$1"
},
"tel_parenthesized_country_code":{
"type":"pattern_replace",
"pattern":"^\\((\\d+)\\)(\\d+)",
"replacement":"+$1$2"
}
},
"tokenizer":{
"intl_tel_country_code": {
"type":"pattern",
"pattern":"\\+(9[976]\\d|8[987530]\\d|6[987]\\d|5[90]\\d|42\\d|3[875]\\d|2[98654321]\\d|9[8543210]|8[6421]|6[6543210]|5[87654321]|4[987654310]|3[9643210]|2[70]|7|1)(\\d{1,14})$",
"group":0
}
},
"filter":{
"autocomplete":{
"type":"edge_ngram",
"min_gram":1,
"max_gram":50
},
"autocomplete_tel":{
"type":"ngram",
"min_gram":3,
"max_gram":20
},
"email":{
"type":"pattern_capture",
"preserve_original":1,
"patterns":[
"([^@]+)",
"(\\p{L}+)",
"(\\d+)",
"@(.+)",
"([^-@]+)"
]
}
},
"analyzer":{
"name":{
"type":"custom",
"tokenizer":"standard",
"filter":[
"trim",
"lowercase",
"asciifolding",
"autocomplete"
]
},
"email":{
"type":"custom",
"tokenizer":"uax_url_email",
"filter":[
"trim",
"lowercase",
"email",
"unique",
"autocomplete"
]
},
"phone":{
"type":"custom",
"tokenizer":"intl_tel_country_code",
"char_filter":[
"trim",
"tel_strip_chars",
"tel_uk_exit_coded",
"tel_parenthesized_country_code"
],
"filter":[
"autocomplete_tel"
]
}
}
}
},
"mappings":{
"person":{
"properties":{
"address":{
"properties":{
"country":{
"type":"string",
"index_name":"country"
}
}
},
"timezone":{
"type":"string"
},
"name":{
"properties":{
"first_name":{
"type":"string",
"analyzer":"name"
},
"last_name":{
"type":"string",
"analyzer":"name"
}
}
},
"email":{
"type":"string",
"analyzer":"email"
},
"phone":{
"type":"string",
"analyzer":"phone"
},
"id":{
"type":"string"
}
}
}
}
}

我已经使用Kopf插件的分析器测试了索引设置,它似乎可以创建正确的 token 。

理想情况下,我将只与索引创建的 token 完全匹配,并在我的bool应该查询中优先考虑更精确的匹配,而不是对多个bool应该匹配进行优先排序。

但是,如果它至少与确切的 token 匹配,我会很高兴。我不能使用 term搜索,因为我的搜索字符串本身需要被标记化,而无需对其应用任何ngram。

总结一下我的要求:
  • 在任何单个字段中按最大可能匹配数得分最高。
  • 然后在任何单个字段中按可能匹配的最低偏移量评分。
  • 然后按匹配的字段数评分,优先考虑较低的偏移量匹配

  • ---更新:---

    我使用 dis_max获得了更好的结果,除了 phone字段仍然难以查询之外,它似乎已成功地在多个ngram匹配项上成功匹配了更大的ngram匹配项。这是新的查询:
    {
    'dis_max': {
    'tie_breaker': 0.0,
    'boost': 1.5,
    'queries': [ // Any one of these matches will return a result
    [
    'match': {
    'phone': {
    'query': $searchString,
    'boost': 1.9
    }
    }
    ],
    [
    'match': {
    'email': {
    'query': $searchString
    }
    }
    ],
    [
    'multi_match': {
    'query': $searchString,
    'type': 'cross_fields', // Match if any term is in any of the fields
    'fields': ['name.first_name', 'name.last_name'],
    'tie_breaker': 0.1,
    'boost': 1.5
    }
    ]
    }
    }
    }

    最佳答案

    可能您不想在搜索字符串上使用自动完成功能(即名称分析器),仅在建立索引期间即映射应为:

    "first_name": {
    "type":"string",
    "index_analyzer":"name"
    }

    同样,要在多次比赛中对first_name高于last_name的比赛评分,您可以提供以下字段级别的提升:

    示例:last_name匹配项的相关性是first_name的一半
    {
    'dis_max': {
    'tie_breaker': 0.0,
    'boost': 1.5,
    'queries': [ // Any one of these matches will return a result
    [
    'match': {
    'phone': {
    'query': $searchString,
    'boost': 1.9
    }
    }
    ],
    [
    'match': {
    'email': {
    'query': $searchString
    }
    }
    ],
    [
    'multi_match': {
    'query': $searchString,
    'type': 'cross_fields', // Match if any term is in any of the fields
    'fields': ['name.first_name', 'name.last_name^0.5'],
    'tie_breaker': 0.1,
    'boost': 1.5
    }
    ]
    }
    }
    }

    关于elasticsearch - Elasticsearch看似随机得分和匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31606645/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com