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 |
---|---|---|---|
佟大為 | 1 | 3 | |
大為 | |||
大 | 2 | ||
為 | |||
老婆 | 5 | 4 | |
老 | |||
婆 | 6 | ||
生了 | 7 | ||
生 | 8 | ||
了 | 9 | ||
孩子 | 10 |
搜尋:佟大,如果執意也要搜出結果呢?
佟 | |||
分析可知:佟大兩個字組成的連詞,沒有作為詞組配置設定的,是以比對不到。
4.2 postition位置不一緻。
假定我字典裡面沒有收錄“劉強東”這個人名。
PUT doctor_index/_doc/4
{
"content":"劉強東方才隻是睡覺了,并沒有違法"
}
POST doctor_index/_search
{
"query": {
"match_phrase": {
"content": "劉強東"
}
}
}
劉強 | |
東方 | |
方才 | |
方 | |
才 | |
隻是 | |
睡覺 | |
睡 | |
覺了 | |
覺 | |
并沒有 | 11 |
并沒 | 12 |
并 | 13 |
沒有 | 14 |
有 | 15 |
違法 | 16 |
法 | 17 |
而劉強東的分詞結果是:
東 |
match_phrase比對必須:position一緻,可以上下對比一下,由于東方組成了短語,導緻結果position不一緻,比對結果檢索不到。
5、如何讓存在的字元都能搜尋到呢?
5.1 關于match_phrase的精确度問題
方案一:match_phrase_prefix結合slop的方案
參見:之前的方案
但是,事後分析發現: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://blog.csdn.net/renenglish/article/details/5847100 https://zhidao.baidu.com/question/451424472.html https://elasticsearch.cn/article/6171https://blog.csdn.net/haiyan0106/article/details/1758929

Elasticsearch基礎、進階、實戰第一公衆号