23

明明存在,怎么搜索不出来呢?

 5 years ago
source link: https://mp.weixin.qq.com/s/JF4COcd9Haj79RexCyEUAA?amp%3Butm_medium=referral
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

1、题记

题出有因:

有位医生朋友在QQ留言,说对于专业词汇,检索不到怎么办? 

举例:搜索:痉湿暍病 结合了国内的多款分词插件,竟然搜索不到?

2、共性认知

2.1 为什么需要分词?

wildcard模糊匹配不也可以全字段模糊查询,进而得到结果呢?
但是,当文档结果集非常大,模糊匹配必然会有性能问题。

搜索引擎的为什么能快速检索到自己查询的关键字呢?倒排索引是以 O(1) 时间复杂度,一招解决问题的关键。

没有词语,怎么建立索引呢?于是,我们需要中文分词!

并且分词发生在用户 查询 服务器建立索引 时。

2.2 查全率 VS 查准率

查全率 =(检索出的相关信息量/系统中的相关信息总量) 100% 

查准率 =(检索出的相关信息量/检索出的信息总量) 100% 

前者是衡量检索系统和检索者检出相关信息的能力,后者是衡量检索系统和检索者拒绝非相关信息的能力。两者合起来,即表示检索效率。

3、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、为什么会检索不到?

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

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

佟大为

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位置不一致。

假定我字典里面没有收录“刘强东”这个人名。
举例:

 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

刘强

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的方案

参见: 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}

6、小结

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

  • 1) 动态更新词库、词典

  • 2)match_phrase结合slop就能解决问题。

所以,一定要 结合自己的业务场景

相信这么处理,开头医生的需求也能实现了。

VZBneeI.jpg!web

加入知识星球,更短时间更快习得更多干货!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK