Elasticsearch 7.x 映射(Mapping)中的字段類型

1 概念
Elasticsearch的映射用來定義一個索引中的文檔如何被存儲,定義一個映射類似於定義一個Mongo DB集合,在Elasticsearch 7.x中,映射和索引是一對一的關係。映射分爲靜態映射和動態映射,前者需要用戶手動定義,後者則直接在向一個未生成的索引添加文檔的時候自動生成。

1.1 動態映射
用戶嘗試向一個不存在的索引添加文檔時,Elasticsearch會新建該索引並根據該文檔字段的特性生成一個動態映射,其推斷的字段映射類型和JSON文檔字段類型的關係如下:

JSON類型    動態映射推斷的映射類型
null    沒有字段被添加,即不填加該映射
布爾型(true或者false)    boolean類型
浮點類型數字    單精度浮點型(float類型)
數字    長整型(long類型)
內嵌對象    object類型
數組    由數組的第一個非null值決定
字符串類型    根據字符串內容特徵而定,有可能爲text/keyword/double/long/date類型等
例如向Elasticsearch索引test-index添加以下文檔:

{
  "id": 1,
  "name": "Trump",
  "height": 180.52,
  "man": true,
  "country": "USA",
  "born": "1946-6-14",
  "child": ["Donald John Trump", "Ivana Marie Trump", "Eric Frederick Trump"]
}



此時查詢動態映射信息:

GET /test-index/_mapping
{
  "test-index" : {
    "mappings" : {
      "properties" : {
        "born" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "child" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "country" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "height" : {
          "type" : "float"
        },
        "id" : {
          "type" : "long"
        },
        "man" : {
          "type" : "boolean"
        },
        "name" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        }
      }
    }
  }
}



其中id被推測爲long類型,height被推測爲float類型,man推測爲boolean類型,其餘字段爲text類型。

1.2 靜態映射
靜態映射是用戶在創建索引時手動指定映射,定義各個字段的屬性,類似於MySQL的建表操作。
用戶可以通過Rest API的PUT方法定義一個索引的映射,例如:

PUT test-index
{
  "mappings": {
    "properties": {
      "born": {
        "type": "text", 
        "fields": {
          "keyword": {
            "type": "keyword", 
            "ignore_above": 256
          }
        }
      }, 
      "child": {
        "type": "text", 
        "fields": {
          "keyword": {
            "type": "keyword", 
            "ignore_above": 256
          }
        }
      }, 
      "country": {
        "type": "text", 
        "fields": {
          "keyword": {
            "type": "keyword", 
            "ignore_above": 256
          }
        }
      }, 
      "height": {
        "type": "float"
      }, 
      "id": {
        "type": "long"
      }, 
      "man": {
        "type": "boolean"
      }, 
      "name": {
        "_all": {
          "enabled": false
        }, 
        "type": "text", 
        "fields": {
          "keyword": {
            "type": "keyword", 
            "ignore_above": 256
          }
        }
      }
    }
  }
}



2 字段類型
Elasticsearch字段類型類似於MySQL中的字段類型。Elasticsearch字段類型主要有:核心類型、複合類型、地理類型、特殊類型。

2.1 核心類型
核心類型可以劃分爲字符串類型、數字類型、日期類型、布爾類型、基於BASE64的二進制類型、範圍類型:

類型    具體類型
字符串類型    text、keyword
數字類型    long、integer、short、byte、double、float、half_float、scaled_float
日期類型    date、date_nanos
布爾類型    boolean
二進制類型    binary
範圍類型    range
字符串類型
Elasticsearch 7.x有兩種字符串類型:text和keyword,在Elasticsearch 5.x之後string類型已經不再支持。

text
text類型適用於需要被全文檢索的字段,例如新聞正文、郵件內容等比較長的文字。text類型會被Lucene分詞器(Analyzer)處理爲一個個詞項,並使用Lucene倒排索引存儲。text字段不能被用於排序。如果需要使用該類型的字段只需要在定義映射時指定JSON中對應字段的type爲text。
keyword
keyword適合簡短、結構化字符串,例如主機名、姓名、商品名稱等,可以用於過濾、排序、聚合檢索,也可以用於精確查詢。
數字類型
數字類型分爲long、integer、short、byte、double、float、half_float、scaled_float,其範圍如下:

long,−263-2^{63}−2 
63
  到 263−12^{63} - 12 
63
 −1
integer,−231-2^{31}−2 
31
  到 231−12^{31} - 12 
31
 −1
short,−32768-32768−32768 到 327673276732767
byte,−128-128−128 到 127127127
double,IEEE 754標準雙精度浮點類型,8字節
float,IEEE 754標準單精度浮點類型,4字節
half_float,IEEE 754標準半精度浮點類型,2字節
scaled_float,縮放類型浮點類型


數字類型的字段在滿足需求的前提下應當儘量選擇範圍較小的數據類型,字段長度越短,搜索效率越高。對於浮點數,可以優先考慮使用scaled_float類型,該類型可以通過縮放因子來精確浮點數,12.34可以轉換爲1234來存儲。

