ElasticSearch實戰三(分詞和對映)
ElasticSearch的文件對映機制(mapping)用於進行欄位的型別確認,將每一個欄位匹配為一種確定的資料型別。
1 ES欄位型別
① 基本欄位型別
字串:text、keyword
text預設為全文文字,keyword預設為非全文文字
數字:long、integer、short、double、float
日期:date
邏輯:boolean
② 複雜資料型別
物件型別:object
陣列型別:array
地理位置:geo_point,geo_shape
我們在建立一個索引的時候,欄位並沒有明確說明屬於哪一個型別的資料,但是ES會根據預設的規則去匹配相應的資料型別的。下面的id,name,birthday,salary,set表示了不同型別的資料結構。
PUT /crm/user/1 { "id":1, "name":"gosaint", "birthday":"2018-11-03", "salary":1000.890, "sex":true }
2 預設對映
檢視索引型別的對映配置:GET {indexName}/_mapping/{typeName}
ES在沒有配置Mapping的情況下新增文件,ES會嘗試對欄位型別進行猜測,並動態生成欄位和型別的對映關係。
JSON type |
Field type |
Boolean: true or false |
"boolean" |
Whole number: 123 |
"long" |
Floating point: 123.45 |
"float" |
String, valid date:"2014-09-15" |
"date" |
String: "foo bar" |
"string" |
針對上述的例項,我們可以使用GET /crm/_mapping/user來檢視資料的資料型別;
birthday:date
id : long
name:text。全文文字,預設會分詞。
salary:flaot
sex :boolean
{
"crm": {
"mappings": {
"user": {
"properties": {
"birthday": {
"type": "date"
},
"id": {
"type": "long"
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"salary": {
"type": "float"
},
"sex": {
"type": "boolean"
}
}
}
}
}
}
3 簡單型別對映
type |
型別:基本資料型別,integer,long,date,boolean,keyword,text... |
enable |
是否啟用:預設為true。 false:不能索引、不能搜尋過濾,僅在_source中儲存 |
boost |
權重提升倍數:用於查詢時加權計算最終的得分。 |
format |
格式:一般用於指定日期格式,如 yyyy-MM-dd HH:mm:ss.SSS |
ignore_above |
長度限制:長度大於該值的字串將不會被索引和儲存。 |
ignore_malformed |
轉換錯誤忽略:true代表當格式轉換錯誤時,忽略該值,被忽略後不會被儲存和索引。 |
include_in_all |
是否將該欄位值組合到_all中。 |
null_value |
預設控制替換值。如空字串替換為”NULL”,空數字替換為-1 |
store |
是否儲存:預設為false。true意義不大,因為_source中已有資料 |
index |
索引模式:analyzed (索引並分詞,text預設模式), not_analyzed (索引不分詞,keyword預設模式),no(不索引) |
analyzer |
索引分詞器:索引建立時使用的分詞器,如ik_smart,ik_max_word,standard |
search_analyzer |
搜尋分詞器:搜尋該欄位的值時,傳入的查詢內容的分詞器。 |
fields |
多欄位索引:當對該欄位需要使用多種索引模式時使用。 如:城市搜尋New York "city": { "type": "text", "analyzer": "ik_smart", "fields": { "raw": { "type": "keyword" } } } 那麼以後搜尋過濾和排序就可以使用city.raw欄位名 |
4 自定義型別對映
在上述的例項中,ES預設已經為相關的欄位指定型別。因此我們不可能改變原來欄位的型別。如我們不能去修改id的型別為integer。但是對於追加的欄位還是可以指定型別對映的。
① 針對單個型別的對映配置方式
POST {indexName}/{typeName}/_mapping
{
"{typeName}": {
"properties": {
"id": {
"type": "long"
},
"content": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer": "ik_smart"
}
}
}
}
POST /crm/user/_mapping
{
"user": {
"properties": {
"id": {
"type": "integer"
},
"name":{
"type":"keyword"
},
"birthday":{
"type":"text"
},
"salary":{
"type":"double"
},
"sex":{
"type":"boolean"
}
}
}
}
看看響應結果:
{
"error": {
"root_cause": [
{
"type": "illegal_argument_exception",
"reason": "mapper [name] of different type, current_type [text], merged_type [keyword]"
}
],
"type": "illegal_argument_exception",
"reason": "mapper [name] of different type, current_type [text], merged_type [keyword]"
},
"status": 400
}
這恰好說明,原來的欄位對映存在,再次指定的時候就會失敗。如果要想重新指派,那麼就要刪除原來的索引庫。
刪除crm索引庫。DELETE /crm。然後建立crm PUT /crm。然後執行上述的自定義指派對映。
{
"crm": {
"mappings": {
"user": {
"_all": {
"enabled": false
},
"dynamic_templates": [
{
"string_as_text": {
"match": "*_text",
"match_mapping_type": "string",
"mapping": {
"analyzer": "ik_max_word",
"fields": {
"raw": {
"ignore_above": 256,
"type": "keyword"
}
},
"search_analyzer": "ik_max_word",
"type": "text"
}
}
},
{
"string_as_keyword": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
],
"properties": {
"birthday": {
"type": "text"
},
"id": {
"type": "integer"
},
"name": {
"type": "keyword"
},
"salary": {
"type": "double"
},
"sex": {
"type": "boolean"
}
}
}
}
}
}
可以看到我們自定義對映成功啦。
② 同時對多個型別的對映配置方式(推薦)
PUT {indexName}
{
"mappings": {
"user": {
"properties": {
"id": {
"type": "integer"
},
"info": {
"type": "text",
"analyzer": "ik_smart",
"search_analyzer"
}
}
},
"dept": {
"properties": {
"id": {
"type": "integer"
},
....更多欄位對映配置
}
}
}
}
5 全域性對映
全域性對映可以通過動態模板和預設設定兩種方式實現。
預設方式:_default_
索引下所有的型別對映配置會繼承_default_的配置,如:
PUT {indexName}
{
"mappings": {
"_default_": {
"_all": {
"enabled": false
}
},
"user": {},
"dept": {
"_all": {
"enabled": true
}
}
}
}
上例中:user和dept都會繼承_default_的配置,user型別的文件中將不會合並所有欄位到_all,而dept會。
動態模板:dynamic_templates
注意:ES會預設把string型別的欄位對映為text型別(預設使用標準分詞器)和對應的keyword型別,如:
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
在實際應用場景中,一個物件的屬性中,需要全文檢索的欄位較少,大部分字串不需要分詞,因此,需要利用全域性模板覆蓋自帶的預設模板:
PUT _template/global_template //建立名為global_template的模板
{
"template": "*", //匹配所有索引庫
"settings": { "number_of_shards": 1 }, //匹配到的索引庫只建立1個主分片
"mappings": {
"_default_": {
"_all": {
"enabled": false //關閉所有型別的_all欄位
},
"dynamic_templates": [
{
"string_as_text": {
"match_mapping_type": "string",//匹配型別string
"match": "*_text", //匹配欄位名字以_text結尾
"mapping": {
"type": "text",//將型別為string的欄位對映為text型別
"analyzer": "ik_max_word",
"search_analyzer": "ik_max_word",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
},
{
"string_as_keyword": {
"match_mapping_type": "string",//匹配型別string
"mapping": {
"type": "keyword"//將型別為string的欄位對映為keyword型別
}
}
}
]
}
}}
說明:上例中定義了兩種動態對映模板string_as_text和string_as_keyword.
在實際的型別欄位對映時,會依次匹配:
①欄位自定義配置
②全域性dynamic_templates[string_as_text、string_as_keyword]、
③索引dynamic_templates[...]
④ES自帶的string型別對映,以最先匹配上的為準。
注意:索引庫在建立的時候會繼承當前最新的dynamic_templates,索引庫建立後,修改動態模板,無法應用到已存在的索引庫。
6 最佳實踐
對映的配置會影響到後續資料的索引過程,因此,在實際專案中應遵循如下順序規則:
① 配置全域性動態模板對映(覆蓋預設的string對映)
② 配置欄位對映(由於基本型別主要用於過濾和普通查詢,因此,欄位對映主要對需要全文檢索的欄位進行配置)
③ 建立、更新和刪除文件
④ 搜尋