Elasticsearch 中文分詞器插件

ES 中默認的分詞器是 Standard Analyzer柠衅,會對文本內容按單詞分類并進行小寫處理烤黍,但是主要是用于處理英文的漠吻,對中文的分詞處理就非常不友好了赵誓。理解了分詞打毛,自己去做搜索的時候就會少一些為什么搜索的結果和預期不符的疑惑。

1俩功、為什么需要中文分詞器插件

先使用 Kibana 測試 ES 默認分詞器對英文的處理:

GET _analyze
{
  "text": "Hello World"
}

結果如下:


所以 ES 默認分詞器對英文的處理是符合預期的幻枉,同時大寫字母也被轉為小寫。

但是對中文的處理呢诡蜓?

GET _analyze
{
  "text": "你好世界"
}

很顯然無法對中文正確的分詞熬甫。那這樣又會導致什么問題呢?

我們先創(chuàng)建一個test索引蔓罚,并添加幾條文檔數(shù)據(jù):

PUT test

POST test/_doc
{
  "content": "Hello World"
}

POST test/_doc
{
  "content": "你好世界"
}

POST test/_doc
{
  "content": "好好學習"
}

操作完成后椿肩,可以在 head 工具中看到如下數(shù)據(jù):


我們先通過hello來查詢數(shù)據(jù):

GET test/_search
{
  "query": {
    "match": {
      "content": "hello"
    }
  }
}

查詢結果如下,可以得到預期的數(shù)據(jù):


再查詢你好試試:

GET test/_search
{
  "query": {
    "match": {
      "content": "你好"
    }
  }
}

結果如下豺谈,我們期望只查出你好世界郑象,但好好學習也被查出來了,原因是就查詢時你好被分詞成了茬末、兩個字厂榛,而不是一個完整的詞。由于我們沒有設置分詞器,使用的是默認的分詞器噪沙,所以在保存文檔數(shù)據(jù)時content字段的中文內容也會被分詞成單個字炼彪,并生成索引,查詢時會使用被分詞后的關鍵字去content生成的索引中匹配正歼,自然會匹配出多條文檔數(shù)據(jù):

所以問題很明顯了辐马,由于使用了 ES 默認的分詞器,導致查詢中文時不能按照我們的預期得到想要的結果局义,所以我們一般都會單獨安裝中文分詞器插件喜爷,ES 中使用比較多的中文分詞器插件是elasticsearch-analysis-ik,簡稱 IK 分詞器萄唇。

2檩帐、安裝 IK 分詞器

它的原碼托管在 GitHub 上,主頁地址 https://github.com/medcl/elasticsearch-analysis-ik另萤。需要注意的是湃密,不同版本的 IK 分詞器對應的 ES 版本是不同的 ,我們的 ES 使用的是7.9.3版本四敞,下載對應版本的 IK 分詞器即可泛源。安裝比較簡單可以參考如下步驟:

  • 在每個 ES 節(jié)點安裝目錄的 plugins 文件夾下創(chuàng)建名為 ik 的文件夾,并將下載好的分詞器壓縮包解壓到里邊
  • 重啟 ES 服務

IK 分詞器有如下兩種分詞模式:

  • ik_max_word忿危,會對文本做最細粒度的拆分达箍,盡可能拆分出多的詞。一個字段的值需要被全文檢索式铺厨,可以在創(chuàng)建索引時設置字段的分詞模式指定為ik_max_word缎玫,這樣字段內容會被最大化的分詞進而生成對應的索引,這樣對應的文檔能更準確的被檢索到解滓。
  • ik_smart赃磨,會對文本做最粗粒度的拆分,拆分出的詞相對會少些洼裤。一般檢索時可以設置關鍵字的分詞模式為ik_smart煞躬,這樣能更準確的檢索到預期的結果。

3逸邦、測試

首先我們測試使用 IK 分詞器后的分詞效果:

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "你好世界"
}

可以看到 IK 分詞器已經(jīng)可以按照我們的預期分詞了:


在測試查詢之前,我們先刪掉之前的test索引在扰,重新創(chuàng)建索引缕减,并指定字段索引時的分詞模式(analyzer),以及檢索式關鍵字的分詞模式(search_analyzer):

PUT test
{
  "mappings": {
    "properties": {
      "content":{
        "type": "text",
        "analyzer": "ik_max_word",
        "search_analyzer": "ik_smart"
      }
    }
  }
}

添加的數(shù)據(jù)和之前一樣芒珠,我們再嘗試查詢你好

GET test/_search
{
  "query": {
    "match": {
      "content": "你好"
    }
  }
}

結果符合預期:


3桥狡、自定義擴展字典

一些新的詞匯或者特殊詞匯,IK 分詞器可能并不會識別,還是會給我們拆分成單個字裹芝,例如這兩個詞唐家三少部逮、南派三叔,先測試下 IK 分詞器對唐家三少的分詞效果:

GET _analyze
{
  "analyzer": "ik_smart",
  "text": "唐家三少"
}

很顯然 IK 分詞器并不會把它當做一個完整詞去處理(南派三叔的情況也是類似的):

我們再給索引添加如下兩條數(shù)據(jù):

