<>1、题记

题出有因:

有位医生朋友在QQ留言,说对于专业词汇,检索不到怎么办?
举例:搜索:痉湿暍病 结合了国内的多款分词插件,竟然搜索不到?

<>2、共性认知

<>2.1 为什么需要分词?

wildcard模糊匹配不也可以全字段模糊查询,进而得到结果呢?
但是,当文档结果集非常大,模糊匹配必然会有性能问题。
搜索引擎的为什么能快速检索到自己查询的关键字呢?倒排索引是以O(1)时间复杂度,一招解决问题的关键。
没有词语,怎么建立索引呢?于是,我们需要中文分词!
并且分词发生在用户查询和服务器建立索引时。

<>2.2 查全率 VS 查准率

查全率=(检索出的相关信息量/系统中的相关信息总量)*100%
查准率=(检索出的相关信息量/检索出的信息总量)*100%
前者是衡量检索系统和检索者检出相关信息的能力,后者是衡量检索系统和检索者拒绝非相关信息的能力。两者合起来,即表示检索效率。

#3、Elasticsearch 多种检索类型选型指南

<>3.1 match检索

含义:精细化切词匹配,只要待匹配的语句中,有一个满足检索结果,就能匹配到。
场景:结果可能达不到实际开发预期。实际业务中但凡有精准度要求的都较少或几乎不使用。
举例:
PUT doctor_index/_doc/4 { "content":"刘强东方才只是睡觉了,并没有违法" }
我输入检索词

“小王睡觉”

,也能匹配到上面的content。

<>3.2match_phrase:短语匹配

含义:相比match,更强调多个分词结果和顺序,都要完整匹配才能检索到。
场景:实战应用中会较多使用,结合slop调整顺序和精度。

<>3.3 query_string

含义:支持与(AND)、或(OR)、非(NOT)的匹配。
场景:有与或非多值匹配的场景,无需单独再开发,开箱即用。底层的关键词实际走的是match_phrase,
不过多个参数(如:default_operator,phrase_slop等)可控制调整精度。
举例:
GET /_search { "query": { "query_string" : { "default_field" : "content",
"query" : "刘强东 AND 无罪" } } }
<>4、为什么会检索不到?

结合几个典型例子,实践分析一把。

<>4.1 分词原因/词典未收录原因

举例:
PUT doctor_index/_doc/3 { "content":"佟大为老婆生了孩子" } POST doctor_index/_search {
"profile":"true", "query": { "match_phrase": { "content": "佟大" } } }
包含”佟大”,但是短语匹配搜索不到。
原因分析:
来看看切词,
GET /_analyze { "text":"佟大为老婆生了孩子", "analyzer": "ik_max_word" }
token start_offset end_offset position
佟大为 0 3 0
大为 1 3 1
大 1 2 2
为 2 3 3
老婆 3 5 4
老 3 4 5
婆 4 5 6
生了 5 7 7
生 5 6 8
了 6 7 9
孩子 7 9 10
搜索:佟大,如果执意也要搜出结果呢?

token start_offset end_offset position
佟 0 1 0
大 1 2 1
分析可知:佟大两个字组成的连词,没有作为词组分配的,所以匹配不到。

<>4.2 postition位置不一致。

假定我字典里面没有收录“刘强东”这个人名。
举例:
PUT doctor_index/_doc/4 { "content":"刘强东方才只是睡觉了,并没有违法" } POST
doctor_index/_search { "query": { "match_phrase": { "content": "刘强东" } } }
原因分析:

token position
刘强 0
东方 1
方才 2
方 3
才 4
只是 5
睡觉 6
睡 7
觉了 8
觉 9
了 10
并没有 11
并没 12
并 13
没有 14
有 15
违法 16
法 17
而刘强东的分词结果是:

token position
刘强 0
东 1
match_phrase匹配必须:position一致,可以上下对比一下,由于东方组成了短语,导致结果position不一致,匹配结果检索不到。

<>5、如何让存在的字符都能搜索到呢?

<>5.1 关于match_phrase的精确度问题

方案一:match_phrase_prefix结合slop的方案
参见:之前的方案 <https://blog.csdn.net/laoyang360/article/details/79249823>
但是,事后分析发现:slop设置不论多大、多小,都可能会引入噪音数据,导致结果不准确。

方案二:match_phrase结合match should关联匹配。
缺点:依然会引入噪音数据。

<>5.2 参考阿里云的实践思路,采取:逐个字分词和ik分词结合的方式。


单字分词应用场景——对于像姓名类字段,业务上需要支持完整匹配,又需要支持单字查询。可以配置1个keyword字段(不分词);1个text字段(分词),分词器选择Elasticsearch
默认分词器standard,按单个汉字切分。

<>5.3 实践一把

我们处理问题的前提:提升查全率。
PUT mix_index { "mappings": { "_doc": { "properties": { "content": { "type":
"text", "analyzer": "ik_max_word", "fields": { "standard": { "type": "text",
"analyzer": "standard" }, "keyword": { "type": "keyword", "ignore_above": 256 }
} } } } } } PUT mix_index/_doc/1 { "content":"佟大为老婆生了孩子" } POST
mix_index/_search { "query": { "bool": { "should": [ { "match_phrase": {
"content": "佟大" } }, { "match_phrase": { "content.standard": "佟大" } } ] } } }
<>6、小结

不是放之四海而皆准的实现方式。要看你的系统对查全率和查准率的要求了,正常的业务场景:

* 1)动态更新词库、词典;
* 2)match_phrase结合slop就能解决问题。
所以,一定要结合自己的业务场景。
相信这么处理,开头医生的需求也能实现了。

参考:
https://www.zhihu.com/question/19578687
<https://www.zhihu.com/question/19578687>
https://blog.csdn.net/renenglish/article/details/5847100
<https://blog.csdn.net/renenglish/article/details/5847100>
https://zhidao.baidu.com/question/451424472.html
<https://zhidao.baidu.com/question/451424472.html>
https://elasticsearch.cn/article/6171 <https://elasticsearch.cn/article/6171>
https://blog.csdn.net/haiyan0106/article/details/1758929
<https://blog.csdn.net/haiyan0106/article/details/1758929>


Elasticsearch基础、进阶、实战第一公众号

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:ixiaoyang8@qq.com
QQ群:637538335
关注微信