ElasticSearch 動態映射和靜態映射,以及四種字段類型

@[toc]
ElasticSearch 系列教程咱們前面已經連着發了三篇了,今天第四篇,咱們來聊一聊 Es 中的動態映射、靜態映射以及四種不一樣的字段類型。java

本文是鬆哥所錄視頻教程的一個筆記,筆記簡明扼要,完整內容小夥伴們能夠參考視頻,視頻下載連接:https://pan.baidu.com/s/1oKiV... 提取碼: p3sxgit

1.ElasticSearch 映射

映射就是 Mapping,它用來定義一個文檔以及文檔所包含的字段該如何被存儲和索引。因此,它其實有點相似於關係型數據庫中表的定義。github

1.1 映射分類

動態映射數據庫

顧名思義,就是自動建立出來的映射。es 根據存入的文檔,自動分析出來文檔中字段的類型以及存儲方式,這種就是動態映射。數組

舉一個簡單例子,新建一個索引,而後查看索引信息:app

image-20201106201219878

在建立好的索引信息中,能夠看到,mappings 爲空,這個 mappings 中保存的就是映射信息。性能

如今咱們向索引中添加一個文檔,以下:編碼

PUT blog/_doc/1
{
  "title":"1111",
  "date":"2020-11-11"
}

文檔添加成功後,就會自動生成 Mappings:es5

image-20201106201516427

能夠看到,date 字段的類型爲 date,title 的類型有兩個,text 和 keyword。spa

默認狀況下,文檔中若是新增了字段,mappings 中也會自動新增進來。

有的時候,若是但願新增字段時,可以拋出異常來提醒開發者,這個能夠經過 mappings 中 dynamic 屬性來配置。

dynamic 屬性有三種取值:

  • true,默認即此。自動添加新字段。
  • false,忽略新字段。
  • strict,嚴格模式,發現新字段會拋出異常。

具體配置方式以下,建立索引時指定 mappings(這其實就是靜態映射):

PUT blog
{
  "mappings": {
    "dynamic":"strict",
    "properties": {
      "title":{
        "type": "text"
      },
      "age":{
        "type":"long"
      }
    }
  }
}

而後向 blog 中索引中添加數據:

PUT blog/_doc/2
{
  "title":"1111",
  "date":"2020-11-11",
  "age":99
}

在添加的文檔中,多出了一個 date 字段,而該字段沒有預約義,因此這個添加操做就回報錯:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "strict_dynamic_mapping_exception",
        "reason" : "mapping set to strict, dynamic introduction of [date] within [_doc] is not allowed"
      }
    ],
    "type" : "strict_dynamic_mapping_exception",
    "reason" : "mapping set to strict, dynamic introduction of [date] within [_doc] is not allowed"
  },
  "status" : 400
}

動態映射還有一個日期檢測的問題。

例如新建一個索引,而後添加一個含有日期的文檔,以下:

PUT blog/_doc/1
{
  "remark":"2020-11-11"
}

添加成功後,remark 字段會被推斷是一個日期類型。

image-20201106203240406

此時,remark 字段就沒法存儲其餘類型了。

PUT blog/_doc/1
{
  "remark":"javaboy"
}

此時報錯以下:

{
  "error" : {
    "root_cause" : [
      {
        "type" : "mapper_parsing_exception",
        "reason" : "failed to parse field [remark] of type [date] in document with id '1'. Preview of field's value: 'javaboy'"
      }
    ],
    "type" : "mapper_parsing_exception",
    "reason" : "failed to parse field [remark] of type [date] in document with id '1'. Preview of field's value: 'javaboy'",
    "caused_by" : {
      "type" : "illegal_argument_exception",
      "reason" : "failed to parse date field [javaboy] with format [strict_date_optional_time||epoch_millis]",
      "caused_by" : {
        "type" : "date_time_parse_exception",
        "reason" : "Failed to parse with all enclosed parsers"
      }
    }
  },
  "status" : 400
}

要解決這個問題,可使用靜態映射,即在索引定義時,將 remark 指定爲 text 類型。也能夠關閉日期檢測。

PUT blog
{
  "mappings": {
    "date_detection": false
  }
}

此時日期類型就回當成文原本處理。

靜態映射

略。

1.2 類型推斷

