一起學(xué) Elasticsearch 系列 -Mapping
本篇講解Elasticsearch中非常重要的一個概念:Mapping,Mapping是索引必不可少的組成部分。
一、Mapping 的基本概念
Mapping 也稱之為映射,定義了 ES 的索引結(jié)構(gòu)、字段類型、分詞器等屬性,是索引必不可少的組成部分。
ES 中的 Mapping 有點(diǎn)類似于關(guān)系型數(shù)據(jù)庫中“表結(jié)構(gòu)”的概念,在 MySQL 中,表結(jié)構(gòu)里包含了字段名稱,字段的類型還有索引信息等。在 Mapping 里也包含了一些屬性,比如字段名稱、類型、字段使用的分詞器、是否評分、是否創(chuàng)建索引等屬性。
查看索引 Mapping
//查看索引完整的mapping
GET /my_index/_mappings
//查看索引指定字段的mapping
GET /my_index/_mappings/field/field_name
例如,如果你有一個名為 "my_index" 的索引,并且你想查詢字段 "my_field" 的 mapping,那么請求就像這樣:
GET /my_index/_mapping/field/my_field
此請求會返回如下類型的輸出:
{
"my_index" : {
"mappings" : {
"my_field" : {
"full_name" : "my_field",
"mapping" : {
"my_field" : {
"type" : "text",
"fields" : {
"keyword" : {
"type" : "keyword",
"ignore_above" : 256
}
}
}
}
}
}
}
}
在這個響應(yīng)中,你可以看到 "my_field" 是 "text" 類型,并且它也有一個子字段 "keyword"。
二、字段數(shù)據(jù)類型
映射的數(shù)據(jù)類型也就是 ES 索引支持的數(shù)據(jù)類型,其概念和 MySQL 中的字段類型相似,但是具體的類型和 MySQL 中有所區(qū)別,最主要的區(qū)別就在于 ES 中支持可分詞的數(shù)據(jù)類型,如:Text 類型,可分詞類型是用以支持全文檢索的,這也是 ES 生態(tài)最核心的功能。
1.數(shù)字類型
- long:64 位有符號整形。
- integer:32 位有符號整形。
- short:16 位有符號整形。
- byte:8位有符號整形。
- double:雙精度64位浮點(diǎn)類型。
- float:單精度32位浮點(diǎn)類型。
- half_float:半精度16位浮點(diǎn)數(shù)。
- scaled_float:縮放類型浮點(diǎn)數(shù),按固定 double 比例因子縮放。
- unsigned_long:無符號 64 位整數(shù)。
2.基本數(shù)據(jù)類型
- binary:存儲二進(jìn)制字符串,經(jīng)過Base64編碼處理。
- boolean:布爾類型,接收 ture 和 false 兩個值。
3.Keywords 類型
- keyword:這種類型被用來索引結(jié)構(gòu)化數(shù)據(jù),如 email 地址、主機(jī)名、狀態(tài)碼以及標(biāo)簽等。這類數(shù)據(jù)可以以精確值的形式進(jìn)行搜索,并且可以用于過濾 (filtering),排序 (sorting) 和聚合 (aggregating)。關(guān)鍵詞字段只和其確切的值匹配,它們的查詢不會進(jìn)行分詞處理。
- constant_keyword:這種類型適用于在所有文檔中都始終有相同值的字段。比如在一次特定的索引操作中,所有的文檔都需要包含一個常量字段,例如 env 的值可能為 "production"。
- wildcard:這種類型的字段可以存儲任何字符串,并且對于這種類型的字段進(jìn)行的查詢可以使用通配符表達(dá)式。這種類型的字段對于像 grep 這樣的場景非常有用,即當(dāng)你需要在一個長字符串中搜索一個較短的子串時。但是要注意,雖然 wildcard 字段提供了強(qiáng)大的模式匹配能力,但是這種能力是需要付出性能代價的。
4.日期類型
JSON 沒有日期數(shù)據(jù)類型,因此 Elasticsearch 中的日期可以是以下三種:
- 包含格式化日期的字符串:例如 "2015-01-01"、 "2015/01/01 12:10:30"。
- 時間戳:表示自"1970年 1 月 1 日"以來的毫秒數(shù)/秒數(shù)。
- date_nanos:此數(shù)據(jù)類型是對 date 類型的補(bǔ)充。但是有一個重要區(qū)別。date 類型存儲最高精度為毫秒,而date_nanos 類型存儲日期最高精度是納秒,但是高精度意味著可存儲的日期范圍小,即:從大約 1970 到 2262。
5.對象類型
- object:默認(rèn)情況下,Elasticsearch 使用 object 數(shù)據(jù)類型來處理 JSON 對象。
- flattened:這是用來索引對象數(shù)組或者具有未知結(jié)構(gòu)的字段的特殊映射類型。其將整個JSON對象作為單個鍵值對存儲,幫助降低索引大小和提高搜索速度。
- nested:這是一個類似于 object 的數(shù)據(jù)類型,但它能保存并查詢對象數(shù)組內(nèi)部對象的獨(dú)立性,因此可以用來處理更復(fù)雜的結(jié)構(gòu)。
- join:這是一個特殊數(shù)據(jù)類型,用于模擬在文檔之間的父/子關(guān)系。這樣可以創(chuàng)建一對多的連接,例如,在博客文章和評論這樣的場景中使用。
6.空間數(shù)據(jù)類型
- geo_point:表示地理位置的點(diǎn),存儲緯度和經(jīng)度信息。
- geo_shape:表示復(fù)雜的地理形狀,如多邊形、線、圓等。
- point:在笛卡爾空間中表示一個點(diǎn),存儲X和Y坐標(biāo)。
- shape:在笛卡爾空間中表示任意復(fù)雜的幾何形狀。
7.文檔排名類型
- dense_vector:記錄浮點(diǎn)值的密集向量。這種類型常用于存儲機(jī)器學(xué)習(xí)模型的輸出,例如詞嵌入、句子嵌入等。
- rank_feature:記錄單個數(shù)值特征以優(yōu)化排名。當(dāng)這個字段被查詢時,Elasticsearch 會考慮其值來重新排序搜索結(jié)果。
- rank_features:記錄多個數(shù)值特征以優(yōu)化排名。與rank_feature類似,但它能夠處理包含多個特征的對象。當(dāng)這些字段被查詢時,Elasticsearch 會考慮它們的值來重新排序搜索結(jié)果。
8.文本搜索類型
- text:用于存儲全文和進(jìn)行全文搜索的數(shù)據(jù)類型。
- annotated-text:這是一個特殊的文本字段,它支持包含標(biāo)記的文本。這些標(biāo)記表示文本中的命名實體或其他重要項,可以在后續(xù)搜索中使用。
- completion :這是一個專門為自動補(bǔ)全和搜索建議設(shè)計的數(shù)據(jù)類型。
- search_as_you_type: 這是一種特殊的文本字段,它被優(yōu)化以提供按鍵查詢時的即時反饋,從而提高用戶輸入時的搜索體驗。
- token_count:這是一種數(shù)值型字段,用于存儲文本字段中的詞元數(shù)量。此字段常用于信息檢索場景,比如評估某個字段的長度。
三、兩種映射類型
1.自動映射:Dynamic Field Mapping
Elasticsearch的Dynamic Field Mapping是一種自動產(chǎn)生index mapping的機(jī)制。在通常情況下,當(dāng)一個新文檔被索引到Elasticsearch中,如果其中包含了未在mapping中定義的字段,Elasticsearch就會嘗試根據(jù)這個新字段的數(shù)據(jù)類型自動生成相應(yīng)的mapping。
自動映射關(guān)系如下:
field type | dynamic |
true/false | boolean |
小數(shù) | float |
數(shù)字 | long |
object | object |
數(shù)組 | 取決于數(shù)組中的第一個非空元素的類型 |
日期格式字符串 | date |
數(shù)字類型字符串 | float/long |
其他字符串 | text + keyword |
除了上述字段類型之外,其他類型都必須顯式映射,也就是必須手工指定,因為其他類型ES無法自動識別。
這里有幾點(diǎn)需要注意:
- 數(shù)據(jù)類型識別:Elasticsearch會按照以下順序判斷數(shù)據(jù)類型:長整數(shù)、浮點(diǎn)數(shù)、布爾值、日期、字符串(字符串可能會進(jìn)一步映射為text或keyword)。
- 字段名稱含義:Elasticsearch不會考慮字段名稱的含義,它僅僅依靠字段的數(shù)據(jù)類型來生成mapping。
- 關(guān)閉動態(tài)映射:如果你不希望Elasticsearch自動創(chuàng)建mapping,可以將index的dynamic設(shè)置為false。
- 動態(tài)模板:你可以使用動態(tài)模板來改變默認(rèn)的mapping規(guī)則,例如,你可以將所有看起來像日期的字符串都映射為date類型。
- 對象和嵌套字段:對于對象(object)和嵌套字段(nested),Elasticsearch也會遞歸地應(yīng)用動態(tài)映射規(guī)則。
- 更新映射:請注意,一旦字段的映射被創(chuàng)建,就不能再修改字段的數(shù)據(jù)類型了。因此,如果你要索引的文檔中有新的字段,最好事先定義好mapping,避免讓Elasticsearch自動映射可能產(chǎn)生不符合你期望的結(jié)果。
- 當(dāng)一個字段第一次出現(xiàn)時,Elasticsearch會使用先行數(shù)據(jù)類型來設(shè)置映射。如果后續(xù)數(shù)據(jù)類型與先前設(shè)置的映射類型不一致,Elasticsearch可能無法正確索引這些文檔。
總的來說,雖然動態(tài)字段映射可以在某些情況下提供便利,但它也可能導(dǎo)致未預(yù)見的問題。因此,更推薦在開始索引文檔之前就定義好mapping。
2.顯式映射:Expllcit Field Mapping
在 Elasticsearch 中,顯式映射(Explicit Field Mapping)是指為索引預(yù)定義的字段類型和行為。當(dāng)你創(chuàng)建一個索引時,你可以定義每個字段的數(shù)據(jù)類型、分詞器或者其他相關(guān)的配置。這就是顯式映射。
以下是一些主要的顯式映射類型:
- 核心數(shù)據(jù)類型:包括 string(字符串)、integer(整型)、long(長整型)、double(雙精度浮點(diǎn)型)、boolean(布爾型)等。
- 復(fù)合數(shù)據(jù)類型:包括 object(對象),用于單個 JSON 對象,nested,用于 JSON 數(shù)組。
- 地理數(shù)據(jù)類型:如 geo_point 和 geo_shape。
- 專門用途的數(shù)據(jù)類型:例如 IP、自動完成、token count、join types 等。
通過顯式映射,Elasticsearch 可以更準(zhǔn)確地解析和索引數(shù)據(jù),對查詢性能優(yōu)化起到關(guān)鍵作用。如果不提供顯式映射,Elasticsearch 將會根據(jù)輸入數(shù)據(jù)自動推斷并生成隱式映射,但可能無法達(dá)到最理想的效果。
以下是一個示例,展示了怎么設(shè)置一個簡單的顯式映射:
PUT my_index
{
"mappings": {
"properties": {
"name": { "type": "text" },
"age": { "type": "integer" }
}
}
}
上述代碼中,我們在 my_index 索引中定義了兩個字段的映射,name 字段類型為 text,age 字段類型為 integer。
注意:在 Elasticsearch 7.0 之后,映射類型被廢棄,所有的映射參數(shù)直接放在 "properties" 下。
四、映射參數(shù)
在Elasticsearch中,映射參數(shù)是用于定義如何處理文檔和其包含的字段的規(guī)則。
主要參數(shù)有下:
- index:是否對當(dāng)前字段創(chuàng)建倒排索引,默認(rèn) true,如果不創(chuàng)建索引,該字段不會通過索引被搜索到,但是仍然會在 source 元數(shù)據(jù)中展示。
- analyzer:指定分析器(character filter、tokenizer、Token filters)。
- boost:對當(dāng)前字段相關(guān)度的評分權(quán)重,默認(rèn)1。
- coerce:是否允許強(qiáng)制類型轉(zhuǎn)換,為 true的話 “1”能被轉(zhuǎn)為 1, false則轉(zhuǎn)不了。雖然這個參數(shù)可以幫助我們強(qiáng)制類型轉(zhuǎn)換,但是它可能會在數(shù)據(jù)質(zhì)量管理中引起問題。如果原始數(shù)據(jù)包含錯誤的類型,使用 "coerce" 可能會隱藏這些問題,而不是將其暴露出來。
- copy_to:該參數(shù)允許將多個字段的值復(fù)制到組字段中,然后可以將其作為單個字段進(jìn)行查詢。
- doc_values:為了提升排序和聚合效率,默認(rèn)true,如果確定不需要對字段進(jìn)行排序或聚合,也不需要通過腳本訪問字段值,則可以禁用doc值以節(jié)省磁盤空間,對于text字段和annotated_text字段,無法禁用此選項,因為這些字段類型在默認(rèn)情況下不使用doc values。
- dynamic:控制是否可以動態(tài)添加新字段
- true :新檢測到的字段將添加到映射中(默認(rèn))。
- false :新檢測到的字段將被忽略。這些字段將不會被索引,因此將無法搜索,但仍會出現(xiàn)在_source返回的匹配項中。這些字段不會添加到映射中,必須顯式添加新字段。
- strict :如果檢測到新字段,則會引發(fā)異常并拒絕文檔。必須將新字段顯式添加到映射。
- eager_global_ordinals:用于聚合的字段上,優(yōu)化聚合性能,但不適用于 Frozen indices。
- Frozen indices(凍結(jié)索引):有些索引使用率很高,會被保存在內(nèi)存中,有些使用率特別低,寧愿在使用的時候重新創(chuàng)建,在使用完畢后丟棄數(shù)據(jù),F(xiàn)rozen indices 的數(shù)據(jù)命中頻率小,不適用于高搜索負(fù)載,數(shù)據(jù)不會被保存在內(nèi)存中,堆空間占用比普通索引少得多,F(xiàn)rozen indices是只讀的,請求可能是秒級或者分鐘級。
- enable:是否創(chuàng)建倒排索引,可以對字段操作,也可以對索引操作,如果不創(chuàng)建索引,仍然可以檢索并在_source元數(shù)據(jù)中展示,謹(jǐn)慎使用,該狀態(tài)無法修改。enable的作用和index類似,區(qū)別就是enable可以對全局進(jìn)行設(shè)置。例如:
PUT my_index
{
"mappings": {
"enabled": false
}
}
- fielddata:查詢時內(nèi)存數(shù)據(jù)結(jié)構(gòu),在首次用當(dāng)前字段聚合、排序或者在腳本中使用時,需要字段為fielddata數(shù)據(jù)結(jié)構(gòu),并且創(chuàng)建倒排索引保存到堆中。
- fields:給field創(chuàng)建多字段,用于不同目的(全文檢索或者聚合分析排序)。
- format:格式化。例如:
"date": {
"type": "date",
"format": "yyyy-MM-dd"
}
- ignore_above:這是一個針對keyword類型字段的設(shè)置,對于超過指定長度的字符串,ES 不會對其建立索引。
- ignore_malformed:忽略類型錯誤。
- index_options:控制將哪些信息添加到反向索引中以進(jìn)行搜索和突出顯示。僅用于text字段。
- Index_phrases:提升 exact_value 查詢速度,但是要消耗更多磁盤空間。
- Index_prefixes:前綴搜索。
- min_chars:前綴最小長度> 0,默認(rèn) 2(包含)。
- max_chars:前綴最大長度< 20,默認(rèn) 5(包含)。
- meta:附加元數(shù)據(jù)。
- normalizer:normalizer 參數(shù)用于解析前(索引或者查詢時)的標(biāo)準(zhǔn)化配置。
- norms:是否禁用評分(在 filter 和聚合字段上應(yīng)該禁用)。
- null_value:為 null 值設(shè)置默認(rèn)值。
- position_increment_gap:對于數(shù)組或者列表類型的字段,在進(jìn)行phrase query或者phrase suggest時,允許用戶自定義同一字段內(nèi)兩個相鄰元素間的位置增量,默認(rèn)100。
- properties:除了mapping還可用于object的屬性設(shè)置。
- search_analyzer:設(shè)置單獨(dú)的查詢時分析器,如果定義了analyzer而沒有定義search_analyzer,則search_analyzer的值默認(rèn)會和analyzer保持一致,如果兩個都沒有定義,則默認(rèn)是:"standard"。analyzer針對的是元數(shù)據(jù),而search_analyzer針對的是傳入的搜索詞。
- similarity:為字段設(shè)置相關(guān)度算法,和評分有關(guān)。支持BM25、classic(TF-IDF)、boolean。
- store:設(shè)置字段是否僅查詢。
- term_vector:運(yùn)維參數(shù)。這個參數(shù)可以設(shè)置存儲哪些信息用于更復(fù)雜的文本處理,例如在詞向量建?;蛘吒鼜?fù)雜的文本檢索場景中使用。
五、Text & Keyword
1.Text
當(dāng)一個字段是要被全文檢索時,比如 Email 內(nèi)容、產(chǎn)品描述,這些字段應(yīng)該使用 text 類型。設(shè)置 text 類型以后,字段內(nèi)容會被分析,在生成倒排索引之前,字符串會被分析器分成一個個詞項。text類型的字段不用于排序,很少用于聚合。
注意事項:
- 適用于全文檢索:如 match 查詢。
- 文本字段會被分詞。
- 默認(rèn)情況下,會創(chuàng)建倒排索引。
- 自動映射器會為 Text 類型創(chuàng)建 Keyword 字段。
2.Keyword
Keyword 類型適用于不分詞的字段,如姓名、Id、數(shù)字等。如果數(shù)字類型不用于范圍查找,用 Keyword 的性能要高于數(shù)值類型。
當(dāng)使用 Keyword 類型查詢時,其字段值會被作為一個整體,并保留字段值的原始屬性。
GET index/_search
{
"query": {
"match": {
"title.keyword": "測試文本值"
}
}
}
注意事項:
- Keyword 不會對文本分詞,會保留字段的原有屬性,包括大小寫等。
- Keyword 僅僅是字段類型,而不會對搜索詞產(chǎn)生任何影響。
- Keyword 一般用于需要精確查找的字段,或者聚合排序字段。
- Keyword 通常和 Term 搜索一起用。
- Keyword 字段的 ignore_above 參數(shù)代表其截斷長度,默認(rèn) 256,如果超出長度,字段值會被忽略,而不是截斷,忽略指的是會忽略這個字段的索引,搜索不到,但數(shù)據(jù)還是存在的。
六、映射模板
之前講過的映射類型或者映射參數(shù),都是為確定的某個字段而聲明的。
但是當(dāng)我們不確定字段名字的時候該怎么設(shè)置mapping呢?映射模板就是用來解決這種場景的。
如果希望對符合某類要求的特定字段制定映射,就需要用到映射模板:Dynamic templates。映射模板有時也被稱作:自動映射模板、動態(tài)模板等。
以下是一個示例:
{
"mappings": {
"dynamic_templates": [
{
"strings_as_keyword": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
},
{
"longs_as_integer": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
}
]
}
}
在上述例子中,我們定義了兩個模板:strings_as_keyword 和 longs_as_integer。當(dāng)新字段被發(fā)現(xiàn)時,Elasticsearch 會檢查這些模板以決定如何映射這個新字段。
- strings_as_keyword 模板將所有新的字符串類型字段映射為 keyword 類型。
- longs_as_integer 模板將所有新的長整數(shù)(long)類型字段映射為 integer 類型。
注意:這些只是示例,實際的映射應(yīng)該取決于實際數(shù)據(jù)和查詢需求。例如,如果你需要對字符串字段進(jìn)行全文搜索,那么將其映射為 text 可能更合適。
1.參數(shù)
- match:匹配字段名稱。
- unmatch:反匹配字段名稱。
- match_mapping_type:匹配字段類型,例如 string、long、double、boolean、date。
- match_pattern:允許更復(fù)雜的名字模式,支持"starts_with"、"ends_with" 和 "contains"。
- path_match:允許你用路徑 (如 article.title) 來匹配字段。
- path_unmatch:反匹配路徑。
- mapping:該字段被匹配時,應(yīng)用的映射設(shè)置。
2.案例
PUT test_dynamic_template
{
"mappings": {
"dynamic_templates": [{
"integers": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"longs_as_strings": {
"match_mapping_type": "string",
"match": "num_*",
"unmatch": "*_text",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
以上代碼會產(chǎn)生以下效果:
- 所有 long 類型字段會默認(rèn)映射為 integer。
- 所有文本字段,如果是以 num_ 開頭,并且不以 _text 結(jié)尾,會自動映射為 keyword 類型。