日期類型
在Elasticsearch中日期可以爲以下形式:

格式化的日期字符串,例如2019-01-01 00:00、2019/01/01
時間戳(和1970-01-01 00:00:00 UTC的差值),單位毫秒或者秒
即使是格式化的日期字符串,Elasticsearch底層依然採用的是時間戳的形式存儲。

布爾類型
JSON文檔中同樣存在布爾類型,不過JSON字符串類型也可以被Elasticsearch轉換爲布爾類型存儲,前提是字符串的取值爲"true"或者"false"。布爾類型常用於檢索中的過濾條件。

二進制類型
二進制類型binary接受BASE64編碼的字符串,默認store屬性爲false,並且不可以被搜索。

範圍類型
範圍類型可以用來表達一個數據的區間,可以分爲5種:

integer_range,可以表示最大的範圍爲 [−231,231−1][-2^{31},2^{31}-1][−2 
31
 ,2 
31
 −1]
float_range,可以表達IEEE754單精度浮點數範圍
long_range,可以表示最大的範圍爲 [−263,263−1][-2^{63},2^{63}-1][−2 
63
 ,2 
63
 −1]
double_range,可以表達IEEE754雙精度浮點數範圍
date_range,可以表達64位時間戳(單位毫秒)範圍。
如果需要使用範圍類型,同樣需要手動定義映射,例如定義一個date_range的映射:

{
  "mappings": {
    "properties": {
      "time_area": {
        "type": "date_range",
        "format": "yyyy-MM-dd HH:mm:ss"
      }
    }
  }
}


然後添加一份文檔:

{
  "time_area": {
    "gte": "2019-11-10 00:00:00",
    "lte": "2019-11-11 15:00:00"
  }
}


gte爲區間最小值,lte爲區間最大值。

2.2 複合類型
複合類型主要有array、object、nested

數組類型
因爲Lucene底層並不真正支持數組類型,所以自然Elasticsearch也沒有專用的數組類型。對於文檔中的數組而言,每個元素必須是同一種類型。例如:[1,2,3]、["a","b","c"]、[{"name":"Trump"},{"name":"Smith"}]是合法的。

之前提到動態映射會以數組的第一個元素的類型來決定整個數組的類型,如果是空數組,那麼會當成null來處理,即忽略該數組字段,不會創建該字段的映射。

object類型
JSON字符串允許嵌套對象,一個文檔可以嵌套多個、多層對象。可以通過object類型來存儲二級文檔,不過由於Lucene並沒有內部對象的概念,Elasticsearch會將原JSON文檔扁平化,例如文檔:

{
    "name": {
        "first": "Donald",
        "last": "Trump"
    }
}



實際上Elasticsearch會將其轉換爲以下格式,並通過Lucene存儲,即使name是object類型:

{
    "name.first": "Donald",
    "name.last": "Trump"
}



對應的動態映射爲:

{
  "mappings": {
    "properties": {
      "name": {
        "properties": {
          "first": {"type":"text"},
          "last": {"type":"text"}
        }
      }
    }
  }
}



nested類型
nested類型可以看成是一個特殊的object類型,可以讓對象數組獨立檢索。例如文檔:

{
  "group": "a group",
  "member": [
    { "first": "Donald", "last": "Trump"},
    { "first": "Barack", "last": "Obama"},
    { "first": "William", "last": "Clinton"}
  ]
}



member字段是一個JSON數組,並且每個數組對象都是一個JSON對象。如果將member設置爲object類型,那麼Elasticsearch會將其轉換爲:

{
  "group": "a group",
  "member.first": ["Donald", "Barack", "William"],
  "member.last": ["Trump", "Obama", "Clinton"]
}



可以看出轉換後的JSON文檔中first和last的關聯丟失了,如果嘗試搜索first爲Donald,last爲Obama的文檔,那麼成功會檢索出上述文檔,但是Donald和Obama在原JSON文檔中並不屬於同一個JSON對象,應當是不匹配的,即檢索不出任何結果。nested類型就是爲了解決這種問題的。nested類型將數組中的每個JSON對象作爲獨立的隱藏文檔來存儲,每個嵌套的對象都能夠獨立地被搜索,所以上述案例中雖然表面上只有1個文檔,但實際上是存儲了4個文檔。
將member字段改爲nested後,檢索first爲Donald,last爲Obama的文檔是就會提示不存在。

2.3 地理類型
地理類型字段分爲兩種:經緯度類型和地理區域類型。

經緯度類型
經緯度類型字段(geo_point)可以存儲經緯度相關信息。通過地理類型的字段,可以用來實現諸如查找在指定地理區域內相關的文檔、根據距離排序、根據地理位置修改評分規則等需求。

如果需要使用到經緯度類型,需要手動定義映射:

{
  "mappings": {
    "properties": {
      "location": {
        "type": "geo_point"
      }
    }
  }
}


geo_point接收以下地理位置數據:

經緯度鍵值對,lat爲緯度,lon爲經度

{
  "location": {
    "lat": 30.0,
    "lon": -50.0
  }
}