es 中動態映射類型推斷方式以下:

JSON 中的數據 自動推斷出來的數據類型
null 沒有字段被添加
true/false boolean
浮點數字 float
數字 long
JSON 對象 object
數組 數組中的第一個非空值來決定
string text/keyword/date/double/long 都有可能

2.ElasticSearch 字段類型

2.1 核心類型

2.1.1 字符串類型

  • string:這是一個已通過期的字符串類型。在 es5 以前,用這個來描述字符串,如今的話,它已經被 text 和 keyword 替代了。
  • text:若是一個字段是要被全文檢索的,好比說博客內容、新聞內容、產品描述,那麼可使用 text。用了 text 以後,字段內容會被分析,在生成倒排索引以前,字符串會被分詞器分紅一個個詞項。text 類型的字段不用於排序,不多用於聚合。這種字符串也被稱爲 analyzed 字段。
  • keyword:這種類型適用於結構化的字段,例如標籤、email 地址、手機號碼等等,這種類型的字段能夠用做過濾、排序、聚合等。這種字符串也稱之爲 not-analyzed 字段。

2.1.2 數字類型

類型 取值範圍
long -2^63到2^63-1
integer -2^31到2^31-1
short -2^15到2^15-1
byte -2^7到2^7-1
double 64 位的雙精度 IEEE754 浮點類型
float 32 位的雙精度 IEEE754 浮點類型
half_float 16 位的雙精度 IEEE754 浮點類型
scaled_float 縮放類型的浮點類型
  • 在知足需求的狀況下,優先使用範圍小的字段。字段長度越短,索引和搜索的效率越高。
  • 浮點數,優先考慮使用 scaled_float。

scaled_float 舉例:

PUT product
{
  "mappings": {
    "properties": {
      "name":{
        "type": "text"
      },
      "price":{
        "type": "scaled_float",
        "scaling_factor": 100
      }
    }
  }
}

2.1.3 日期類型

因爲 JSON 中沒有日期類型,因此 es 中的日期類型形式就比較多樣:

  • 2020-11-11 或者 2020-11-11 11:11:11
  • 一個從 1970.1.1 零點到如今的一個秒數或者毫秒數。

es 內部將時間轉爲 UTC,而後將時間按照 millseconds-since-the-epoch 的長整型來存儲。

自定義日期類型:

PUT product
{
  "mappings": {
    "properties": {
      "date":{
        "type": "date"
      }
    }
  }
}

這個可以解析出來的時間格式比較多。

PUT product/_doc/1
{
  "date":"2020-11-11"
}

PUT product/_doc/2
{
  "date":"2020-11-11T11:11:11Z"
}


PUT product/_doc/3
{
  "date":"1604672099958"
}

上面三個文檔中的日期均可以被解析,內部存儲的是毫秒計時的長整型數。

2.1.4 布爾類型(boolean)

JSON 中的 「true」、「false」、true、false 均可以。

2.1.5 二進制類型(binary)

二進制接受的是 base64 編碼的字符串,默認不存儲,也不可搜索。

2.1.6 範圍類型

  • integer_range
  • float_range
  • long_range
  • double_range
  • date_range
  • ip_range

定義的時候,指定範圍類型便可:

PUT product
{
  "mappings": {
    "properties": {
      "date":{
        "type": "date"
      },
      "price":{
        "type":"float_range"
      }
    }
  }
}

插入文檔的時候,須要指定範圍的界限:

PUT product
{
  "mappings": {
    "properties": {
      "date":{
        "type": "date"
      },
      "price":{
        "type":"float_range"
      }
    }
  }
}

指定範圍的時,可使用 gt、gte、lt、lte。

2.2 複合類型

2.2.1 數組類型

es 中沒有專門的數組類型。默認狀況下,任何字段均可以有一個或者多個值。須要注意的是,數組中的元素必須是同一種類型。

添加數組是,數組中的第一個元素決定了整個數組的類型。

2.2.2 對象類型(object)

因爲 JSON 自己具備層級關係,因此文檔包含內部對象。內部對象中,還能夠再包含內部對象。

PUT product/_doc/2
{
  "date":"2020-11-11T11:11:11Z",
  "ext_info":{
    "address":"China"
  }
}

2.2.3 嵌套類型(nested)

