1. 程式人生 > >elasticsearch的mapping和analysis

elasticsearch的mapping和analysis

repl 個推 field mat parent ppi 逗號 rip lin

轉發自:http://blog.csdn.net/hzrandd/article/details/47128895

分析和分析器

分析(analysis)是這樣一個過程:

  • 首先,表征化一個文本塊為適用於倒排索引單獨的詞(term)
  • 然後標準化這些詞為標準形式,提高它們的“可搜索性”或“查全率”

這個工作是分析器(analyzer)完成的。一個分析器(analyzer)只是一個包裝用於將三個功能放到一個包裏:

字符過濾器

首先字符串經過字符過濾器(character filter),它們的工作是在表征化(譯者註:這個詞叫做斷詞更合適)前處理字符串。字符過濾器能夠去除HTML標記,或者轉換"&"

"and"

分詞器

下一步,分詞器(tokenizer)被表征化(斷詞)為獨立的詞。一個簡單的分詞器(tokenizer)可以根據空格或逗號將單詞分開(譯者註:這個在中文中不適用)。

表征過濾

最後,每個詞都通過所有表征過濾(token filters),它可以修改詞(例如將"Quick"轉為小寫),去掉詞(例如停用詞像"a""and"``"the"等等),或者增加詞(例如同義詞像"jump""leap"

Elasticsearch提供很多開箱即用的字符過濾器,分詞器和表征過濾器。這些可以組合來創建自定義的分析器以應對不同的需求。我們將在《自定義分析器》章節詳細討論。

內建的分析器

不過,Elasticsearch還附帶了一些預裝的分析器,你可以直接使用它們。下面我們列出了最重要的幾個分析器,來演示這個字符串分詞後的表現差異:

"Set the shape to semi-transparent by calling set_trans(5)"

標準分析器

標準分析器是Elasticsearch默認使用的分析器。對於文本分析,它對於任何語言都是最佳選擇(譯者註:就是沒啥特殊需求,對於任何一個國家的語言,這個分析器就夠用了)。它根據Unicode Consortium的定義的單詞邊界(word boundaries)來切分文本,然後去掉大部分標點符號。最後,把所有詞轉為小寫。產生的結果為:

set, the, shape, to, semi, transparent, by, calling, set_trans, 5

簡單分析器

簡單分析器將非單個字母的文本切分,然後把每個詞轉為小寫。產生的結果為:

set, the, shape, to, semi, transparent, by, calling, set, trans

空格分析器

空格分析器依據空格切分文本。它不轉換小寫。產生結果為:

Set, the, shape, to, semi-transparent, by, calling, set_trans(5)

語言分析器

特定語言分析器適用於很多語言。它們能夠考慮到特定語言的特性。例如,english分析器自帶一套英語停用詞庫——像andthe這些與語義無關的通用詞。這些詞被移除後,因為語法規則的存在,英語單詞的主體含義依舊能被理解(譯者註:stem English words這句不知道該如何翻譯,查了字典,我理解的大概意思應該是將英語語句比作一株植物,去掉無用的枝葉,主幹依舊存在,停用詞好比枝葉,存在與否並不影響對這句話的理解。)。

english分析器將會產生以下結果:

set, shape, semi, transpar, call, set_tran, 5

註意"transparent""calling""set_trans"是如何轉為詞幹的。

當分析器被使用

當我們索引(index)一個文檔,全文字段會被分析為單獨的詞來創建倒排索引。不過,當我們在全文字段搜索(search)時,我們要讓查詢字符串經過同樣的分析流程處理,以確保這些詞在索引中存在。

全文查詢我們將在稍後討論,理解每個字段是如何定義的,這樣才可以讓它們做正確的事:

  • 當你查詢全文(full text)字段,查詢將使用相同的分析器來分析查詢字符串,以產生正確的詞列表。
  • 當你查詢一個確切值(exact value)字段,查詢將不分析查詢字符串,但是你可以自己指定。

現在你可以明白為什麽《映射和分析》的開頭會產生那種結果:

  • date字段包含一個確切值:單獨的一個詞"2014-09-15"
  • _all字段是一個全文字段,所以分析過程將日期轉為三個詞:"2014""09""15"

當我們在_all字段查詢2014,它一個匹配到12條推文,因為這些推文都包含詞2014

GET /_search?q=2014              # 12 results

當我們在_all字段中查詢2014-09-15,首先分析查詢字符串,產生匹配任一詞20140915的查詢語句,它依舊匹配12個推文,因為它們都包含詞2014

GET /_search?q=2014-09-15        # 12 results !

當我們在date字段中查詢2014-09-15,它查詢一個確切的日期,然後只找到一條推文:

GET /_search?q=date:2014-09-15   # 1  result

當我們在date字段中查詢2014,沒有找到文檔,因為沒有文檔包含那個確切的日期:

GET /_search?q=date:2014         # 0  results !

測試分析器

尤其當你是Elasticsearch新手時,對於如何分詞以及存儲到索引中理解起來比較困難。為了更好的理解如何進行,你可以使用analyze API來查看文本是如何被分析的。在查詢字符串參數中指定要使用的分析器,被分析的文本做為請求體:

GET /_analyze?analyzer=standard
Text to analyze

結果中每個節點在代表一個詞:

{
   "tokens": [
      {
         "token":        "text",
         "start_offset": 0,
         "end_offset":   4,
         "type":         "<ALPHANUM>",
         "position":     1
      },
      {
         "token":        "to",
         "start_offset": 5,
         "end_offset":   7,
         "type":         "<ALPHANUM>",
         "position":     2
      },
      {
         "token":        "analyze",
         "start_offset": 8,
         "end_offset":   15,
         "type":         "<ALPHANUM>",
         "position":     3
      }
   ]
}

token是一個實際被存儲在索引中的詞。position指明詞在原文本中是第幾個出現的。start_offsetend_offset表示詞在原文本中占據的位置。

analyze API 對於理解Elasticsearch索引的內在細節是個非常有用的工具,隨著內容的推進,我們將繼續討論它。

指定分析器

當Elasticsearch在你的文檔中探測到一個新的字符串字段,它將自動設置它為全文string字段並用standard分析器分析。

你不可能總是想要這樣做。也許你想使用一個更適合這個數據的語言分析器。或者,你只想把字符串字段當作一個普通的字段——不做任何分析,只存儲確切值,就像字符串類型的用戶ID或者內部狀態字段或者標簽。

為了達到這種效果,我們必須通過映射(mapping)人工設置這些字段。

映射

我們知道索引中每個文檔都有一個類型(type)。 每個類型擁有自己的映射(mapping)或者模式定義(schema definition)。一個映射定義了字段類型,每個字段的數據類型,以及字段被Elasticsearch處理的方式。映射還用於設置關聯到類型上的元數據。

核心簡單字段類型

Elasticsearch支持以下簡單字段類型:

類型表示的數據類型
String string
Whole number byte, short, integer, long
Floating point float, double
Boolean boolean
Date date

當你索引一個包含新字段的文檔——一個之前沒有的字段——Elasticsearch將使用動態映射猜測字段類型,這類型來自於JSON的基本數據類型,使用以下規則:

JSON typeField type
Boolean: true or false "boolean"
Whole number: 123 "long"
Floating point: 123.45 "double"
String, valid date: "2014-09-15" "date"
String: "foo bar" "string"

註意

這意味著,如果你索引一個帶引號的數字——"123",它將被映射為"string"類型,而不是"long"類型。然而,如果字段已經被映射為"long"類型,Elasticsearch將嘗試轉換字符串為long,並在轉換失敗時會拋出異常。

查看映射

我們可以使用_mapping後綴來查看Elasticsearch中的映射。在本章開始我們已經找到索引gb類型tweet中的映射:

GET /gb/_mapping/tweet

這展示給了我們字段的映射(叫做屬性(properties)),這些映射是Elasticsearch在創建索引時動態生成的:

{
   "gb": {
      "mappings": {
         "tweet": {
            "properties": {
               "date": {
                  "type": "date",
                  "format": "dateOptionalTime"
               },
               "name": {
                  "type": "string"
               },
               "tweet": {
                  "type": "string"
               },
               "user_id": {
                  "type": "long"
               }
            }
         }
      }
   }
}

小提示

錯誤的映射,例如把age字段映射為string類型而不是integer類型,會造成查詢結果混亂。

要檢查映射類型,而不是假設它是正確的!

自定義字段映射

映射中最重要的字段參數是type。除了string類型的字段,你可能很少需要映射其他的type

{
    "number_of_clicks": {
        "type": "integer"
    }
}

string類型的字段,默認的,考慮到包含全文本,它們的值在索引前要經過分析器分析,並且在全文搜索此字段前要把查詢語句做分析處理。

對於string字段,兩個最重要的映射參數是indexanalyer

index

index參數控制字符串以何種方式被索引。它包含以下三個值當中的一個:

解釋
analyzed 首先分析這個字符串,然後索引。換言之,以全文形式索引此字段。
not_analyzed 索引這個字段,使之可以被搜索,但是索引內容和指定值一樣。不分析此字段。
no 不索引這個字段。這個字段不能為搜索到。

string類型字段默認值是analyzed。如果我們想映射字段為確切值,我們需要設置它為not_analyzed

{
    "tag": {
        "type":     "string",
        "index":    "not_analyzed"
    }
}

其他簡單類型——longdoubledate等等——也接受index參數,但相應的值只能是nonot_analyzed,它們的值不能被分析。

分析

對於analyzed類型的字符串字段,使用analyzer參數來指定哪一種分析器將在搜索和索引的時候使用。默認的,Elasticsearch使用standard分析器,但是你可以通過指定一個內建的分析器來更改它,例如whitespacesimpleenglish

{
    "tweet": {
        "type":     "string",
        "analyzer": "english"
    }
}

在《自定義分析器》章節我們將告訴你如何定義和使用自定義的分析器。

更新映射

你可以在第一次創建索引的時候指定映射的類型。此外,你也可以晚些時候為新類型添加映射(或者為已有的類型更新映射)。

重要

你可以向已有映射中增加字段,但你不能修改它。如果一個字段在映射中已經存在,這可能意味著那個字段的數據已經被索引。如果你改變了字段映射,那已經被索引的數據將錯誤並且不能被正確的搜索到。

我們可以更新一個映射來增加一個新字段,但是不能把已有字段的類型那個從analyzed改到not_analyzed

為了演示兩個指定的映射方法,讓我們首先刪除索引gb

DELETE /gb

然後創建一個新索引,指定tweet字段的分析器為english

PUT /gb <1>
{
  "mappings": {
    "tweet" : {
      "properties" : {
        "tweet" : {
          "type" :    "string",
          "analyzer": "english"
        },
        "date" : {
          "type" :   "date"
        },
        "name" : {
          "type" :   "string"
        },
        "user_id" : {
          "type" :   "long"
        }
      }
    }
  }
}

<1> 這將創建包含mappings的索引,映射在請求體中指定。

再後來,我們決定在tweet的映射中增加一個新的not_analyzed類型的文本字段,叫做tag,使用_mapping後綴:

PUT /gb/_mapping/tweet
{
  "properties" : {
    "tag" : {
      "type" :    "string",
      "index":    "not_analyzed"
    }
  }
}

註意到我們不再需要列出所有的已經存在的字段,因為我們沒法修改他們。我們的新字段已經被合並至存在的那個映射中。

測試映射

你可以通過名字使用analyze API測試字符串字段的映射。對比這兩個請求的輸出:

GET /gb/_analyze?field=tweet
Black-cats <1>

GET /gb/_analyze?field=tag
Black-cats <1>

<1> 我們想要分析的文本被放在請求體中。

tweet字段產生兩個詞,"black""cat",tag字段產生單獨的一個詞"Black-cats"。換言之,我們的映射工作正常。

elasticsearch的mapping和analysis