POST test/_doc
{
  "content": "唐家三少"
}

POST test/_doc
{
  "content": "南派三叔"
}

試著查詢一下唐家三少

GET test/_search
{
  "query": {
    "match": {
      "content": "唐家三少"
    }
  }
}

我們希望的是查詢唐家三少時嫂易,只查詢出唐家三少所在的文檔數(shù)據(jù)兄朋,讓 IK 分詞器把它當做一個詞去處理,而不是直接拆分成單個字怜械。我們可以自定義擴展字典來解決這個問題颅和。

3.1、本地字典

定義本地擴展字典的步驟如下:

  • 在分詞器插件目錄的 config 目錄下創(chuàng)建 my.dic 文件(文件名不做限制缕允,但后綴名必須是.dic)峡扩,然后添加要擴展的詞匯:

  • 定義好了擴展字典,接下來需要在分詞器插件目錄的 config 目錄下的configIKAnalyzer.cfg.xml 文件中配置定義的字典:

<properties>
    <comment>IK Analyzer 擴展配置</comment>
    <!--用戶可以在這里配置自己的擴展字典 -->
    <entry key="ext_dict">my.dic</entry>
     <!--用戶可以在這里配置自己的擴展停止詞字典-->
    <entry key="ext_stopwords"></entry>
    <!--用戶可以在這里配置遠程擴展字典 -->
    <!-- <entry key="remote_ext_dict">words_location</entry> -->
    <!--用戶可以在這里配置遠程擴展停止詞字典-->
    <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
  • 重啟 ES 服務
3.2障本、測試

完成了上述配置教届,我們再嘗試查詢唐家三少

GET test/_search
{
  "query": {
    "match": {
      "content": "唐家三少"
    }
  }
}

實現(xiàn)了我們預期的效果:


3.3、遠程字典

如果每次修擴展字典都要重啟 ES 服務也是挺麻煩的驾霜,我們可以通過定義遠程擴展字典來解決這個問題案训。

我們要做的就是提供一個接口,返回擴展字典文件即可寄悯。我們這里創(chuàng)建一個 Spring Boot 項目萤衰,將自定義的詞典放在靜態(tài)資源目錄即可:


這樣我們就可以通過接口 http://localhost:8080/my.dic 訪問到遠程字典,然后在 configIKAnalyzer.cfg.xml 中配置遠程擴展字典即可:

<properties>
    <comment>IK Analyzer 擴展配置</comment>
    <!--用戶可以在這里配置自己的擴展字典 -->
    <!--<entry key="ext_dict">my.dic</entry> -->
     <!--用戶可以在這里配置自己的擴展停止詞字典-->
    <entry key="ext_stopwords"></entry>
    <!--用戶可以在這里配置遠程擴展字典 -->
    <entry key="remote_ext_dict">http://localhost:8080/my.dic</entry> 
    <!--用戶可以在這里配置遠程擴展停止詞字典-->
    <!-- <entry key="remote_ext_stopwords">words_location</entry> -->
</properties>
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末猜旬,一起剝皮案震驚了整個濱河市脆栋,隨后出現(xiàn)的幾起案子萝毛,更是在濱河造成了極大的恐慌施掏,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件缀棍,死亡現(xiàn)場離奇詭異熟嫩,居然都是意外死亡秦踪,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進店門掸茅,熙熙樓的掌柜王于貴愁眉苦臉地迎上來椅邓,“玉大人,你說我怎么就攤上這事昧狮【澳伲” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵逗鸣,是天一觀的道長合住。 經(jīng)常有香客問我绰精,道長,這世上最難降的妖魔是什么透葛? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任笨使,我火速辦了婚禮,結果婚禮上僚害,老公的妹妹穿的比我還像新娘硫椰。我一直安慰自己,他們只是感情好贡珊,可當我...
    茶點故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布最爬。 她就那樣靜靜地躺著,像睡著了一般门岔。 火紅的嫁衣襯著肌膚如雪爱致。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天寒随,我揣著相機與錄音糠悯,去河邊找鬼。 笑死妻往,一個胖子當著我的面吹牛互艾,可吹牛的內容都是我干的。 我是一名探鬼主播讯泣,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼纫普,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了好渠?” 一聲冷哼從身側響起昨稼,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎拳锚,沒想到半個月后假栓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡霍掺,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年匾荆,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片杆烁。...
    茶點故事閱讀 38,789評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡牙丽,死狀恐怖,靈堂內的尸體忽然破棺而出兔魂,到底是詐尸還是另有隱情剩岳,我是刑警寧澤,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布入热,位于F島的核電站拍棕,受9級特大地震影響,放射性物質發(fā)生泄漏勺良。R本人自食惡果不足惜绰播,卻給世界環(huán)境...
    茶點故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望尚困。 院中可真熱鬧蠢箩,春花似錦、人聲如沸事甜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽逻谦。三九已至掌实,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邦马,已是汗流浹背贱鼻。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留滋将,地道東北人邻悬。 一個月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像随闽,于是被迫代替她去往敵國和親父丰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 43,697評論 2 351

推薦閱讀更多精彩內容