1. 程式人生 > >Elasticsearch從入門到放棄:分詞器初印象

Elasticsearch從入門到放棄:分詞器初印象

Elasticsearch 系列回來了,先給因為這個系列關注我的同學說聲抱歉,拖了這麼久才回來,這個系列雖然叫「Elasticsearch 從入門到放棄」,但只有三篇就放棄還是有點過分的,所以還是回來繼續更新。 之前我們聊過了[ Elasticsearch 的索引](https://jackeyzhe.github.io/2019/10/13/Elasticsearch%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83%EF%BC%9A%E7%B4%A2%E5%BC%95%E5%9F%BA%E6%9C%AC%E4%BD%BF%E7%94%A8%E6%96%B9%E6%B3%95/)和[文件](https://jackeyzhe.github.io/2019/11/24/Elasticsearch%E4%BB%8E%E5%85%A5%E9%97%A8%E5%88%B0%E6%94%BE%E5%BC%83%EF%BC%9A%E6%96%87%E6%A1%A3CRUD%E8%A6%81%E7%89%A2%E8%AE%B0/),不太熟悉的話可以先翻閱一下前文。今天再一起聊一下 Elasticsearch 的分詞器。 ### 關於分詞 如果你是講 Elasticsearch 作為搜尋引擎,那麼你應該需要對分詞進行了解,Elasticsearch 的分詞是將全文字轉換為一系列單詞,這樣有助於在搜尋時得到相關的結果以及相關性分析。例如我們有一個文字為“I love Elasticsearch”,然後 Elasticsearch 可以將其分解為三個單詞,這時我們無論搜尋哪個單詞,都能搜到這個文字。 Elasticsearch 通過分詞器對文字進行分詞處理,Elasticsearch 的分詞器是由 Character Filters、Tokenizer 和Token Filter 三部分組成。在介紹它們之前,我們先來簡單瞭解一下 Analyze API,它可以幫助我們快速測試一個 Analyzer 的作用,它的用法也非常簡單: ``` shell GET /_analyze { "analyzer" : "standard", "text" : "Quick Brown Foxes!" } ``` 其中,analyzer 是指定的分詞器,text 是被測試的文字,這樣就能得到這個文字分詞後的效果。 這是最簡單的一種用法,此外,我們還可以在 path 中指定 index,用於測試指定索引中 mapping 設定的 analyzer 或者索引預設的 analyzer。當然,你也可以測試一下自定義的 analyzer,只需要在引數中設定好 Character Filters、Tokenizer 和Token Filter 即可。關於 Analyze API 更多的使用方法可以自行查閱官方文件[ Analyze API](https://www.elastic.co/guide/en/elasticsearch/reference/current/indices-analyze.html) ### 內建 Analyzer 為了方便使用,Elasticsearch 為我們提供了幾種內建 Analyzer: - Fingerprint:它可以將文字處理為小寫的、去除擴充套件的、有序的、唯一的單詞 - Keyword:不分詞 - Language:提供了30多種常見語言的分詞器 - Pattern:使用正則表示式分詞,預設\W+(非字元分隔) - Simple:按照非字母切分,小寫處理 - Standard:預設分詞器,會基於 Unicode 文字語法,按照單詞劃分,並進行小寫處理 - Stop:小寫處理,過濾停用詞(the, a, is) - Whitespace:按照空格切分,不轉小寫 現在我們來測試一下 Whitespace Analyzer ``` shell GET _analyze { "analyzer": "whitespace", "text": "The 2 QUICK Brown-Foxes jumped over the lazy dog's bone." } ``` 它的執行結果是 ``` json { "tokens" : [ { "token" : "The", "start_offset" : 0, "end_offset" : 3, "type" : "word", "position" : 0 }, { "token" : "2", "start_offset" : 4, "end_offset" : 5, "type" : "word", "position" : 1 }, { "token" : "QUICK", "start_offset" : 6, "end_offset" : 11, "type" : "word", "position" : 2 }, { "token" : "Brown-Foxes", "start_offset" : 12, "end_offset" : 23, "type" : "word", "position" : 3 }, { "token" : "jumped", "start_offset" : 24, "end_offset" : 30, "type" : "word", "position" : 4 }, { "token" : "over", "start_offset" : 31, "end_offset" : 35, "type" : "word", "position" : 5 }, { "token" : "the", "start_offset" : 36, "end_offset" : 39, "type" : "word", "position" : 6 }, { "token" : "lazy", "start_offset" : 40, "end_offset" : 44, "type" : "word", "position" : 7 }, { "token" : "dog's", "start_offset" : 45, "end_offset" : 50, "type" : "word", "position" : 8 }, { "token" : "bone.", "start_offset" : 51, "end_offset" : 56, "type" : "word", "position" : 9 } ] } ``` 如果有興趣,可以自行測試一下其他的內建 Analyzer。除了內建的 Analyzer 之外,你也可以根據需要自定義分詞器。 下面我們來看怎麼定義我們需要的 Analyzer。 前面提到 Analyzer 由三部分組成,其中 Character Filters 用於對原始文字進行處理(例如去掉html標籤),Tokenizer 是按照指定規則進行切分,Token Filter 負責將切分的單詞進行加工(例如轉小寫)。 ### Character Filters Character Filters 是分詞的第一步,Elasticsearch 用它來對原始文字進行一些處理。內建的 Character Filters 有三個,分別是: - HTML strip:使用解碼值替換HTML標籤 - Mapping:使用指定的替換項替換指定的字串 - Pattern replace:使用指定的替換項替換正則匹配的字串 HTML strip 預設會替換文字中所有的 HTML 標籤,你也可以通過設定**escaped_tags**,將一些特定的標籤排除 ``` shell PUT my_index { "settings": { "analysis": { "analyzer": { "my_analyzer": { "tokenizer": "keyword", "char_filter": [ "my_custom_html_strip_char_filter" ] } }, "char_filter": { "my_custom_html_strip_char_filter": { "type": "html_strip", "escaped_tags": [ "b" ] } } } } } ``` 這個自定義 Analyzer 就不會替換標籤 b。 ![](https://res.cloudinary.com/dxydgihag/image/upload/v1593363494/Blog/ES/04/es4-1.png) ### Tokenizer 在對原始文字進行初步的處理之後,Tokenizer 就要上場了,它幫助我們根據指定的規則進行分詞,Elasticsearch 同樣提供了一些內建的 Tokenizer。 - Character group:按照配置的字元組進行切分 - Classic:針對英語語法進行分詞 - Edge n-gram:從單詞的起始字元開始按長度依次切分quick 會被分為[q, qu, qui, quic, quick] - Keyword:不切分 - Letter:遇到非字母的字元進行切分 - Lowercase:與類似 Letter 類似,不過它會把切分後的單詞轉為小寫 - N-gram:把單詞切分為指定長度的字串集合,quick 會被分為[qu, ui, ic, ck] - Path hierarchy:對路徑進行切分,/foo/bar/baz 會分為[/foo, /foo/bar, /foo/bar/baz] - Pattern:根據正則匹配進行切分 - Simple pattern:正則會受到一些限制,但不支援按照匹配到的分割符切分 - Simple pattern split:是支援按照匹配到的分割符切分的Simple pattern - Standard:按照單詞進行切分 - Thai:針對泰語進行切分 - UAX URL email:與 Standard 相似,但它會把 url 或郵箱當作一個整體 - Whitespace:按照空格進行切分 在這裡你可以先對這些內建的 Tokenizer 有個初步的瞭解,知道它們能幹什麼,在具體使用的時候可以查閱官方文件進行更詳細的瞭解,很多 Tokenizer 還支援一些引數配置,這些到實際場景中靈活使用就好。 ### Token Filter Elasticsearch 內建的 Token Filter 非常多,這裡列幾個常用的吧: - Trim:刪除前後空格 - Uppercase:轉大寫 - Lowercase:轉小寫 - Stop:停用詞過濾 - …… Elasticsearch 中內建的這些分詞器及元件可以滿足我們日常的大部分需求了,能夠做到靈活應用就很厲害了。如果真的遇到解決不了的問題,你也可以嘗試自定義分詞器,例如對我們的中文進行分詞。 ### 中文分詞 中文分詞的難點在於,它不像英文那樣有天然的空格可以進行切分,我們也不能簡單的把它分成一個個的字,而是要分成有意義的詞。 比較不錯的中文分詞器有 ICU Analyzer、IK 和 THULAC #### ICU Analyzer ICU Analyzer 並不是 Elasticsearch 內建的分詞器,所以我們需要預先安裝外掛才能使用 執行命令 ``` shell elasticsearch-plugin install analysis-icu ``` 進行安裝,安裝好以後可以使用命令``` elasticsearch-plugin list ```進行檢視。 安裝好之後就可以執行下面這個例子 ``` shell GET _analyze { "analyzer": "standard", "text": "覺得好看就點贊" } GET _analyze { "analyzer": "icu_analyzer", "text": "覺得好看就點贊" } ``` 你會發現 standard analyzer 就是把這句話拆成一個個字,而 icu analyzer 基本會根據語義進行拆分。 ### 總結 經過本文的介紹,相信你對 Elasticsearch 的分詞器也有了一個初步的認識,知道它由什麼組成,能夠使用 Analyze API 對一個分詞器進行簡單的測試,也基本能夠自定義一些分詞器了。 我對內建的 Token Filter 介紹的比較少,你可以結合官方文件,對你感興趣的 Token Filter 進行更深入的研究,如果有什麼問題也歡迎和我