elasticsearch的mapping和analysis
轉發自: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
分析器自帶一套英語停用詞庫——像and
或the
這些與語義無關的通用詞。這些詞被移除後,因為語法規則的存在,英語單詞的主體含義依舊能被理解(譯者註: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
,首先分析查詢字符串,產生匹配任一詞2014
、09
或15
的查詢語句,它依舊匹配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_offset
和end_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 type | Field 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
字段,兩個最重要的映射參數是index
和analyer
。
index
index
參數控制字符串以何種方式被索引。它包含以下三個值當中的一個:
值 | 解釋 |
---|---|
analyzed |
首先分析這個字符串,然後索引。換言之,以全文形式索引此字段。 |
not_analyzed |
索引這個字段,使之可以被搜索,但是索引內容和指定值一樣。不分析此字段。 |
no |
不索引這個字段。這個字段不能為搜索到。 |
string
類型字段默認值是analyzed
。如果我們想映射字段為確切值,我們需要設置它為not_analyzed
:
{
"tag": {
"type": "string",
"index": "not_analyzed"
}
}
其他簡單類型——
long
、double
、date
等等——也接受index
參數,但相應的值只能是no
和not_analyzed
,它們的值不能被分析。
分析
對於analyzed
類型的字符串字段,使用analyzer
參數來指定哪一種分析器將在搜索和索引的時候使用。默認的,Elasticsearch使用standard
分析器,但是你可以通過指定一個內建的分析器來更改它,例如whitespace
、simple
或english
。
{
"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