日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理

發布時間:2024/9/3 编程问答 32 豆豆
生活随笔 收集整理的這篇文章主要介紹了 初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
簡介:命名有包含搜索關鍵詞的文檔,但結果卻沒有?存進去的文檔被分成哪些詞(term)了?自定義分詞規則,但感覺好麻煩呢,無從下手?

作者介紹

魏彬,普翔科技 CTO,開源軟件愛好者,中國第一位 Elastic 認證工程師,《Elastic日報》和 《ElasticTalk》社區項目發起人,被 elastic 中國公司授予 2019 年度合作伙伴架構師特別貢獻獎。對 Elasticsearch、Kibana、Beats、Logstash、Grafana 等開源軟件有豐富的實踐經驗,為零售、金融、保險、證券、科技等眾多行業的客戶提供過咨詢和培訓服務,幫助客戶在實際業務中找準開源軟件的定位,實現從 0 到 1 的落地、從 1 到 N 的拓展,產生實際的業務價值。

初次接觸 Elasticsearch 的同學經常會遇到分詞相關的難題,比如如下這些場景:

1、為什么命名有包含搜索關鍵詞的文檔,但結果里面就沒有相關文檔呢?
2、我存進去的文檔到底被分成哪些詞(term)了?
3、我得自定義分詞規則,但感覺好麻煩呢,無從下手

如果你遇到過類似的問題,希望本文可以解決你的疑惑。

一、上手

讓我們從一個實例出發,如下創建一個文檔:

PUT test/doc/1 {"msg":"Eating an apple a day keeps doctor away" }

然后我們做一個查詢,我們試圖通過搜索 eat這個關鍵詞來搜索這個文檔

POST test/_search {"query":{"match":{"msg":"eat"}} }

ES的返回結果為0。這不太對啊,我們用最基本的字符串查找也應該能匹配到上面新建的文檔才對啊!

各位不要急,我們先來看看什么是分詞。

二、 分詞

搜索引擎的核心是倒排索引(這里不展開講),而倒排索引的基礎就是分詞。所謂分詞可以簡單理解為將一個完整的句子切割為一個個單詞的過程。在 es 中單詞對應英文為 term。我們簡單看個例子:


ES 的倒排索引即是根據分詞后的單詞創建,即 我、愛、北京、天安門這4個單詞。這也意味著你在搜索的時候也只能搜索這4個單詞才能命中該文檔。

實際上 ES 的分詞不僅僅發生在文檔創建的時候,也發生在搜索的時候,如下圖所示:

讀時分詞發生在用戶查詢時,ES 會即時地對用戶輸入的關鍵詞進行分詞,分詞結果只存在內存中,當查詢結束時,分詞結果也會隨即消失。而寫時分詞發生在文檔寫入時,ES 會對文檔進行分詞后,將結果存入倒排索引,該部分最終會以文件的形式存儲于磁盤上,不會因查詢結束或者 ES 重啟而丟失。

ES 中處理分詞的部分被稱作分詞器,英文是Analyzer,它決定了分詞的規則。ES 自帶了很多默認的分詞器,比如Standard、 Keyword、Whitespace等等,默認是 Standard。當我們在讀時或者寫時分詞時可以指定要使用的分詞器。

三、寫時分詞結果

回到上手階段,我們來看下寫入的文檔最終分詞結果是什么。通過如下 api 可以查看:

POST test/_analyze {"field": "msg","text": "Eating an apple a day keeps doctor away" }

其中 test為索引名,_analyze 為查看分詞結果的 endpoint,請求體中 field 為要查看的字段名,text為具體值。該 api 的作用就是請告訴我在 test 索引使用 msg 字段存儲一段文本時,es 會如何分詞。

返回結果如下:

{"tokens": [{"token": "eating","start_offset": 0,"end_offset": 6,"type": "<ALPHANUM>","position": 0},{"token": "an","start_offset": 7,"end_offset": 9,"type": "<ALPHANUM>","position": 1},{"token": "apple","start_offset": 10,"end_offset": 15,"type": "<ALPHANUM>","position": 2},{"token": "a","start_offset": 16,"end_offset": 17,"type": "<ALPHANUM>","position": 3},{"token": "day","start_offset": 18,"end_offset": 21,"type": "<ALPHANUM>","position": 4},{"token": "keeps","start_offset": 22,"end_offset": 27,"type": "<ALPHANUM>","position": 5},{"token": "doctor","start_offset": 28,"end_offset": 34,"type": "<ALPHANUM>","position": 6},{"token": "away","start_offset": 35,"end_offset": 39,"type": "<ALPHANUM>","position": 7}] }

返回結果中的每一個 token即為分詞后的每一個單詞,我們可以看到這里是沒有 eat 這個單詞的,這也解釋了在上手中我們搜索 eat 沒有結果的情況。如果你去搜索 eating ,會有結果返回。

寫時分詞器需要在 mapping 中指定,而且一經指定就不能再修改,若要修改必須新建索引。如下所示我們新建一個名為ms_english 的字段,指定其分詞器為 english:

