- Object : 優先考慮 Denormailzation
- Nested : 當資料包含多數值物件(對個演員),同時有查詢需求
- Child/Parent: 關聯文件更新非常頻繁時
- Kibana 目前暫不支援 nested 型別 和 parent / child 型別,在未來有可能會支援
- 如果需要使用 Kibana 進行資料分析,在資料建模時仍需要對巢狀和父子關聯型別作出取捨
- 一個文件中,最好避免大量的欄位
- 過多的欄位數不容易維護
- Mapping 資訊儲存在 Cluster State 中, 資料量過大,對叢集效能會有影響(Cluster State 資訊需要和所有的節點同步)
- 刪除或者修改資料需要 reindex
- 預設最大欄位數是1000,可以設定
index.mapping.total_fields.limit
限制最大的欄位數
- 什麼原因會導致文件中會有成百上千的欄位?
- Dynamic (生產環境中,儘量不要開啟 Dynamic)
- true - 未知欄位會被自動加入
- false - 新欄位不會被索引,但是會儲存在 _source
- strict - 新增欄位不會被索引,文件寫入失敗
- Strict
一個例子: Cookie Service 的資料
- 來自 Cookie Service 的資料
- Cookie 的鍵值對很多
- 當 Dynamic 設定為 True
- 同時採用扁平化的設計,必然導致欄位數量的膨脹
##索引資料,dynamic mapping 會不斷加入新增欄位
PUT cookie_service/_doc/1
{
"url":"www.google.com",
"cookies":{
"username":"tom",
"age":32
}
}
PUT cookie_service/_doc/2
{
"url":"www.amazon.com",
"cookies":{
"login":"2019-01-01",
"email":"xyz@abc.com"
}
}
GET cookie_service/_mapping
解決方案: Nested Object & Key Value
PUT cookie_service
{
"mappings": {
"properties": {
"cookies": {
"type": "nested",
"properties": {
"name": {
"type": "keyword"
},
"dateValue": {
"type": "date"
},
"keywordValue": {
"type": "keyword"
},
"IntValue": {
"type": "integer"
}
}
},
"url": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
寫入 & 查詢
PUT cookie_service/_doc/1
{
"url":"www.google.com",
"cookies":[
{
"name":"username",
"keywordValue":"tom"
},
{
"name":"age",
"intValue":32
}
]
}
PUT cookie_service/_doc/2
{
"url":"www.amazon.com",
"cookies":[
{
"name":"login",
"dateValue":"2019-01-01"
},
{
"name":"email",
"IntValue":32
}
]
}
# Nested 查詢,通過bool查詢進行過濾
POST cookie_service/_search
{
"query": {
"nested": {
"path": "cookies",
"query": {
"bool": {
"filter": [
{
"term": {
"cookies.name": "age"
}},
{
"range":{
"cookies.intValue":{
"gte":30
}
}
}
]
}
}
}
}
}
通過 Nested 物件儲存 Key / Value 的一些不足
- 可以減少欄位數量,解決 Cluster State 中 儲存過多 Meta 資訊的問題,但是
- 導致查詢語句複雜度增加
- Nested 物件 ,不利於在 Kibana 彙總實現視覺化分析
- 問題:
- 正則,萬用字元查詢,字首查詢屬於 Term 查詢,但是效能不夠好
- 特別是將萬用字元放在開頭,會導致效能的災難
- 案例:
- 文件中某個欄位包含了 ES 的版本資訊,例如 version:“7.1.0”
- 搜尋所有是 bug fix 的版本?每個主要版本號所關聯的文件?
GET softwares/_mapping
PUT softwares/_doc/1
{
"software_version":"7.1.0"
}
解決方案:將字串轉換為物件
# 優化,使用inner object
PUT softwares/
{
"mappings": {
"_meta": {
"software_version_mapping": "1.1"
},
"properties": {
"version": {
"properties": {
"display_name": {
"type": "keyword"
},
"hot_fix": {
"type": "byte"
},
"marjor": {
"type": "byte"
},
"minor": {
"type": "byte"
}
}
}
}
}
}
#通過 Inner Object 寫入多個文件
PUT softwares/_doc/1
{
"version": {
"display_name": "7.1.0",
"marjor": 7,
"minor": 1,
"hot_fix": 0
}
}
PUT softwares/_doc/2
{
"version": {
"display_name": "7.2.0",
"marjor": 7,
"minor": 2,
"hot_fix": 0
}
}
PUT softwares/_doc/3
{
"version": {
"display_name": "7.2.1",
"marjor": 7,
"minor": 2,
"hot_fix": 1
}
}
搜尋過濾
# 通過 bool 查詢,
POST softwares/_search
{
"query": {
"bool": {
"filter": [
{
"match": {
"version.marjor": 7
}
},
{
"match": {
"version.minor": 2
}
}
]
}
}
}
PUT ratings
{
"mappings": {
"properties": {
"rating": {
"type": "float",
"null_value": 1.0
}
}
}
}
PUT ratings/_doc/1
{
"rating": 5
}
PUT ratings/_doc/2
{
"rating": null
}
使用 Null_Value 解決空值的問題
POST ratings/_search
{
"size": 0,
"aggs": {
"avg": {
"avg": {
"field": "rating"
}
}
}
}
POST ratings/_search
{
"query": {
"term": {
"rating": {
"value": 1
}
}
}
}
- Mappings 設定非常重要,需要從兩個維度進行考慮
- 功能:索引,聚合,排序
- 效能:儲存的開銷,記憶體的開銷,搜尋的效能
- Mappings 設定是一個迭代的過程
- 加入新的欄位容易(必要時需要 update_by_query)
- 更新刪除欄位不允許(需要Reindex 重建資料)
- 最好能對 Mappings 加入 Meta 資訊,更好的進行版本管理
- 可以考慮 Mapping 檔案上傳 git 進行管理
PUT softwares/
{
"mappings": {
"_meta": {
"software_version_mapping": "1.0"
}
}
}
本作品採用《CC 協議》,轉載必須註明作者和本文連結