Elasticsearch能檢索出來,但不能正確高亮怎麼辦?

1、問題引出

微信羣裏的線上實戰問題:

諸位大哥,es中:

keyword類型的字段進行高亮查詢,值爲 123asd456,查詢 sd4,高亮結果是 em 123asd456 em

有沒有辦法只對我查詢的sd4高亮?

明明查詢id的一部分,卻高亮結果是整個id串,怎麼辦?

死磕Elasticsearch技術微信羣

2、一個Demo描述清楚問題

注:本文示例DSL在7.2版本運行ok,6.X之前早期版本可能需要微調。

PUT findex
{
  "mappings": {
    "properties": {
      "aname":{
        "type":"text"
      },
      "acode":{
        "type":"keyword"
      }
    }
  }
}

POST findex/_bulk
{"index":{"_id":1}}
{"acode":"160213.OF","aname":"X泰納斯達克100"}
{"index":{"_id":2}}
{"acode":"160218.OF","aname":"X泰國證房地產"}

POST findex/_search
{
  "highlight": {
    "fields": {
      "acode": {}
    }
  },
  "query": {
    "bool": {
      "should": [
        {
          "wildcard": {
            "acode": "*1602*"
          }
        }
      ]
    }
  }
}

高亮檢索結果,

  "highlight" : {
          "acode" : [
            "<em>160213.OF</em>"
          ]
        }

也就是說整個串都被高亮了,沒有達到預期。

實際需求:搜索1602,相關數據:160213.O、160218.OF都能召回,且僅高亮搜索字段1602

3、問題拆解

  • 檢索選型wildcard是爲了解決子串能匹配的問題,wildcard的實現類似mysql的“like”模糊匹配。

  • 傳統的text標準分詞器,包括中文分詞器ik、英文分詞器english、standard等都不能解決上述子串匹配問題。

而實際業務需求:

一方面:要求輸入子串召回全串;

另一方面:要求高亮檢索的子串。

只能更換一種分詞Ngram來實現了!

4、什麼是Ngram?

4.1 Ngram定義

Ngram是一種基於統計語言模型的算法。

Ngram基本思想:是將文本里面的內容按照字節進行大小爲N的滑動窗口操作,形成了長度是N的字節片段序列。每一個字節片段稱爲gram,對所有gram的出現頻度進行統計,並且按照事先設定好的閾值進行過濾,形成關鍵gram列表,也就是這個文本的向量特徵空間,列表中的每一種gram就是一個特徵向量維度。

該模型基於這樣一種假設,第N個詞的出現只與前面N-1個詞相關,而與其它任何詞都不相關,整句的概率就是各個詞出現概率的乘積。

這些概率可以通過直接從語料中統計N個詞同時出現的次數得到。常用的是二元的Bi-Gram(二元語法)和三元的Tri-Gram(三元語法)。

4.2 Ngram舉例

中文句子:“你今天吃飯了嗎”,它的Bi-Gram(二元語法)分詞結果爲:

你今
今天
天吃
吃飯
飯了
了嗎

4.3 Ngram 應用場景

  • 場景1:文本壓縮、檢查拼寫錯誤、加速字符串查找、文獻語種識別。

  • 場景2:自然語言處理自動化領域得到新的應用,如自動分類、自動索引、超鏈的自動生成、文獻檢索、無分隔符語言文本的切分等。

  • 場景3:自然語言的自動分類功能。對應到Elasticsearch檢索,應用場景就更加明確:無分隔符語言文本的切分分詞,提高檢索效率(相比:wildcard 查詢和正則查詢)。

5、實踐一把

PUT findex_ext
{
  "settings": {
    "index.max_ngram_diff": 10,
    "analysis": {
      "analyzer": {
        "my_analyzer": {
          "tokenizer": "my_tokenizer"
        }
      },
      "tokenizer": {
        "my_tokenizer": {
          "type": "ngram",
          "min_gram": 4,
          "max_gram": 10,
          "token_chars": [
            "letter",
            "digit"
          ]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "aname": {
        "type": "text"
      },
      "acode": {
        "type": "text",
        "analyzer": "my_analyzer",
        "fields": {
          "keyword": {
            "type": "keyword"
          }
        }
      }
    }
  }
}

POST findex_ext/_bulk
{"index":{"_id":1}}
{"acode":"160213.OF","aname":"X泰納斯達克100"}
{"index":{"_id":2}}
{"acode":"160218.OF","aname":"X泰國證房地產"}

# 查看分詞結果
POST findex_ext/_analyze
{
  "analyzer": "my_analyzer",
  "text":"160213.OF"
}

POST findex_ext/_search
{
  "highlight": {
    "fields": {
      "acode": {}
    }
  },
  "query": {
    "bool": {
      "should": [
        {
          "match_phrase": {
            "acode": {
              "query": "1602"
            }
          }
        }
      ]
    }
  }
}

注意:三個核心參數

  • min_gram:最小字符長度(切分),默認爲1

  • max_gram:最大字符長度(切分),默認爲2

  • token_chars:生成的分詞結果中包含的字符類型,默認是全部類型。如上的示例中代表:保留數字、字母。若上述示例中,只指定  "letter",則數字就會被過濾掉,分詞結果只剩下串中的字符如:"OF"。

返回結果截取片段如下:

    "highlight" : {
          "acode" : [
            "<em>1602</em>13.OF"
          ]
        }

已經能滿足檢索和高亮的雙重需求。

5、選型注意

  • Ngram的本質:用空間換時間。其能匹配的前提是寫入的時候已經按照:min_gram、max_gram切詞。

  • 數據量非常少且不要求子串高亮,可以考慮keyword。

  • 數據量大且要求子串高亮,推薦使用:Ngram分詞結合match或者match_phrase檢索實現。

  • 數據量大,切記不要使用wildcard前綴匹配!

    原因:帶有通配符的pattern構造出來的DFA(Deterministic Finite Automaton)可能會很複雜,開銷很大!甚至可能導致線上環境宕機。

    Wood大叔也 多次強調:wildcard query應杜絕使用通配符打頭,實在不得已要這麼做,就一定需要限制用戶輸入的字符串長度。

6、小結

爲討論解決線上問題,引申出Ngram的原理和使用邏輯,並指出了wildcard和Ngram的適用業務場景。希望對實戰中的你有所啓發和幫助!

你在業務中遇到子串匹配和高亮的情況嗎?你是如何分詞和檢索的?歡迎留言討論。

參考:

1、https://zhuanlan.zhihu.com/p/32829048

2、http://blog.sciencenet.cn/blog-713101-797384.html

3、https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-ngram-tokenizer.html

4、https://elasticsearch.cn/article/171


更多推薦:

1、Elasticsearch實戰|如何從數千萬手機號中識別出情侶號?

2、乾貨|Elasticsearch開發人員最佳實戰指南

3、95後運維小哥20天+通過Elastic認證考試經驗分享

4、潛心一技、做到極致!——Elastic認證工程師之路

5、“金三銀四“,敢不敢“試”?

中國通過Elastic認證工程師考試人數最多的圈子!

更短時間更快習得更多幹貨!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章