PUT test/_mapping/doc {"properties": {"msg_english":{"type":"text","analyzer": "english"}} }

四、讀時分詞結果

由于讀時分詞器默認與寫時分詞器默認保持一致,拿 上手 中的例子,你搜索 msg 字段,那么讀時分詞器為 Standard ,搜索 msg_english 時分詞器則為 english。這種默認設定也是非常容易理解的,讀寫采用一致的分詞器,才能盡最大可能保證分詞的結果是可以匹配的。

然后 ES 允許讀時分詞器單獨設置,如下所示:

POST test/_search{"query":{"match":{"msg":{"query": "eating","analyzer": "english"}}}}

如上 analyzer 字段即可以自定義讀時分詞器,一般來講不需要特別指定讀時分詞器。

如果不單獨設置分詞器,那么讀時分詞器的驗證方法與寫時一致;如果是自定義分詞器,那么可以使用如下的 api 來自行驗證結果。

POST _analyze{"text":"eating","analyzer":"english"}

返回結果如下:

{"tokens": [{"token": "eat","start_offset": 0,"end_offset": 6,"type": "<ALPHANUM>","position": 0}] }

由上可知 english分詞器會將 eating處理為 eat,大家可以再測試下默認的 standard分詞器,它沒有做任何處理。

五、解釋問題

現在我們再來看下 上手 中所遇問題的解決思路。

1、查看文檔寫時分詞結果
2、查看查詢關鍵詞的讀時分詞結果
3、匹對兩者是否有命中

我們簡單分析如下:

由上圖可以定位問題的原因了。

六、解決需求

由于 eating只是 eat的一個變形,我們依然希望輸入 eat時可以匹配包含 eating的文檔,那么該如何解決呢?

答案很簡單,既然原因是在分詞結果不匹配,那么我們就換一個分詞器唄~ 我們可以先試下 ES 自帶的 english分詞器,如下:

# 增加字段 msg_english,與 msg 做對比 PUT test/_mapping/doc {"properties": {"msg_english":{"type":"text","analyzer": "english"}} } # 寫入相同文檔 PUT test/doc/1 {"msg":"Eating an apple a day keeps doctor away","msg_english":"Eating an apple a day keeps doctor away" } # 搜索 msg_english 字段 POST test/_search {"query": {"match": {"msg_english": "eat"}} }

執行上面的內容,我們會發現結果有內容了,原因也很簡單,如下圖所示:

由上圖可見 english分詞器會將 eating分詞為 eat,此時我們搜索 eat或者 eating肯定都可以匹配對應的文檔了。至此,需求解決。

七、深入分析

最后我們來看下為什么english分詞器可以解決我們遇到的問題。一個分詞器由三部分組成:char filter、tokenizer 和 token filter。各部分的作用我們這里就不展開了,我們來看下 standard和english分詞器的區別。

從上圖可以看出,english分詞器在 Token Filter 中和 Standard不同,而發揮主要作用的就是 stemmer,感興趣的同學可以自行去看起它的作用。

八、自定義分詞

如果我們不使用 english分詞器,自定義一個分詞器來實現上述需求也是完全可行的,這里不詳細講解了,只給大家講一個快速驗證自定義分詞器效果的方法,如下:

POST _analyze {"char_filter": [], "tokenizer": "standard","filter": ["stop","lowercase","stemmer"],"text": "Eating an apple a day keeps doctor away" }

通過上面的 api 你可以快速驗證自己要定制的分詞器,當達到自己需求后,再將這一部分配置加入索引的配置。

至此,我們再看開篇的三個問題,相信你已經心里有答案了,趕緊上手去自行測試下吧!

聲明:本文由原文《掌握 analyze API,一舉搞定 Elasticsearch 分詞難題》作者“魏彬”授權轉載,對未經許可擅自使用者,保留追究其法律責任的權利。


【阿里云Elastic Stack】100%兼容開源ES,獨有9大能力,提供免費X-pack服務(單節點價值$6000)

相關活動


更多折扣活動,請訪問阿里云 Elasticsearch 官網

阿里云 Elasticsearch 商業通用版,1核2G ,SSD 20G首月免費
阿里云 Logstash 2核4G首月免費


原文鏈接:https://developer.aliyun.com/article/768351?

版權聲明:本文中所有內容均屬于阿里云開發者社區所有,任何媒體、網站或個人未經阿里云開發者社區協議授權不得轉載、鏈接、轉貼或以其他方式復制發布/發表。申請授權請郵件developerteam@list.alibaba-inc.com,已獲得阿里云開發者社區協議授權的媒體、網站,在轉載使用時必須注明"稿件來源:阿里云開發者社區,原文作者姓名",違者本社區將依法追究責任。 如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至:developer2020@service.aliyun.com 進行舉報,并提供相關證據,一經查實,本社區將立刻刪除涉嫌侵權內容。

總結

以上是生活随笔為你收集整理的初次使用 Elasticsearch 遇多种分词难题?那是你没掌握这些原理的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。