nested 是 object 中的一個特例。

若是使用 object 類型,假若有以下一個文檔:

{
  "user":[
    {
      "first":"Zhang",
      "last":"san"
    },
    {
      "first":"Li",
      "last":"si"
    }
    ]
}

因爲 Lucene 沒有內部對象的概念,因此 es 會將對象層次扁平化,將一個對象轉爲字段名和值構成的簡單列表。即上面的文檔,最終存儲形式以下:

{
"user.first":["Zhang","Li"],
"user.last":["san","si"]
}

扁平化以後,用戶名之間的關係沒了。這樣會致使若是搜索 Zhang si 這我的,會搜索到。

此時能夠 nested 類型來解決問題,nested 對象類型能夠保持數組中每一個對象的獨立性。nested 類型將數組中的每一餓對象做爲獨立隱藏文檔來索引,這樣每個嵌套對象均可以獨立被索引。

{
{
"user.first":"Zhang",
"user.last":"san"
},{
"user.first":"Li",
"user.last":"si"
}
}

優勢

文檔存儲在一塊兒,讀取性能高。

缺點

更新父或者子文檔時須要更新更個文檔。

2.3 地理類型

使用場景:

  • 查找某一個範圍內的地理位置
  • 經過地理位置或者相對中心點的距離來聚合文檔
  • 把距離整個到文檔的評分中
  • 經過距離對文檔進行排序

2.3.1 geo_point

geo_point 就是一個座標點,定義方式以下:

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

建立時指定字段類型,存儲的時候,有四種方式:

PUT people/_doc/1
{
  "location":{
    "lat": 34.27,
    "lon": 108.94
  }
}

PUT people/_doc/2
{
  "location":"34.27,108.94"
}

PUT people/_doc/3
{
  "location":"uzbrgzfxuzup"
}

PUT people/_doc/4
{
  "location":[108.94,34.27]
}

注意,使用數組描述,先經度後緯度。

地址位置轉 geo_hash:http://www.csxgame.top/#/

2.3.2 geo_shape

GeoJSON ElasticSearch 備註
Point point 一個由經緯度描述的點
LineString linestring 一個任意的線條,由兩個以上的點組成
Polygon polygon 一個封閉多邊形
MultiPoint multipoint 一組不連續的點
MultiLineString multilinestring 多條不關聯的線
MultiPolygon multipolygon 多個多邊形
GeometryCollection geometrycollection 幾何對象的集合
circle 一個圓形
envelope 經過左上角和右下角兩個點肯定的矩形

指定 geo_shape 類型:

PUT people
{
  "mappings": {
    "properties": {
      "location":{
        "type": "geo_shape"
      }
    }
  }
}

添加文檔時須要指定具體的類型:

PUT people/_doc/1
{
  "location":{
    "type":"point",
    "coordinates": [108.94,34.27]
  }
}

若是是 linestring,以下:

PUT people/_doc/2
{
  "location":{
    "type":"linestring",
    "coordinates": [[108.94,34.27],[100,33]]
  }
}

2.4 特殊類型

2.4.1 IP

存儲 IP 地址,類型是 ip:

PUT blog
{
  "mappings": {
    "properties": {
      "address":{
        "type": "ip"
      }
    }
  }
}

添加文檔:

PUT blog/_doc/1
{
  "address":"192.168.91.1"
}

搜索文檔:

GET blog/_search
{
  "query": {
    "term": {
      "address": "192.168.0.0/16"
    }
  }
}

2.4.2 token_count

用於統計字符串分詞後的詞項個數。

PUT blog
{
  "mappings": {
    "properties": {
      "title":{
        "type": "text",
        "fields": {
          "length":{
            "type":"token_count",
            "analyzer":"standard"
          }
        }
      }
    }
  }
}

至關於新增了 title.length 字段用來統計分詞後詞項的個數。

添加文檔:

PUT blog/_doc/1
{
  "title":"zhang san"
}

能夠經過 token_count 去查詢:

GET blog/_search
{
  "query": {
    "term": {
      "title.length": 2
    }
  }
}

最後,鬆哥還蒐集了 50+ 個項目需求文檔,想作個項目練練手的小夥伴不妨看看哦~



需求文檔地址:https://github.com/lenve/javadoc

相關文章
相關標籤/搜索