elasticsearch mappings之dynamic的三種狀態
一般的,mapping
則又可以分為動態對映(dynamic mapping)和靜態(顯示)對映(explicit mapping)和精確(嚴格)對映(strict mappings),具體由dynamic
屬性控制。
動態對映(dynamic:true)
現在有這樣的一個索引:
PUT m1 { "mappings": { "doc":{ "properties": { "name": { "type": "text" }, "age": { "type": "long" } } } } }
通過GET m1/_mapping
看一下mappings
資訊:
{ "m1" : { "mappings" : { "doc" : { "dynamic" : "true", "properties" : { "age" : { "type" : "long" }, "name" : { "type" : "text" } } } } } }
新增一些資料,並且新增一個sex
PUT m1/doc/1 { "name": "小黑", "age": 18, "sex": "不詳" }
當然,新的欄位查詢也沒問題:
GET m1/doc/_search { "query": { "match": { "sex": "不詳" } } }
返回結果:
{ "took" : 1, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 },"hits" : { "total" : 1, "max_score" : 0.5753642, "hits" : [ { "_index" : "m1", "_type" : "doc", "_id" : "1", "_score" : 0.5753642, "_source" : { "name" : "小黑", "age" : 18, "sex" : "不詳" } } ] } }
現在,一切都很正常,跟elasticsearch自動建立時一樣。那是因為,當 Elasticsearch 遇到文件中以前未遇到的欄位,它用動態對映來確定欄位的資料型別並自動把新的欄位新增到型別對映。我們再來看mappings
你就明白了:
{ "m1" : { "mappings" : { "doc" : { "dynamic" : "true", "properties" : { "age" : { "type" : "long" }, "name" : { "type" : "text" }, "sex" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } }
通過上例可以發下,elasticsearch幫我們新增了一個sex
的對映。所以。這一切看起來如此自然。這一切的功勞都要歸功於dynamic
屬性。我們知道在關係型資料庫中,欄位建立後除非手動修改,則永遠不會更改。但是,elasticsearch預設是允許新增新的欄位的,也就是dynamic:true
。
其實建立索引的時候,是這樣的:
PUT m1 { "mappings": { "doc":{ "dynamic":true, "properties": { "name": { "type": "text" }, "age": { "type": "long" } } } } }
上例中,當dynamic
設定為true
的時候,elasticsearch
就會幫我們動態的新增對映屬性。也就是等於啥都沒做!
這裡有一點需要注意的是:mappings
一旦建立,則無法修改。因為Lucene生成倒排索引後就不能改了。
靜態對映(dynamic:false)
現在,我們將dynamic
值設定為false
:
PUT m2 { "mappings": { "doc":{ "dynamic":false, "properties": { "name": { "type": "text" }, "age": { "type": "long" } } } } }
現在再來測試一下false
和true
有什麼區別:
PUT m2/doc/1 { "name": "小黑", "age":18 } PUT m2/doc/2 { "name": "小白", "age": 16, "sex": "不詳" }
第二條資料相對於第一條資料來說,多了一個sex
屬性,我們以sex
為條件來查詢一下:
GET m2/doc/_search { "query": { "match": { "sex": "不詳" } } }
結果如下:
{ "took" : 0, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "skipped" : 0, "failed" : 0 }, "hits" : { "total" : 0, "max_score" : null, "hits" : [ ] } }
結果是空的,也就是什麼都沒查詢到,那是為什呢?來GET m2/_mapping
一下此時m2
的mappings
資訊:
{ "m2" : { "mappings" : { "doc" : { "dynamic" : "false", "properties" : { "age" : { "type" : "long" }, "name" : { "type" : "text" } } } } } }
可以看到elasticsearch並沒有為新增的sex
建立對映關係。所以查詢不到。
當elasticsearch察覺到有新增欄位時,因為dynamic:false
的關係,會忽略該欄位,但是仍會儲存該欄位。
在有些情況下,dynamic:false
依然不夠,所以還需要更嚴謹的策略來進一步做限制。
嚴格模式(dynamic:strict)
讓我們再建立一個mappings
,並且將dynamic
的狀態改為strict
:
PUT m3 { "mappings": { "doc": { "dynamic": "strict", "properties": { "name": { "type": "text" }, "age": { "type": "long" } } } } }
現在,新增兩篇文件:
PUT m3/doc/1 { "name": "小黑", "age": 18 } PUT m3/doc/2 { "name": "小白", "age": 18, "sex": "不詳" }
第一篇文件新增和查詢都沒問題。但是,當新增第二篇文件的時候,你會發現報錯了:
{ "error": { "root_cause": [ { "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [sex] within [doc] is not allowed" } ], "type": "strict_dynamic_mapping_exception", "reason": "mapping set to strict, dynamic introduction of [sex] within [doc] is not allowed" }, "status": 400 }
錯誤提示,嚴格動態對映異常!說人話就是,當dynamic:strict
的時候,elasticsearch如果遇到新欄位,會丟擲異常。
小結:
動態對映(dynamic:true):動態新增新的欄位(或預設)。
靜態對映(dynamic:false):忽略新的欄位。在原有的對映基礎上,當有新的欄位時,不會主動的新增新的對映關係,只作為查詢結果出現在查詢中。
嚴格模式(dynamic: strict):如果遇到新的欄位,就丟擲異常。