用逗號分割的字符串,前者爲緯度,後者爲經度
{
  "location": "30.0,-50.0"
}

數組形式座標
{
  "location": [30.0,-50.0]
}

地理區域類型
經緯度類型可以表達一個點,而geo_shape類型可以表達一塊地理區域,區域的形狀可以是任意多邊形,也可以是點、線、面、多點、多線、多面等幾何類型。GeoJSON一種表達地理區域的編碼規範,具體可參考文檔 《Geo格式規範說明》。

2.4 特殊類型
IP類型
IP類型的字段可以用來存儲IPv4或者IPv6地址,如果需要存儲IP類型的字段,需要手動定義映射:

{
  "mappings": {
    "properties": {
      "my_ip": {
        "type": "ip"
      }
    }
  }
}



然後添加文檔:

{
  "my_ip": "10.0.0.1"
}

join類型
join類型是Elasticsearch 6.x引入的類型,以取代淘汰的_parent元字段。用來實現文檔的一對一、一對多的關係。
join類型的Mapping如下:

PUT my_index
{
  "mappings": {
    "properties": {
      "my_join_field": { 
        "type": "join",
        "relations": {
          "question": "answer" 
        }
      }
    }
  }
}



my_join_field爲join類型字段的名稱
relations指定關係:question是answer的父類
例如定義一個ID爲1父文檔:

PUT my_join_index/1?refresh
{
  "text": "This is a question",
  "my_join_field": "question" 
}

接下來定義一個子文檔:

PUT my_join_index/_doc/3?routing=1&refresh 
{
  "text": "This is an answer",
  "my_join_field": {
    "name": "answer", 
    "parent": "1" 
  }
}



該文檔指定了父文檔ID爲1。

更多特殊類型
參考官方文檔

3 元字段
元字段是映射中描述文檔本身的字段,所有的元字段類型都以下劃線開頭,元字段可以分爲:

文檔屬性的元字段

字段名    作用
_index    文檔所屬的索引
_type    文檔類型,在ES 7以上版本中類型已被廢棄,所以該值一律爲_doc
_id    文檔唯一ID
源文檔的元字段

字段名    作用
_source    文檔原始JSON字符串
_size    _source字段的大小
索引的元字段

字段名    作用
_all    包含索引全部字段的超級字段
_field_names    文檔中包含非空值的所有字段
路由的元字段

字段名    作用
_routing    將文檔路由到特定分片的自定義路由值
自定義元字段:meta,用於自定義元數據。

3.1 _index字段
_index字段爲文檔所在的索引名稱,它是一個虛擬字段,並不會實際存儲在Lucene索引中。利用該字段可以用來執行多索引查詢,可以通過_index進行term查詢、聚合查詢、terms查詢等,但不支持prefix、regexp、fuzzy、wildcard查詢。

terms查詢示例如下:

GET index1,index2/_serach
{
  "query": {
    "terms": {
      "_index": ["index1", "index2"]
    }
  },
  "aggs": {
    "indices": {
      "terms": {
        "field": "_index",
        "size": 10
      }
    }
  },
  "sort": [{"_index": {"order": "asc"}}]
}



3.2 _id和_type字段
每條被索引的文檔都有一個_type字段和_id字段。前者爲類型字段,後者爲ID字段,用來標識唯一的在Elasticsearch 5.X版本以前,每個索引可以建立多個類型,到Elasticsearch 6.X後,只能建立一個類型,到7.X之後類型概念被取消,_type字段統一爲_doc。

_id字段用於標識索引中唯一的文檔,可以用於term、terms、match、query_string、simple_query_string查詢,不能用於聚合、腳本和排序。

3.3 _source字段
_source存儲文檔的原始JSON字符串,update、update_by_query、重建索引、高亮關鍵字、索引數據備份、修改mapping等一系列操作都需要用到_source。雖然可以在定義mapping時不存儲_source,不過最好不要這麼做。

3.4 _all字段
_all字段是一個把文檔中其它字段拼接在一起之後的字段,使用空格分隔,_all字段會被解析和索引但是不會存儲。_all字段典型的用途就是在不知道具體字段的前提下,查找包含某個關鍵字的文檔,例如:

GET index1/_search
{
  "query": {
    "match": {
      "_all": "apple"
    }
  }
}


3.5 _field_names字段
_field_names存儲文檔中所有非空字段的名字,常用於檢索存在某個指定字段的文檔:

GET index1/_search
{
  "query": {
    "match": {
      "_field_names": "name"
    }
  }
}



上述示例是查詢出具有name字段的文檔。

3.6 _routing
Elasticsearch通過以下公式來計算文檔應該分配到哪個分片上:
shard_num = hash(_routing) % num_primary_shards

默認的_routing值是文檔的_id字段,指定_routing參數可以設置自定義路由,例如:

PUT my_index/_doc/1?routing=user1&refresh=true 
{
  "title": "This is a document"
}



上述示例中指定routing爲user1
————————————————
版權聲明:本文爲CSDN博主「A__Plus」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/abc123lzf/article/details/102957060

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章