天天看點

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

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/6171

https://blog.csdn.net/haiyan0106/article/details/1758929

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

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

繼續閱讀