Elasticsearch中每個field都對應一個數據類型. 本篇詳細介紹string、date、array、object、nested、geo等數據類型的作用及主要用法. 歡迎交流( ⊙ o ⊙ ) ...
目錄
說在前面: Elasticsearch中每個field都要精確對應一個數據類型.
本文的所有演示, 都是基於Elasticsearch 6.6.10進行的, 不同的版本可能存在API發生修改、不支持的情況, 還請註意.
1 核心數據類型
1.1 字元串類型 - string(不再支持)
(1) 使用示例:
PUT website
{
"mappings": {
"blog": {
"properties": {
"title": {"type": "string"}, // 全文本
"tags": {"type": "string", "index": "not_analyzed"} // 關鍵字, 不分詞
}
}
}
}
(2) ES 5.6.10中的響應信息:
#! Deprecation: The [string] field is deprecated, please use [text] or [keyword] instead on [tags]
#! Deprecation: The [string] field is deprecated, please use [text] or [keyword] instead on [title]
{
"acknowledged": true,
"shards_acknowledged": true,
"index": "website"
}
(3) ES 6.6.10中的響應信息:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "No handler for type [string] declared on field [title]"
}
],
"type": "mapper_parsing_exception",
"reason": "Failed to parse mapping [blog]: No handler for type [string] declared on field [title]",
"caused_by": {
"type": "mapper_parsing_exception",
"reason": "No handler for type [string] declared on field [title]"
}
},
"status": 400
}
可知string類型的field已經被移除了, 我們需要用text或keyword類型來代替string.
1.1.1 文本類型 - text
在Elasticsearch 5.4 版本開始, text取代了需要分詞的string.
—— 當一個欄位需要用於全文搜索(會被分詞), 比如產品名稱、產品描述信息, 就應該使用text類型.
text的內容會被分詞, 可以設置是否需要存儲:
"index": "true|false"
.
text類型的欄位不能用於排序, 也很少用於聚合.
使用示例:
PUT website
{
"mappings": {
"blog": {
"properties": {
"summary": {"type": "text", "index": "true"}
}
}
}
}
1.1.2 關鍵字類型 - keyword
在Elasticsearch 5.4 版本開始, keyword取代了不需要分詞的string.
—— 當一個欄位需要按照精確值進行過濾、排序、聚合等操作時, 就應該使用keyword類型.
keyword的內容不會被分詞, 可以設置是否需要存儲:
"index": "true|false"
.
使用示例:
PUT website
{
"mappings": {
"blog": {
"properties": {
"tags": {"type": "keyword", "index": "true"}
}
}
}
}
1.2 數字類型 - 8種
數字類型有如下分類:
類型 | 說明 |
---|---|
byte | 有符號的8位整數, 範圍: [-128 ~ 127] |
short | 有符號的16位整數, 範圍: [-32768 ~ 32767] |
integer | 有符號的32位整數, 範圍: [$-2^{31}$ ~ $2^{31}$-1] |
long | 有符號的32位整數, 範圍: [$-2^{63}$ ~ $2^{63}$-1] |
float | 32位單精度浮點數 |
double | 64位雙精度浮點數 |
half_float | 16位半精度IEEE 754浮點類型 |
scaled_float | 縮放類型的的浮點數, 比如price欄位只需精確到分, 57.34縮放因數為100, 存儲結果為5734 |
使用註意事項:
儘可能選擇範圍小的數據類型, 欄位的長度越短, 索引和搜索的效率越高;
優先考慮使用帶縮放因數的浮點類型.
使用示例:
PUT shop
{
"mappings": {
"book": {
"properties": {
"name": {"type": "text"},
"quantity": {"type": "integer"}, // integer類型
"price": {
"type": "scaled_float", // scaled_float類型
"scaling_factor": 100
}
}
}
}
}
1.3 日期類型 - date
JSON沒有日期數據類型, 所以在ES中, 日期可以是:
- 包含格式化日期的字元串, "2018-10-01", 或"2018/10/01 12:10:30".
- 代表時間毫秒數的長整型數字.
- 代表時間秒數的整數.
如果時區未指定, 日期將被轉換為UTC格式, 但存儲的卻是長整型的毫秒值.
可以自定義日期格式, 若未指定, 則使用預設格式:strict_date_optional_time||epoch_millis
(1) 使用日期格式示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"pub_date": {"type": "date"} // 日期類型
}
}
}
}
// 添加數據
PUT website/blog/11
{ "pub_date": "2018-10-10" }
PUT website/blog/12
{ "pub_date": "2018-10-10T12:00:00Z" } // Solr中預設使用的日期格式
PUT website/blog/13
{ "pub_date": "1589584930103" } // 時間的毫秒值
(2) 多種日期格式:
多個格式使用雙豎線
||
分隔, 每個格式都會被依次嘗試, 直到找到匹配的.
第一個格式用於將時間毫秒值轉換為對應格式的字元串.
使用示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"date": {
"type": "date", // 可以接受如下類型的格式
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
}
1.4 布爾類型 - boolean
可以接受表示真、假的字元串或數字:
- 真值: true, "true", "on", "yes", "1"...
- 假值: false, "false", "off", "no", "0", ""(空字元串), 0.0, 0
1.5 二進位型 - binary
二進位類型是Base64編碼字元串的二進位值, 不以預設的方式存儲, 且不能被搜索.
使用示例:
// 添加映射
PUT website
{
"mappings": {
"blog": {
"properties": {
"blob": {"type": "binary"} // 二進位
}
}
}
}
// 添加數據
PUT website/blog/1
{
"title": "Some binary blog",
"blob": "hED903KSrA084fRiD5JLgY=="
}
註意: Base64編碼的二進位值不能嵌入換行符
\n
.
1.6 範圍類型 - range
range類型支持以下幾種:
類型 | 範圍 |
---|---|
integer_range | $-2^{31}$ ~ $2^{31}-1$ |
long_range | $-2^{63}$ ~ $2^{63}-1$ |
float_range | 32位單精度浮點型 |
double_range | 64位雙精度浮點型 |
date_range | 64位整數, 毫秒計時 |
ip_range | IP值的範圍, 支持IPV4和IPV6, 或者這兩種同時存在 |
(1) 添加映射:
PUT company
{
"mappings": {
"department": {
"properties": {
"expected_number": { // 預期員工數
"type": "integer_range"
},
"time_frame": { // 發展時間線
"type": "date_range",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
},
"ip_whitelist": { // ip白名單
"type": "ip_range"
}
}
}
}
}
(2) 添加數據:
PUT company/department/1
{
"expected_number" : {
"gte" : 10,
"lte" : 20
},
"time_frame" : {
"gte" : "2018-10-01 12:00:00",
"lte" : "2018-11-01"
},
"ip_whitelist": "192.168.0.0/16"
}
(3) 查詢數據:
GET company/department/_search
{
"query": {
"term": {
"expected_number": {
"value": 12
}
}
}
}
GET company/department/_search
{
"query": {
"range": {
"time_frame": {
"gte": "208-08-01",
"lte": "2018-12-01",
"relation": "within"
}
}
}
}
查詢結果:
{
"took": 26,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 1.0,
"hits": [
{
"_index": "company",
"_type": "department",
"_id": "1",
"_score": 1.0,
"_source": {
"expected_number": {
"gte": 10,
"lte": 20
},
"time_frame": {
"gte": "2018-10-01 12:00:00",
"lte": "2018-11-01"
},
"ip_whitelist" : "192.168.0.0/16"
}
}
]
}
}
2 複雜數據類型
2.1 數組類型 - array
ES中沒有專門的數組類型, 直接使用[]定義即可;
數組中所有的值必須是同一種數據類型, 不支持混合數據類型的數組:
① 字元串數組: ["one", "two"];
② 整數數組: [1, 2];
③ 由數組組成的數組: [1, [2, 3]], 等價於[1, 2, 3];
④ 對象數組: [{"name": "Tom", "age": 20}, {"name": "Jerry", "age": 18}].
註意:
- 動態添加數據時, 數組中第一個值的類型決定整個數組的類型;
- 不支持混合數組類型, 比如[1, "abc"];
- 數組可以包含null值, 空數組[]會被當做missing field —— 沒有值的欄位.
2.2 對象類型 - object
JSON文檔是分層的: 文檔可以包含內部對象, 內部對象也可以包含內部對象.
(1) 添加示例:
PUT employee/developer/1
{
"name": "ma_shoufeng",
"address": {
"region": "China",
"location": {"province": "GuangDong", "city": "GuangZhou"}
}
}
(2) 存儲方式:
{
"name": "ma_shoufeng",
"address.region": "China",
"address.location.province": "GuangDong",
"address.location.city": "GuangZhou"
}
(3) 文檔的映射結構類似為:
PUT employee
{
"mappings": {
"developer": {
"properties": {
"name": { "type": "text", "index": "true" },
"address": {
"properties": {
"region": { "type": "keyword", "index": "true" },
"location": {
"properties": {
"province": { "type": "keyword", "index": "true" },
"city": { "type": "keyword", "index": "true" }
}
}
}
}
}
}
}
}
2.3 嵌套類型 - nested
嵌套類型是對象數據類型的一個特例, 可以讓array類型的對象被獨立索引和搜索.
2.3.1 對象數組是如何存儲的
① 添加數據:
PUT game_of_thrones/role/1
{
"group": "stark",
"performer": [
{"first": "John", "last": "Snow"},
{"first": "Sansa", "last": "Stark"}
]
}
② 內部存儲結構:
{
"group": "stark",
"performer.first": [ "john", "sansa" ],
"performer.last": [ "snow", "stark" ]
}
③ 存儲分析:
可以看出, user.first和user.last會被平鋪為多值欄位, 這樣一來, John和Snow之間的關聯性就丟失了.
在查詢時, 可能出現John Stark的結果.
2.3.2 用nested類型解決object類型的不足
如果需要對以最對象進行索引, 且保留數組中每個對象的獨立性, 就應該使用嵌套數據類型.
—— 嵌套對象實質是將每個對象分離出來, 作為隱藏文檔進行索引.
① 創建映射:
PUT game_of_thrones
{
"mappings": {
"role": {
"properties": {
"performer": {"type": "nested" }
}
}
}
}
② 添加數據:
PUT game_of_thrones/role/1
{
"group" : "stark",
"performer" : [
{"first": "John", "last": "Snow"},
{"first": "Sansa", "last": "Stark"}
]
}
③ 檢索數據:
GET game_of_thrones/_search
{
"query": {
"nested": {
"path": "performer",
"query": {
"bool": {
"must": [
{ "match": { "performer.first": "John" }},
{ "match": { "performer.last": "Snow" }}
]
}
},
"inner_hits": {
"highlight": {
"fields": {"performer.first": {}}
}
}
}
}
}
3 地理數據類型
3.1 地理點類型 - geo point
地理點類型用於存儲地理位置的經緯度對, 可用於:
- 查找一定範圍內的地理點;
- 通過地理位置或相對某個中心點的距離聚合文檔;
- 將距離整合到文檔的相關性評分中;
- 通過距離對文檔進行排序.
(1) 添加映射:
PUT employee
{
"mappings": {
"developer": {
"properties": {
"location": {"type": "geo_point"}
}
}
}
}
(2) 存儲地理位置:
// 方式一: 緯度 + 經度鍵值對
PUT employee/developer/1
{
"text": "小蠻腰-鍵值對地理點參數",
"location": {
"lat": 23.11, "lon": 113.33 // 緯度: latitude, 經度: longitude
}
}
// 方式二: "緯度, 經度"的字元串參數
PUT employee/developer/2
{
"text": "小蠻腰-字元串地理點參數",
"location": "23.11, 113.33" // 緯度, 經度
}
// 方式三: ["經度, 緯度"] 數組地理點參數
PUT employee/developer/3
{
"text": "小蠻腰-數組參數",
"location": [ 113.33, 23.11 ] // 經度, 緯度
}
(3) 查詢示例:
GET employee/_search
{
"query": {
"geo_bounding_box": {
"location": {
"top_left": { "lat": 24, "lon": 113 }, // 地理盒子模型的上-左邊
"bottom_right": { "lat": 22, "lon": 114 } // 地理盒子模型的下-右邊
}
}
}
}
3.2 地理形狀類型 - geo_shape
是多邊形的複雜形狀. 使用較少, 這裡省略.
可以參考這篇文章: Elasticsearch地理位置總結
4 專門數據類型
4.1 IP類型
IP類型的欄位用於存儲IPv4或IPv6的地址, 本質上是一個長整型欄位.
(1) 添加映射:
PUT employee
{
"mappings": {
"customer": {
"properties": {
"ip_addr": { "type": "ip" }
}
}
}
}
(2) 添加數據:
PUT employee/customer/1
{ "ip_addr": "192.168.1.1" }
(3) 查詢數據:
GET employee/customer/_search
{
"query": {
"term": { "ip_addr": "192.168.0.0/16" }
}
}
4.2 計數數據類型 - token_count
token_count類型用於統計字元串中的單詞數量.
本質上是一個整數型欄位, 接受並分析字元串值, 然後索引字元串中單詞的個數.
(1) 添加映射:
PUT employee
{
"mappings": {
"customer": {
"properties": {
"name": {
"type": "text",
"fields": {
"length": {
"type": "token_count",
"analyzer": "standard"
}
}
}
}
}
}
}
(2) 添加數據:
PUT employee/customer/1
{ "name": "John Snow" }
PUT employee/customer/2
{ "name": "Tyrion Lannister" }
(3) 查詢數據:
GET employee/customer/_search
{
"query": {
"term": { "name.length": 2 }
}
}
參考資料
版權聲明
作者: 馬瘦風
出處: 博客園 馬瘦風的博客
您的支持是對博主的極大鼓勵, 感謝您的閱讀.
本文版權歸博主所有, 歡迎轉載, 但請保留此段聲明, 併在文章頁面明顯位置給出原文鏈接, 否則博主保留追究相關人員法律責任的權利.