Elastic學習之旅 (5) 倒排索引和Analyzer分詞

大家好,我是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核心技術與實戰

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章