大家好,我是Edison。
上一篇:ES文檔的CRUD操作
重要概念1:倒排索引
在學習ES時,倒排索引是一個非常重要的概念。要了解倒排索引,就得先知道什麼是正排索引。舉個簡單的例子,書籍的目錄頁(從章節名稱快速知道頁碼)其實就是一個典型的正排索引。而一般書籍的末尾部分的索引頁,則是一個典型的倒排索引,是從關鍵詞 到 章節名稱 / 頁碼。
由上可知,對於圖書來講:目錄頁就是正排索引,索引頁就是倒排索引。
而對於搜索引擎來講:文檔ID到文檔內容和單詞的關聯是正排索引,而單詞到文檔ID的關係則是倒排索引。
我們可以從下面的兩個表格來感受下正排索引和倒排索引的區別:
倒排索引的核心內容
倒排索引包含兩個部分:
-
單詞詞典(Term Dictionary):記錄所有文檔的單詞,記錄單詞到倒排列表的關聯關係。單詞詞典一般都很大,一般都通過B+樹 或 哈希拉鍊法 實現,以滿足高性能的插入和查詢。
-
倒排列表(Posting List):記錄了單詞對應的文檔結合,由倒排索引項組成。倒排索引項(Posting)包括 文檔ID、詞頻(TF,該單詞在文檔中出現的次數,用於相關性評分)、位置(Postion,單詞在文檔中分詞的位置,用於語句搜索) 以及 偏移(Offset,記錄單詞的開始結束爲止,實現高亮顯示)
下圖展示了ES中的一個例子:
ES中的JSON文檔中的每個字段,都有自己的倒排索引。當然,我們可以指定對某些字段不做索引,以節省存儲空間,但是這些字段就無法被搜索。
重要概念2:Analyzer
在ES中文本分析是其最常見的功能之一,文本分析(Analysis)是把全文轉換爲一系列單詞(term)的過程,也叫作分詞。
文本分析是通過Analyzer來實現,我們可以使用ES內置的分析器,也可以按需定製分析器。
除了在數據寫入時會進行全文轉換詞條,在匹配Query語句時也需要用相同的分析器對查詢語句進行分析。
ES中的內置分詞器
-
Standard Analyzer - 默認分詞器,按詞切分,小寫處理
-
Simple Analyzer - 按照非字母切分(符號被過濾),小寫處理
-
Stop Analyzer - 小寫處理,停用詞過濾(the, a, is)
-
Whitespace Analyzer - 按照空格切分,不轉小寫
-
Keyword Analyzer - 不分詞,直接將輸入當做輸出
-
Patter Analyzer - 正則表達式,默認 \W+(非字符分隔)
-
Language - 提供了30多種常見語言的分詞器
-
Custom Analyzer - 自定義分詞器
通過Analyzer進行分詞
這裏,我們來用_analyzer API做一些demo:
(1)Standard Analyzer
GET /_analyze { "analyzer": "standard", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:按詞切分,默認小寫(Quick被轉成了quick)
{ "tokens" : [ { "token" : "2", "start_offset" : 0, "end_offset" : 1, "type" : "<NUM>", "position" : 0 }, { "token" : "running", "start_offset" : 2, "end_offset" : 9, "type" : "<ALPHANUM>", "position" : 1 }, { "token" : "quick", "start_offset" : 10, "end_offset" : 15, "type" : "<ALPHANUM>", "position" : 2 }, { "token" : "brown", "start_offset" : 16, "end_offset" : 21, "type" : "<ALPHANUM>", "position" : 3 }, { "token" : "foxes", "start_offset" : 22, "end_offset" : 27, "type" : "<ALPHANUM>", "position" : 4 }, { "token" : "leap", "start_offset" : 28, "end_offset" : 32, "type" : "<ALPHANUM>", "position" : 5 }, { "token" : "over", "start_offset" : 33, "end_offset" : 37, "type" : "<ALPHANUM>", "position" : 6 }, { "token" : "lazy", "start_offset" : 38, "end_offset" : 42, "type" : "<ALPHANUM>", "position" : 7 }, { "token" : "dogs", "start_offset" : 43, "end_offset" : 47, "type" : "<ALPHANUM>", "position" : 8 }, { "token" : "in", "start_offset" : 48, "end_offset" : 50, "type" : "<ALPHANUM>", "position" : 9 }, { "token" : "the", "start_offset" : 51, "end_offset" : 54, "type" : "<ALPHANUM>", "position" : 10 }, { "token" : "summer", "start_offset" : 55, "end_offset" : 61, "type" : "<ALPHANUM>", "position" : 11 }, { "token" : "evening", "start_offset" : 62, "end_offset" : 69, "type" : "<ALPHANUM>", "position" : 12 } ] }
(2)Simple Analyzer
GET /_analyze { "analyzer": "simple", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:非字母切分,忽略了數字2,小寫處理
{ "tokens" : [ { "token" : "running", "start_offset" : 2, "end_offset" : 9, "type" : "word", "position" : 0 }, ...... ] }
(3)Whitespace Analyzer
GET /_analyze { "analyzer": "whitespace", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:按照空格切分,不轉小寫。可以看到,brown-foxes被看成是一個整體,並未像其他分詞一樣分爲brown 和 foxes。此外,也不會強制換位小寫,比如Quick就保留了大寫。
{ "tokens" : [ ...... { "token" : "Quick", "start_offset" : 10, "end_offset" : 15, "type" : "word", "position" : 2 }, { "token" : "brown-foxes", "start_offset" : 16, "end_offset" : 27, "type" : "word", "position" : 3 }, ...... ] }
(4)Stop Analyzer
GET /_analyze { "analyzer": "stop", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:小寫處理,停用詞過濾(the, a, is),這裏原文中的in, over, the都被過濾掉了。
(5)Keyword Analyzer
GET /_analyze { "analyzer": "keyword", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:不做任何分詞處理,而是將輸入整體作爲一個term。通常用於不需要對輸入做分詞的場景。
{ "tokens" : [ { "token" : "2 running Quick brown-foxes leap over lazy dogs in the summer evening.", "start_offset" : 0, "end_offset" : 70, "type" : "word", "position" : 0 } ] }
(6)Pattern Analyzer
GET /_analyze { "analyzer": "pattern", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
正則表達式,默認 \W+(非字符分隔)
新增一個表達式analyzer:
PUT my_index { "settings": { "analysis": { "analyzer": { "my_email_analyzer": { "type": "pattern", "pattern": "\\W|_", "lowercase": true } } } } } POST my_index/_analyze { "analyzer": "my_email_analyzer", "text": "[email protected]" }
(7)Lanuage Analyzer
ES提供了多種語言的分詞器:阿拉伯語、亞美尼亞語、巴斯克語、孟加拉語、巴西語、保加利亞語、加泰羅尼亞語、捷克語、丹麥語、荷蘭語、英語、芬蘭語、法語、加利西亞語、德語、希臘語、印地語、匈牙利語、印度尼西亞語、愛爾蘭語、意大利語、拉脫維亞語、立陶宛語、挪威語、波斯語、葡萄牙語、羅馬尼亞語、俄語、索拉尼語、西班牙語、瑞典語、土耳其語、泰國語。
這裏我們看看English:
GET /_analyze { "analyzer": "english", "text": "2 running Quick brown-foxes leap over lazy dogs in the summer evening." }
分詞結果:將running替換爲了run,將foxes替換爲fox,dogs替換爲dog,evening替換爲了even,in被忽略。
可以看到,ES支持的語言分詞器中,沒有支持中文,這是因爲:中文分詞存在較大的難點,不像英語那麼簡單。
不過,我們可以安裝一些中文分詞器的插件(plugin),比如ICU Analyzer, 它提供了unicode的支持,更好地支持亞洲語言。
elasticsearch-plugin install analysis-icu
ICU Analyzer的示例:
POST /_analyze { "analyzer": "icu_analyzer", "text": "他說的確實在理" }
分詞結果:
[他,說的,確實,在,理]
小結
本篇,我們瞭解了ElasticSearch的另一個重要概念:倒排索引 和 一個重要工具:Analyzer,還通過一些demo瞭解了Analyzer的具體使用案例,它們幫助ElasticSearch實現了強大的搜索功能。
參考資料
極客時間,阮一鳴,《ElasticSearch核心技術與實戰》