
本文案例操作,建議先閱讀我之前的文章《ElasticSearch之安裝及基本操作API》
Mapping (映射)類似關系型數據庫中的表的結構定義。我們將數據以 JSON 格式存入到 ElasticSearch 中后,在搜索引擎中 JSON 字段映射對應的類型,這時需要 mapping 來定義內容的類型。
字段類型
JSON 數據類型映射到 ElasticSearch 定義的類型,常用的簡單類型有:
| JSON類型 | ElasticSearch 類型 |
|---|---|
| 文本類型 | Text/Keyword |
| 整數類型 | long/integer |
| 浮點類型 | float/double |
| 時間類型 | date |
| 布爾值 | boolean |
| 數組 | Text/Keyword |
上面要注意的是時間類型,JSON 中並沒有時間類型,這里主要指時間格式數據的類型。
定義映射
在關系型數據庫中,存儲數據之前,我們會先創建表結構,給字段指定一個存在的類型。同樣 ElasticSearch 在進行數據存儲前,也可以先定義好存儲數據的 Mapping 結構。
先定義一個簡單的 person Mapping:

上圖中就是一個 Mapping 的定義,如果是在 ElasticSearch7 之前,mappings 里還有 _type 屬性。
動態映射
當沒有事先定義好 Mapping,添加數據時,ElasticSearch 會自動根據字段進行換算出對應的類型,但是換算出來的類型並不一定是我們想要的字段類型,還是需要人為的干預進行修改成想要的 Mapping。
更新映射
使用 dynamic 控制映射是否可以被更新。
dynamic-true
設置 dynamic 為true是默認 dynamic 的默認值,新增字段數據可以寫入,同時也可以被索引,Mapping 結構也會被更新。

添加數據,同時多添加一個沒被定義的 gender 字段。
# 向 person 中添加數據
PUT person/_doc/1
{
"uId": 1,
"name": "ytao",
"age": 18,
"address": "廣東省珠海市",
"birthday": "2020-01-15T12:00:00Z",
"money": 108.2,
"isStrong": true,
"gender": "男" # Mapping 中未定義的字段
}
添加成功,搜索 gender 字段:

查看 Mapping 結構:

新添加的字段值,在添加過程中 Mapping 已自動添加字段。
dynamic-false
設置 dynamic 為false時,新增字段數據可以寫入,不可以被索引,Mapping 結構會被更新。
同樣先將 dynamic 設置為 false,然后向里面添加數據,其他步驟和上面 true 操作一樣。定義 Mapping,添加數據。
搜索 gender 字段:

此時新增字段數據無法被索引,但數據可以寫入。

Mappnig 也不會添加新增的字段:

dynamic-strict
設置 dynamic 為strict時,從字面上意思也可以看出,對於動態映射是較嚴格的,新增字段數據不可以寫入,不可以被索引,Mapping 結構不會被更新。只能按照定義好的 Mapping 結構添加數據。
在添加新字段數據時,就馬上會拋出異常:

自動識別日期類型
上文中,當 dynamic 設置為 true 時,添加新字段數據自動識別類型更新 Mapping,如果是日期類型的話,我們是可以指定識別的類型。
指定 person 的 dynamic_date_formats 格式:
PUT person/_mapping
{
"dynamic_date_formats": ["yyyy/MM/dd"]
}
這里是可以指定多個時間格式。
向 person 添加新數據,分別是 today 和 firstDate:
PUT person/_doc/2
{
"today": "2020-01-15",
"firstDate": "2020/01/15"
}
添加新字段數據后的 Mapping:

由於上面我們指定了時間格式為 yyyy/MM/dd 時是可以識別為時間格式,所以 today 字段的值為 yyyy-MM-dd 格式無法識別為時間類型,判為 text 類型。
多字段
Mapping 中可以定義 fields 多字段屬性,以滿足不同場景下的實現。比如 address 定義為 text 類型,fields 里面又有定義 keyword 類型,這里主要是區分兩個不同不同使用場景。
text會建立分詞倒排索引,用於全文檢索。keyword不會建立分詞倒排索引,用於排序和聚合。
添加數據:
# 向 person 中添加數據
PUT person/_doc/1
{
"uId": 1,
"name": "ytao",
"age": 18,
"address": "廣東省珠海市",
"birthday": "2020-01-15T12:00:00Z",
"money": 108.2,
"isStrong": true
}
查詢address數據。

查詢address.keyword數據。

通過keyword檢索時,由於不會建立分詞索引,並沒有獲取到數據。
控制索引
在字段中使用 index 指定當前字段索引是否能被搜索到。指定類型為 boolean 類型,false 為不可搜索到,true 為可以搜索到。
先刪除之前的 Mapping:
DELETE person
創建 Mapping,設置name屬性的 index 為 false。

再次添加上面的數據后搜索name字段:

字段 index 設置 false 后,由於沒有被索引,所以搜索無法獲取到索引。
空值處理
現在向 ElasticSearch 中添加一條 address 為空的數據:
PUT person/_doc/2
{
"uId": 2,
"name": "Jack",
"age": 22,
"address": null,
"birthday": "2020-01-15T12:00:00Z",
"money": 68.7,
"isStrong": true
}
搜索 address.keyword 為空的數據:

搜索返回異常,默認是不被允許搜索 NUll。
這是需要在 Mapping 指定 null_value 屬性,並且不能在text類型中聲明。

搜索 address.keyword 為空的數據:

設置 "null_value": "NULL" 后,空值可以處理搜索。
聚合多個字段
聚合多個字段放到一個索引中,使用 copy_to 進行聚合。例如我們在多字段查詢中,這是不需要對每個字段進行過濾篩選,只需對聚合字段即可。
在使用 copy_to 時,是通過指定聚合的名稱實現。

實際上,copy_to 不使用數組格式添加名稱,也會自動轉換成數據格式。
添加兩條數據,待校驗搜索:
# 向 person 中添加數據
PUT person/_doc/1
{
"uId": 1,
"name": "ytao",
"age": 18,
"address": "廣東省珠海市",
"birthday": "2020-01-15T12:00:00Z",
"money": 108.2,
"isStrong": true
}
PUT person/_doc/2
{
"uId": 2,
"name": "楊廣東",
"age": 22,
"address": null,
"birthday": "2020-01-15T12:00:00Z",
"money": 68.7,
"isStrong": true
}
查詢 full_name 的值,會返回 name 和 address 相關的值的對象。

從上面返回結果看到,_source 中的字段沒有增加相應的 copy_to 字段名,所以 copy_to 只會拷貝字段內容至索引,並不會改變包含的字段。
總結
通過本文對創建 Mapping 文件的常用並且實用的操作介紹,也基本能掌握這些日常的使用。了解 Mapping 的功能操作,相信對存儲時的設計也有一定幫助。
個人博客: https://ytao.top
關注公眾號 【ytao】,更多原創好文

