探究 | 明明存在,怎麼搜索不出來呢?

一、題記
題出有因:服務器

有位醫生朋友在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
佟大爲


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.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就能解決問題。

因此,必定要結合本身的業務場景。相信這麼處理,開頭醫生的需求也能實現了。

相關文章
相關標籤/搜索