一、题记
题出有因:服务器
有位医生朋友在QQ留言,说对于专业词汇,检索不到怎么办? app
举例:搜索:痉湿暍病 结合了国内的多款分词插件,居然搜索不到?ide
二、共性认知
2.1 为何须要分词?
wildcard模糊匹配不也能够全字段模糊查询,进而获得结果呢?
可是,当文档结果集很是大,模糊匹配必然会有性能问题。post
搜索引擎的为何能快速检索到本身查询的关键字呢?倒排索引是以O(1)时间复杂度,一招解决问题的关键。性能
没有词语,怎么创建索引呢?因而,咱们须要中文分词!搜索引擎
而且分词发生在用户查询和服务器创建索引时。阿里云
2.2 查全率 VS 查准率
查全率=(检索出的相关信息量/系统中的相关信息总量)100% 插件
查准率=(检索出的相关信息量/检索出的信息总量)100% 索引
前者是衡量检索系统和检索者检出相关信息的能力,后者是衡量检索系统和检索者拒绝非相关信息的能力。二者合起来,即表示检索效率。token
三、Elasticsearch 多种检索类型选型指南
3.1 match检索
含义:精细化切词匹配,只要待匹配的语句中,有一个知足检索结果,就能匹配到。
场景:结果可能达不到实际开发预期。实际业务中但凡是有精准度要求的都较少或几乎不使用。
举例:
1PUT doctor_index/_doc/4
2{
3 "content":"刘强东方才只是睡觉了,并无违法"
4}
我输入检索词
“小王睡觉”
,也能匹配到上面的content。
3.2match_phrase:短语匹配
含义:相比match,更强调多个分词结果和顺序,都要完整匹配才能检索到。
场景:实战应用中会较多使用,结合slop调整顺序和精度。
3.3 query_string
含义:支持与(AND)、或(OR)、非(NOT)的匹配。
场景:有与或非多值匹配的场景,无需单独再开发,开箱即用。底层的关键词实际走的是match_phrase,
不过多个参数(如:default_operator,phrase_slop等)可控制调整精度。
举例:
1GET /_search
2{
3 "query": {
4 "query_string" : {
5 "default_field" : "content",
6 "query" : "刘强东 AND 无罪"
7 }
8 }
9}
四、为何会检索不到?
结合几个典型例子,实践分析一把。
4.1 分词缘由/词典未收录缘由
举例:
1PUT doctor_index/_doc/3
2{
3 "content":"佟大为老婆生了孩子"
4}
5POST doctor_index/_search
6{
7"profile":"true",
8 "query": {
9 "match_phrase": {
10 "content": "佟大"
11 }
12 }
13}
包含”佟大”,可是短语匹配搜索不到。
缘由分析:
来看看切词,
1GET /_analyze
2{
3 "text":"佟大为老婆生了孩子",
4 "analyzer": "ik_max_word"
5}
token start_offset end_offset position
佟大为
3
大为
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
佟
1
大
1
2
1
分析可知:佟大两个字组成的连词,没有做为词组分配的,因此匹配不到。
4.2 postition位置不一致。
假定我字典里面没有收录“刘强东”这我的名。
举例:
1PUT doctor_index/_doc/4
2{
3 "content":"刘强东方才只是睡觉了,并无违法"
4}
5POST doctor_index/_search
6{
7 "query": {
8 "match_phrase": {
9 "content": "刘强东"
10 }
11 }
12}
缘由分析:
token position
刘强
东方
1
方才
2
方
3
才
4
只是
5
睡觉
6
睡
7
觉了
8
觉
9
了
10
并无
11
并没
12
并
13
没有
14
有
15
违法
16
法
17
而刘强东的分词结果是:
token position
刘强
东
1
match_phrase匹配必须:
position一致,能够上下对比一下,因为东方组成了短语,致使结果position不一致,匹配结果检索不到。
五、如何让存在的字符都能搜索到呢?
5.1 关于match_phrase的精确度问题
方案一:match_phrase_prefix结合slop的方案
参见:Elasticsearch实战 | match_phrase搜不出来,怎么办?
可是,过后分析发现:slop设置不论多大、多小,均可能会引入噪音数据,致使结果不许确。
方案二:match_phrase结合match should关联匹配。
缺点:依然会引入噪音数据。
5.2 参考阿里云的实践思路,采起:逐个字分词和ik分词结合的方式。
单字分词应用场景——对于像姓名类字段,业务上须要支持完整匹配,又须要支持单字查询。能够配置1个keyword字段(不分词);
1个text字段(分词),分词器选择Elasticsearch默认分词器standard,按单个汉字切分。
5.3 实践一把
咱们处理问题的前提:提高查全率。
1PUT mx_index
2{
3 "mappings": {
4 "_doc": {
5 "properties": {
6 "content": {
7 "type": "text",
8 "analyzer": "ik_max_word",
9 "fields": {
10 "standard": {
11 "type": "text",
12 "analyzer": "standard"
13 },
14 "keyword": {
15 "type": "keyword",
16 "ignore_above": 256
17 }
18 }
19 }
20 }
21 }
22 }
23}
24
25PUT mx_index/_doc/1
26{
27 "content":"佟大为老婆生了孩子"
28}
29
30POST mx_index/_search
31{
32 "query": {
33 "bool": {
34 "should": [
35 {
36 "match_phrase": {
37 "content": "佟大"
38 }
39 },
40 {
41 "match_phrase": {
42 "content.standard": "佟大"
43 }
44 }
45 ]
46 }
47 }
48}
六、小结
不是放之四海而皆准的实现方式。要看你的系统对查全率和查准率的要求了,正常的业务场景:
1)动态更新词库、词典;
2)match_phrase结合slop就能解决问题。
因此,必定要结合本身的业务场景。相信这么处理,开头医生的需求也能实现了。