elasticsearch映射
前面講到,無論是關系型數據庫還是非關系型數據庫,乃至elasticsearch這種事實上承擔著一定儲存作用的搜索引擎,數據類型都是非常重要而基礎的概念。但elasticsearch與其它承擔著數據存儲的技術有著比較大的區別之一就是映射,和倒排索引。
映射是定義如何存儲和編制文檔及其包含的字段的過程。例如,使用映射來定義:
- 哪些字符串字段應被視為全文字段。
- 哪些字段包含數字,日期或地理位置。
- 文檔中所有字段的值是否應該編入catch-all _all字段。
- 日期值的格式。
- 自定義規則來控制動態添加字段的映射。
很顯然,對於一個搜索引擎來說,光有數據結構是遠遠不夠的。映射是elasticsearch區別與數據庫的重要特征之一。
映射可以看作是建表的過程。但與數據庫不同的是,映射可以為一個字段建立不同的映射以滿足不同的場景,可以對數據進行清洗,容錯,建立倒排索引。
倒排索引
有兩篇文章:
1 我是程序員
2 我熱愛寫程序
先分詞
1 【我】【是】【程序】【程序員】
2【我】【熱愛】【寫】【程序】
前面文章對關鍵字,經倒排後變成關鍵字對文章
關鍵字 | 文章號 |
我 | 1,2 |
是 | 1 |
程序 | 1,2 |
程序員 | 1 |
熱愛 | 2 |
寫 | 2 |
為了快速定位和節省存儲大小,還需要加上關鍵字出現頻率和位置。
關鍵字 | 文章號(頻率) | 位置 |
我 | 1(1) | 1 |
2(1) | 1 | |
是 | 1(1) | 2 |
程序 | 1(1) | 3 |
2(1) | 4 | |
程序員 | 1(1) | 4 |
熱愛 | 1(1) | 1 |
寫 | 1(1) | 3 |
映射的類型
元數據 Meta-fields
用於定制文檔的相關元數據。元字段的示例包括文檔的_index,_type,_id和_source字段。
|
索引標識 |
|
由_type和_id組成的復合字段。
|
|
文檔的映射類型。一個索引當中可以具有多個type。查詢的時候指定索引,再指定type. |
|
文檔ID。 |
|
文檔正文。是用戶保存的真正的數據。 |
|
文檔正文的大小。 |
|
_all字段是把其它字段拼接在一起的超級字段,所有的字段用空格分開,_all字段會被解析和索引,但是不存儲。當你只想返回包含某個關鍵字的文檔但是不明確地搜某個字段的時候就需要使用_all字段。 |
|
字段用來存儲文檔中的所有非空字段的名字,這個字段常用於exists查詢。 |
|
用於創建兩個映射類型之間的父子關系。
|
|
|
_all
它將所有其他字段的值連接成一個大字符串,使用空格作為分隔符,然後對其進行分析和索引,但不存儲。這意味著它可以被搜索,但不能被檢索。
這段話的意思是,它是一個邏輯上的概念。它沒有這個具體的健以及值。所以沒有具體的存儲。它沒有一人常駐的物理存儲。相當於對全部字段進行搜索。
PUT my_index/user/1 { "first_name": "John", "last_name": "Smith", "date_of_birth": "1970-10-24" } GET my_index/_search { "query": { "match": { "_all": "john smith 1970" } } }
// ["john"
,"smith"
,"1970"
,"10"
,"24"
]
_field_names
字段索引包含除null之外的任何值的文檔中的每個字段的名稱。該字段由存在的查詢使用來查找特定字段具有或不具有任何非空值的文檔。
PUT my_index/my_type/1 { "title": "This is a document" } PUT my_index/my_type/2?refresh=true { "title": "This is another document", "body": "This document has a body" } GET my_index/_search { "query": { "terms": { "_field_names": [ "title" ] } } } //返回兩條數據,因為兩條數據都包含titile字段
_routing
使用以下公式決定該文檔路由到哪個shard
shard_num = hash(_routing) % num_primary_shards
用戶定義字段
每個映射類型包含與該類型相關的字段或屬性的列表。用戶類型可能包含title,name和age字段,而blogpost類型可能包含title,body,user_id和已創建的字段。同一索引中不同映射類型中具有相同名稱的字段必須具有相同的映射。
映射參數 Mapping parameters
analyzer
normalizer
boost
coerce
copy_to
doc_values
dynamic
enabled
fielddata
format
ignore_above
ignore_malformed
include_in_all
index_options
index
fields
norms
null_value
position_increment_gap
properties
search_analyzer
similarity
store
term_vector
analyzer
分詞器。es有內置的分詞器,也可以使用第三方的分詞工具。如IK。
{ "mappings": { "my_type": { "properties": { "content": { "type": "text", "analyzer": "ik_max_word",//寫入時使用的分詞器 "search_analyzer": "ik_max_word"//搜索時使用的分詞器 } } } } }
normalizer
keyword類型的標準化解析器。我們知道keyword不能分詞,可它也有標準化的需求,比如忽略大小寫,比如統一去掉特殊字符。那麽normalizer就是為此而準備的。
PUT index { "settings": { "analysis": { "normalizer": { "my_normalizer": { "type": "custom", "char_filter": [], "filter": ["lowercase", "asciifolding"] } } } }, "mappings": { "type": { "properties": { "foo": { "type": "keyword", "normalizer": "my_normalizer" } } } } } PUT index/type/1 { "foo": "BÀR" } PUT index/type/2 { "foo": "bar" } PUT index/type/3 { "foo": "baz" } POST index/_refresh GET index/_search { "query": { "match": { "foo": "BAR" } } }
//返回前面兩條記錄
coerce
數據並不總是很幹凈。根據它的生成方式,一個數字可能會在JSON體中呈現為一個真正的JSON數字,例如5,但它也可以呈現為字符串,例如。 “5”。或者,可以將應該是整數的數字呈現為浮點,例如, 5.0或甚至“5.0”。
強制嘗試清除臟值以適應字段的數據類型。例如:
字符串將被強制為數字。
對於整數值,浮點將被截斷。
{ "mappings": { "my_type": { "properties": { "number_one": { "type": "integer" }, "number_two": { "type": "integer", "coerce": false } } } } } PUT my_index/my_type/1 { "number_one": "10" }
//成功 PUT my_index/my_type/2 { "number_two": "10" }
//失敗
copy_to
允許將一個或者多個字段的值復制到某一個字段中。
{ "mappings": { "my_type": { "properties": { "first_name": { "type": "text", "copy_to": "full_name" }, "last_name": { "type": "text", "copy_to": "full_name" }, "full_name": { "type": "text" } } } } } PUT my_index/my_type/1 { "first_name": "John", "last_name": "Smith" } //full_name = ["John","Smith"]
doc_values
為了加快排序、聚合操作,在建立倒排索引的時候,額外增加一個列式存儲映射,是一個空間換時間的做法。默認是開啟的,對於確定不需要聚合或者排序的字段可以關閉。text類型沒有doc_values。
{ "mappings": { "my_type": { "properties": { "status_code": { "type": "keyword" }, "session_id": { "type": "keyword", "doc_values": false } } } } }
dynamic
The dynamic
setting controls whether new fields can be added dynamically or not. It accepts three settings:
|
新檢測的字段將添加到映射中。 (默認)
|
|
新檢測的字段將被忽略。這些字段將不會被索引,因此不會被搜索,但仍將顯示在返回的匹配的_source字段中。這些字段將不會添加到映射中,必須顯式添加新字段。
|
|
如果檢測到新字段,將拋出異常並拒絕文檔。新字段必須明確添加到映射中。
|
enabled
enabled默認為true,將搜索所有字段。如果設置為false,該字段將不會被搜索。但仍會隨著_source返回。
fielddata
對非text類型的字段進行排序可以使用doc_value來進行加速。但是對於,text類型的字段,卻不能進行分組排序。更何況加速。下面這個異常展示了,對text類型的字段進行分組排序的錯誤。
但是可以通過設置fielddata值來達到這一目的。
它將字段加載到內存中,因此第一次肯定會很慢。而且將占用內存。如果內存達到某一個值,將請求執行失敗。這個值可以配置。
format
對字段進行格式化。
{ "mappings": { "my_type": { "properties": { "date": { "type": "date", "format": "yyyy-MM-dd" } } } } }
ignore_above
大小超過ignore_above設置的字符串不會被索引或存儲。
ignore_malformed
嘗試將錯誤的數據類型索引到字段中,默認情況下會引發異常,並拒絕整個文檔。 ignore_malformed參數(如果設置為true)允許忽略該異常。格式不正確的字段未編入索引,但文檔中的其他字段正常處理。
前面講到,可以通過coerce來進行數據清洗。例如,interger類型的數據寫入了一個“10”,這是可以處理的。但如果寫入的是一個"頂替",那就沒法處理了。如果,將該字段ignore_malformed參數設置為true,那麽將忽略該字段。
include_in_all
include_in_all參數提供對_all字段中包含哪些字段的字段控制。它默認為true,除非index設置為false。
index_options
控制索引時存儲哪些信息到倒排索引中,接受以下配置:
參數 | 作用 |
---|---|
docs | 只存儲文檔編號 |
freqs | 存儲文檔編號和詞項頻率 |
positions | 文檔編號、詞項頻率、詞項的位置被存儲,偏移位置可用於臨近搜索和短語查詢 |
offsets | 文檔編號、詞項頻率、詞項的位置、詞項開始和結束的字符位置都被存儲,offsets設為true會使用Postings highlighter |
fields
可以為一個字段映射多個數據類型。比如,一個字符串,可以映射為text,滿足全文搜索。同時可以映射為keyword,滿足分組和排序。
{ "mappings": { "my_type": { "properties": { "city": { "type": "text", "fields": { "raw": { "type": "keyword" } } } } } } }
也可以使用多個分詞器來對同一個字段進行分詞。
{ "mappings": { "my_type": { "properties": { "text": { "type": "text",//標準分詞器 "fields": { "english": { "type": "text", "analyzer": "english" //英文分詞器 } } } } } } }
norms
norms參數用於標準化文檔,以便查詢時計算文檔的相關性。norms雖然對評分有用,但是會消耗較多的磁盤空間,如果不需要對某個字段進行評分,最好不要開啟norms。
null_value
空值不能被索引或搜索。當一個字段設置為null(或一個空數組或一個空值數組)時,它被視為該字段沒有值。
null_value參數允許您使用指定的值替換顯式空值,以便對其進行索引和搜索。
position_increment_gap
不常用。忽略。
properties
當數據類型為object或者nested,有子節點的時候,可以使用properties來達到。
{ "mappings": { "my_type": { "properties": { "manager": { "properties": { "age": { "type": "integer" }, "name": { "type": "text" } } }, "employees": { "type": "nested", "properties": { "age": { "type": "integer" }, "name": { "type": "text" } } } } } } }
寫入數據
{ "region": "US", "manager": { "name": "Alice White", "age": 30 }, "employees": [ { "name": "John Smith", "age": 34 }, { "name": "Peter Brown", "age": 26 } ] }
search_analyzer
大多數情況下索引和搜索的時候應該指定相同的分析器,確保query解析以後和索引中的詞項一致。但是有時候也需要指定不同的分析器,例如使用edge_ngram過濾器實現自動補全。
{ "settings": { "analysis": { "filter": { "autocomplete_filter": { "type": "edge_ngram", "min_gram": 1, "max_gram": 20 } }, "analyzer": { "autocomplete": { //映射的時候使用autocomplete解析器 "type": "custom", "tokenizer": "standard", "filter": [ "lowercase", "autocomplete_filter" ] } } } }, "mappings": { "my_type": { "properties": { "text": { "type": "text", "analyzer": "autocomplete", //創建索引的時候,使用autocomplete解析器 "search_analyzer": "standard" //搜索的時候,使用standard解析器 } } } } } PUT my_index/my_type/1 { "text": "Quick Brown Fox" //創建索引的時候,使用autocomplete解析器,[ q, qu, qui, quic, quick, b, br, bro, brow, brown, f, fo, fox ] } GET my_index/_search { "query": { "match": { "text": { "query": "Quick Br", //搜索的時候,使用標準解析器,[ quick, br ] "operator": "and" } } } }
store
我們知道,_source字段存儲了原始數據(默認)。當然可以通過設置其屬性值來選擇不存儲。此外,還可以通過store選擇是否額外存儲某個字段。store屬性默認為no,表示不存儲。當設置為yes時,會在_source之外獨立存儲。此時,搜索時,會繞過_source,單獨進行一次IO得到該字段的值。
store會嚴重影響搜索效率,盡管如此,在以下兩種情況下,還是可以選擇使用:
1:字段很長,每次檢索_source代價很大。
2:需要單獨對某些字段進行索引重建。
index
表示字段是否索引。接受true或false。老版的es接受三個值。分別是
analyzed 分詞,索引。
not_analyzed 不分詞,索引。
no 不索引。
動態映射
前面講到的都是先映射後建立索引。但是,也可以,不先建立映射,直接寫入數據;或者,加入沒有映射的字段,es會根據數據的類型自動判斷數據類型,創建索引。
default
可以使用default來作為基本映射。其它映射將繼承默認的配置。
{ "mappings": { "_default_": { "_all": { "enabled": false } }, "user": {}, "blogpost": { "_all": { "enabled": true } } } }
_default_將_all字段設置為disabled.user字段繼承,也將_all字段disabled。而blogpost則重寫了_all屬性。
dynamic
動態添加字段。它有三個選項。前面已經講到。
這裏補充一點,動態添加字段,可能會出現一個問題。比如:
先出現一個值:2017-08-22,動態匹配為date類型。而此字段此後進來的值為非日期類型,匹配失敗。為了避免這種情況出現,可以選擇關閉日期匹配
{ "mappings": { "my_type": { "date_detection": false } } }
dynamic templates
相當於使用模板模式匹配動態字段。
通過dynamic_templates
,你可以擁有對新字段的動態映射規則擁有完全的控制。你設置可以根據字段名稱或者類型來使用一個不同的映射規則。
每個模板都有一個名字,可以用來描述這個模板做了什麽。同時它有一個mapping
用來指定具體的映射信息,和至少一個參數(比如match
)用來規定對於什麽字段需要使用該模板。
模板的匹配是有順序的 - 第一個匹配的模板會被使用。比如我們可以為string
字段指定兩個模板:
es
:以_es
結尾的字段應該使用spanish
解析器en
:其它所有字段使用english
解析器
我們需要將es
模板放在第一個,因為它相比能夠匹配所有字符串字段的en
模板更加具體:
{ "mappings": { "my_type": { "dynamic_templates": [ { "es": { "match": "*_es", "match_mapping_type": "string", "mapping": { "type": "string", "analyzer": "spanish" } }}, { "en": { "match": "*", "match_mapping_type": "string", "mapping": { "type": "string", "analyzer": "english" } }} ] }}}
match_mapping_type
允許你只對特定類型的字段使用模板,正如標準動態映射規則那樣,比如string
,long
等。
match
參數只會匹配字段名,path_match
參數用於匹配對象中字段的完整路徑,比如address.*.name
可以匹配如下字段:
{ "address": "city": "name": "New York" } } }
unmatch
和path_unmatch
模式能夠用來排除某些字段,沒有被排除的字段則會被匹配。
總結
一。映射可以簡單的理解為數據庫建表的過程。但映射更為強大得多。
二。倒排索引。傳統數據庫索引的方式是,【表->字段】。而倒排索引的方式是先將字段進行分詞,然後將單詞跟文檔進行關聯,變為【文檔->單詞】,並將記錄其它更為強大的信息(文檔編號、詞項頻率、詞項的位置、詞項開始和結束的字符位置可以被存儲)。倒排索引是elasticsearch區別於數據庫的關鍵。
三。映射的字段包括元數據,就是默認的字段。以及用戶自定義的字段。
1:元數據,一般以"_"開頭。如下圖。比較重要的字段有_index,_type,_id,_source,_routing。其它字段較為不重要。_all 6.0以後將移除該字段。可以忽略。
_index 索引名稱。可以看作是數據庫名稱。
_type 可以看作是表名。
_id 可以看作是唯一標識。
_routing 是決定將該值保存在集群中哪個分片的值。
_source 存儲原始數據的地方。es將原始數據存儲在_source。另外還會保存倒排索引。另外,還可以將數據單獨保存在_store。
點擊其中一行數據:
2:用戶自定義字段。
analyzer 首先一個字段進來,除了keyword類型的以外,都可以選擇是否分詞。
normalizer keyword類型的標準化解析器。我們知道keyword不能分詞,可它也有標準化的需求,比如忽略大小寫,比如統一去掉特殊字符。那麽normalizer就是為此而準備的。
coerce 強制嘗試清除臟值以適應字段的數據類型。與其說是數據清洗,不如說是數據適配。比如,該字段數據為整型,進來一個字段為 “10”,那麽它會自動適配為 10。
doc_values 倒排索引加快了全文搜索的速度,但對於排序和聚合操作,很多時候還是顯得有些力不從心。此字段,在倒排索引的基礎上,再增加了一個列式存儲。加快排序和聚合。默認開啟。text因為一般存儲字段比較長,沒有此屬性值。
dynamic 動態添加字段。在映射的時候沒有考慮到的字段,後期數據出現了,es提供了三種選擇方案。true,默認,添加,適配類型。false,忽略。存儲原始值,但不會被添加到倒排索引。因此,不能搜索,但可以返回。strict,拋出異常。
需要註意的是,如果選擇了true,那麽es會根據首次進來的數據選擇一個類型,如果後續的數據不符合這個類型 ,可能會拋出異常。如:先出現一個值:2017-08-22,動態匹配為date類型。而此字段此後進來的值為非日期類型,匹配失敗。為了避免這種情況出現, 可以選擇關閉日期匹配
enabled 這個字段可以設置在 _source中,也可以設置在自定義字段中,表示是否存儲原始數據。
fielddata 對於text類型的字段,不能分組,但可以通過此字段來達到此目的。
format 對字段進行格式化。
ignore_above 對字段長度進行限制。
ignore_malformed 對字段類型進行限制。設置為true,在字段類型不匹配的情況下,忽略該異常。
index_options 對字段建立倒排索引的信息進行限制。信息分別為文檔編號、詞項頻率、詞項的位置、詞項開始和結束的字符位置。
fields 一個字段映射為多個類型。
store store屬性默認為no,表示不存儲。當設置為yes時,會在_source之外獨立存儲。此時,搜索時,會繞過_source,單獨進行一次IO得到該字段的值。
index 表示字段是否索引。接受true或false。
參考:
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
http://blog.csdn.net/liyantianmin/article/details/52531500
elasticsearch映射