不为失败找理由,要为成功找方法。

如何将以关键字为开头的结果排在最前?

Elasticsearch | 作者 zhangdi | 发布于2021年02月23日 | 阅读数:228

案例:
现在有两条文档,id=1,id=2:
{
"id": 1,
"name": "营口中北工程有限公司"
}
{
"id": 2,
"name": "中北工程设计咨询有限公司"
}
使用ik中文分词,ik_max_word分词后:
id1的name分词结果为:

{
    "tokens": [
        {
            "token": "营口",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "口中",
            "start_offset": 1,
            "end_offset": 3,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "中北",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "工程",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "有限公司",
            "start_offset": 6,
            "end_offset": 10,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "有限",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 5
        },
        {
            "token": "公司",
            "start_offset": 8,
            "end_offset": 10,
            "type": "CN_WORD",
            "position": 6
        }
    ]
}
id=2的name分词结果为:

{
    "tokens": [
        {
            "token": "中北",
            "start_offset": 0,
            "end_offset": 2,
            "type": "CN_WORD",
            "position": 0
        },
        {
            "token": "工程设计",
            "start_offset": 2,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 1
        },
        {
            "token": "工程",
            "start_offset": 2,
            "end_offset": 4,
            "type": "CN_WORD",
            "position": 2
        },
        {
            "token": "设计",
            "start_offset": 4,
            "end_offset": 6,
            "type": "CN_WORD",
            "position": 3
        },
        {
            "token": "咨询",
            "start_offset": 6,
            "end_offset": 8,
            "type": "CN_WORD",
            "position": 4
        },
        {
            "token": "有限公司",
            "start_offset": 8,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 5
        },
        {
            "token": "有限",
            "start_offset": 8,
            "end_offset": 10,
            "type": "CN_WORD",
            "position": 6
        },
        {
            "token": "公司",
            "start_offset": 10,
            "end_offset": 12,
            "type": "CN_WORD",
            "position": 7
        }
    ]
}
现在用户搜索 “中北工程”,结果id1的评分比id2高,期望达到的结果是 以“中北工程”开头的排在最前。
尝试关闭词频统计和归一化都没啥效果,或者是我没用好。麻烦各位帮帮我,或者提供点思路。谢谢了!!难不成要通过机器人训练分词还是相关性?
已邀请:

God_lockin

赞同来自:

加上哥prefix或者match_phrase之类的should条件试试

zhangdi - d_vv

赞同来自:

版本是ES7.6

Morry

赞同来自:

prefix是针对term的prefix,所以要加个name.keyword子字段,然后再should prefix name.keyword。
 
另外,如果前缀加分是你业务场景下的固定逻辑,那应该直接在index前把前缀抽出来,es里加个额外字段 name_prefix,查询时直接加权,name_prefix^10,这样性能最好,而且这个字段是在外部直接抽出来的,不依赖于ik分词,流程上可控性更高

zhangdi - d_vv

赞同来自:

查询请求参数:
{
"query": {
"bool": {
"must": [
{
"match": {
"name": {
"query": "中北工程",
"boost": 0.1
}
}
}
],
"should": [
{
"prefix": {
"sname.keyword": {
"value": "中北工程",
"boost": 10
}
}
}
]
}
}
}
结果只返回了id2,而且should的分数没有被计算上。
 
setting和mapping
{
"settings": {
"analysis": {
"analyzer": {
"my_analyzer": {
"tokenizer": "my_tokenizer"
}
},
"tokenizer": {
"my_tokenizer": {
"type": "edge_ngram",
"min_gram": 2,
"max_gram": 20,
"token_chars": [
"letter",
"digit"
]
}
}
}
},
"mappings": {
"properties": {
"id": {
"type": "long"
},
"name": {
"type": "text",
"analyzer": "my_analyzer"
},
"sname": {
"type": "keyword"
}
}
}
}

weicai - 90后

赞同来自:

可以使用自定义相关性得分,这里使用的是脚本script_score这里的脚本,使用的是 java 函数,下面这个例子的算分,是根据匹配文档中中国的位置,逆序排列的,使用的是Math.pow(x,-1)函数,这样位置越靠前,对应的值越大。当然,你也可以位置*_score,等等方式。

排序:_score(中国人民)>_score(人民中国)
 
POST weibo/_search
{
"query": {
"function_score": {
"query": {
"match": {
"text": {
"query": "中北工程",
"operator": "and"
}
}
},
"script_score": {
"script": {
"source": "Math.pow(params['_source']['text'].indexOf('中北工程')+1, -1)"
}
},
"boost_mode": "replace"
}
}
}

zhangdi - d_vv

赞同来自:

是因为bm25得分不同导致的,
营口中北工程有限公司 和 中北工程设计咨询有限公司

tf, computed as freq / (freq + k1 * (1 - b + b * dl / avgdl)) from
只因为dl(长度)分数分别为 7 和 8 ,所以怎么计算怎么分词都是id1排名靠前。。。很头大
 

CurryQin

赞同来自:

可以加一个关键字keyword,如果keyword也包含搜索的关键字,该文档分数提高就好了

yanglz3

赞同来自:

试试重评分

zhangdi - d_vv

赞同来自:

不知道最佳方案是什么了。用function script可以满足需求,但是性能就不如意了。
其它的词,如:陕西公路XXX 也会被排在 陕西XXX公路XXXX 后面,真是奇怪

要回复问题请先登录注册