Elasticsearch 數據建模的一些建議

如何處理關聯關係

clipboard.png

  • Kibana 目前暫時不支持 nested 類型和 parent/child 類型 ,在未來有可能會支持,在Kibana界面上展示數據的時候不是很友好
  • 如果需要使用Kibana進行數據分析,在建模時需要對嵌套和父子類型進行取捨

避免過多字段

  1. 過多字段不好維護
  2. Mapping信息保存在Cluster State中,數據量過大,對集羣性能有影響(Cluster State信息需要和所有節點同步)
  3. 刪除或者修改數據需要reindex.
  4. 默認最大字段數是 1000,可以設置 index.mapping.total_fields.limt 限定最大字段數
  5. 生產環境儘量不要打開Dynamic Dynamic Mapping
  • 考慮下這樣一個場景,
##索引數據,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":"[email protected]"
 }
}

我們的cookie字段使用了Dynamic=true默認值,所以隨着寫入的數據越來越多,如果不對cookies字段的子字段進行限制的話,字段數會越來越多,會影響性能,

  • 解決方案
#使用 Nested 對象,增加key/value
PUT cookie_service
{
  "mappings": {
    "dynamic": "strict",
    "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
          }
        }
      }
    }
  }
}

需要說明幾點的是:

  • 設置"dynamic": "strict"阻止其他字段加入
  • 通過name和dateValue, keywordValue, IntValue這樣的設計可以存儲任意的key-value

避免正則查詢

正則查詢的性能不夠好,前綴查詢屬於Term查詢

  • 案例如下:

文檔中某個字段包含了Elasticsearch的版本信息,例如version: "7.1.0",現在我們需要查詢朱版本是7,次要版本是2的文檔,不要使用正則查詢

  • 解決方案如下: 我們使用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"
          }
        }
      }
    }
  }
}

然後我們再使用查詢

POST softwares/_search
{
  "query": {
    "bool": {
      "filter": [
        {
          "match":{
            "version.marjor":7
          }
        },
        {
          "match":{
            "version.minor":2
          }
        }

      ]
    }
  }
}

避免空值引起的聚合不準

  • 首先我們先看一下示例
PUT ratings/_doc/1
{
 "rating":5
}
PUT ratings/_doc/2
{
 "rating":null
}

POST ratings/_search
{
  "size": 0,
  "aggs": {
    "avg": {
      "avg": {
        "field": "rating"
      }
    }
  }
}

# 查詢結果
{
  "took" : 1,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg" : {
      "value" : 5.0
    }
  }
}

很明顯,我們查到了兩條數據,但是平均值是5,這個很難以理解,

  • 解決方案,我們給null值設置一個默認值
PUT ratings
{
  "mappings": {
    "properties": {
      "rating": {
        "type": "float",
        "null_value": 0
      }
    }
  }
}

再次插入上面的數據,我們得到下面的結果

{
  "took" : 5,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 2,
      "relation" : "eq"
    },
    "max_score" : null,
    "hits" : [ ]
  },
  "aggregations" : {
    "avg" : {
      "value" : 2.5
    }
  }
}

這樣就比較對了,當然null_value的值是可以自己根據業務需求自己設定的

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