本篇主要講解倒排索引的基本原理以及ES經常使用的幾種分詞器介紹。java
倒排索引是搜索引擎中常見的索引方法,用來存儲在全文搜索下某個單詞在一個文檔中存儲位置的映射。經過倒排索引,咱們輸入一個關鍵詞,能夠很是快地獲取包含這個關鍵詞的文檔列表。node
咱們先看英文的,假設咱們有兩個文檔:git
爲了創建倒排索引,咱們先按最簡單的用空格把每一個單詞分開,能夠獲得以下結果:
*表示該列文檔中有這個詞條,爲空表示沒有該詞條github
Term | doc1 | doc2 |
---|---|---|
I | * | * |
have | * | |
a | * | |
friend | * | |
who | * | |
loves | * | |
smile | * | |
love | * | |
me | * | |
you | * |
若是咱們要搜索 I love you,咱們只須要查找包含每一個詞條的文檔:架構
Term | doc1 | doc2 |
---|---|---|
I | * | * |
love | * | |
you | * |
兩個文檔都能匹配上,若是按命中詞條數量來算,doc2比doc1更匹配。併發
這個是倒排索引最簡化的表達方式,在ES的倒排索引存儲結果中,還會記錄每一個詞條在文檔中出現的位置。elasticsearch
咱們再看一下這個索引的創建過程,loves和love有區別嗎?沒有,都是愛的意思,一個是第三人稱單數,一個是原形。若是能將一些語法的區別處理掉,這樣的搜索結果是否是更切合實際需求?
例如:分佈式
如今索引看上去成這樣:高併發
Term | doc1 | doc2 |
---|---|---|
friend | * | |
love | * | * |
smile | * | |
me | * | |
you | * |
這樣是否是精簡了不少?
這個過程叫normalization,在創建倒排索引的時候,會執行一系列的操做,對拆分出的各個單詞進行相應的處理,以提高後面搜索的時候可以搜索到相關聯的文檔的機率,如時態的轉換,單複數的轉換,同義詞的轉換,大小寫的轉換等。學習
分詞器的做用就是把整篇文檔,按必定的語義切分紅一個一個的詞條,目標是提高文檔的召回率,並下降無效數據的噪音。
recall召回率,也叫可搜索性,指搜索的時候,增長可以搜索到的結果的數量。
降噪:指下降文檔中一些低相關性詞條對總體搜索排序結果的干擾。
文檔的分詞過程包含如下幾步:
對字符串進行預處理,如HTML標籤清洗<span>Love</span> --> Love,I & you --> I and you等等。
把字符串切分紅單個的詞條,如英文的按空格和標點切分,中文的按詞語切分,針對不一樣的語言,有不一樣的分詞器,有相對簡單的標準分詞器,也有特別複雜的中文分詞器,裏面包含了很是複雜的切分邏輯如:
I Love you --> I/Love/you
我和個人祖國 --> 我/和/個人/祖國
將分詞器獲得的詞條進一步的處理,如改變詞條(英文詞幹提取loves --> love),刪除無實際意義的詞條(英文的a, and, this,中文的"的","了","嗎"),增長詞條(補充同義詞)
分詞器很是重要,好的分詞器能夠顯著提高召回率,不恰當的分詞器獲得的結果可能會對搜索產生歧義,最後處理好的結果再拿去創建倒排索引。
Elasticsearch自身提供了內置的分詞器,也容許使用第三方的分詞器。
ES默認分詞器,根據Unicode聯盟定義的單詞邊界劃分文本,刪除絕大部分標點,最後將詞條小寫。
在任何不是字母的地方分隔文本,將詞條小寫
在空格的地方劃分文本
特定的語言的分詞器,如english,英語分詞器,維護了一組英語停用詞and、the之類的,用於刪除詞條,針對英文語法規則,有提取單詞詞幹的能力。
內置的分詞器主要是對英文的支持效果比較好,中文則須要使用外部的分詞器。
會將文本作最細粒度的拆分;儘量多的拆分出詞語。
如南京市長江大橋 --> 南京市/南京/市長/長江大橋/長江/大橋
會作最粗粒度的拆分;已被分出的詞語將不會再次被其它詞語佔有
如南京市長江大橋 --> 南京市/長江大橋
支持亞洲語言中文,日文,韓文
如南京市長江大橋 --> 南京/京市/市長/長江/江大/大橋
阿里自研的中文分詞器
如南京市長江大橋 --> 南京/市/長江/大橋
外部分詞器衆多,開源也有不少,有針對不一樣語言,不一樣領域的,各位能夠結合自身業務的特色,挑選適合本身的分詞器,這裏就不一一介紹了,有興趣本身能夠去了解一下。
以Elasticsearch 6.3.1版本爲例,集成IK分詞器,其餘的分詞器過程也相似,在ES的bin目錄下執行插件安裝命令便可:./elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.3.1/elasticsearch-analysis-ik-6.3.1.zip
其中install後面的那個的地址是 elasticsearch-analysis-ik 的github release對應ES版本的下載地址。
安裝成功後,ES啓動日誌就能看到以下信息:[2019-11-27T12:17:15,255][INFO ][o.e.p.PluginsService] [node-1] loaded plugin [analysis-ik]
ES有analyze API來查看文本是如何被分詞的,可用來作學習和調試用,請求命令以下:
GET /_analyze { "analyzer": "ik_max_word", "text": "南京市長江大橋" }
響應結果:
{ "tokens": [ { "token": "南京市", "start_offset": 0, "end_offset": 3, "type": "CN_WORD", "position": 0 }, { "token": "南京", "start_offset": 0, "end_offset": 2, "type": "CN_WORD", "position": 1 }, { "token": "市長", "start_offset": 2, "end_offset": 4, "type": "CN_WORD", "position": 2 }, { "token": "長江大橋", "start_offset": 3, "end_offset": 7, "type": "CN_WORD", "position": 3 }, { "token": "長江", "start_offset": 3, "end_offset": 5, "type": "CN_WORD", "position": 4 }, { "token": "大橋", "start_offset": 5, "end_offset": 7, "type": "CN_WORD", "position": 5 } ] }
本篇主要介紹了倒排索引的基本思路,展現了簡化後的結構,並闡述了分詞處理的基本步驟。目前市面上流行的分詞器組件特別多,開源的社區也很是活躍,各位可根據實際的項目需求背景,挑選適合的進行集成 ,注意版本號的兼容性問題便可。
專一Java高併發、分佈式架構,更多技術乾貨分享與心得,請關注公衆號:Java架構社區