ElasticSearch | 数据建模 | 最佳实践
2020-06-01 本文已影响0人
乌鲁木齐001号程序员
建议一 | 如何处理关联关系
- Object - 优先考虑 Denomalization;
- Nested Object - 当数据包含多数值对象(多个演员),同时有查询需求;
- Child / Parent - 关联文档更新非常频繁时;
Kibana
- Kibana 目前暂不支持 Nested Object 和 Parent / Child 类型,在未来有可能支持;
- 如果需要使用 Kibana 进行数据分析,在数据建模时,仍需要对 Nested Object 和 Parent / Child 类型做出取舍;
建议二 | 避免过多字段
- 一个文档中,最好避免大量的字段;
- 过多的字段数不容易维护;
- Mapping 信息保存在 Cluster State 中,数据量过大,对集群性能会有影响(Cluster State 信息需要和所有节点同步);
- 删除或修改数据需要 Reindex;
- 默认最大字段数是 1000,可以设置 index.mapping.total_field.limit 限定最大字段数;
什么情况会导致成百上千的字段?
- 索引的 Mapping 的 dynamic 设置成了 true;随着新文档的写入,新文档有新字段,Mapping 中记录的索引的字段数就越来越多,引发 Mapping 文件膨胀的问题;
- 解决方案:Nested Object & Key Value;
Dynamic 的取值
- true - 未知字段会被自动加入
- false - 新字段不会被索引,但是会保存在 _source 中;
- strict - 新增字段不会被索引,也不会保存在 _source 中,文档写入失败;
使用 Nested Object & Key Value 解决字段过多的问题 | 示例
-
cookies
字段的type
设置成nested
; - 然后可以在 cookie 字段中设置不同类型的数据,它们以 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
}
]
}
- 使用 Nested Object & Key Value 的形式存储多字段,查询要这么查;
POST cookie_service/_search
{
"query": {
"nested": {
"path": "cookies",
"query": {
"bool": {
"filter": [
{
"term": {
"cookies.name": "age"
}
},
{
"range":{
"cookies.intValue":{
"gte":30
}
}
}
]
}
}
}
}
}
使用 Nested Object & Key Value 解决字段过多的问题 | 弊端
- 导致查询语句复杂度增加;
- Nested 对象,不利于在 Kibana 中实现可视化分析;
建模建议三 | 避免正则查询
- 正则,通配符查询,前缀查询都属于 Term 查询,但是性能不够好;
- 特别是将通配符放在开头,会导致性能的灾难;
案例 | 查寻所有版本是 7.1 开头的 ElasticSearch 信息
- 比如文档中有字段形如:
"version":"7.1.1"
; - 可以把字符串转换成对象;
# 在Mapping中加入元信息,便于管理
PUT softwares/
{
"mappings": {
"_meta": {
"software_version_mapping": "1.0"
}
}
}
GET softwares/_mapping
PUT softwares/_doc/1
{
"software_version":"7.1.0"
}
DELETE softwares
# 优化,使用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"
}
}
}
}
}
}
建议四 | 避免空值引起的聚合不准
空值引起的聚合不准 | 案例
- 聚合出来的平均值是 5,不对;
PUT ratings/_doc/1
{
"rating":5
}
PUT ratings/_doc/2
{
"rating":null
}
POST ratings/_search
POST ratings/_search
{
"size": 0,
"aggs": {
"avg": {
"avg": {
"field": "rating"
}
}
}
}
解决方案
-
"null_value": 1.0
将空值设置成 1;
DELETE ratings
PUT ratings
{
"mappings": {
"properties": {
"rating": {
"type": "float",
"null_value": 1.0
}
}
}
}
为索引的 Mapping 加入 Meta 信息
- Mapping 设置非常重要,需要从两个维度进行考虑;
- 功能:搜索、聚合、排序;
- 性能:存储的开销、内存的开销、搜索的性能;
- Mapping 设置是一个迭代的过程
- 加入新的字段很容易(必要时需要 update_by_query);
- 更新 / 删除字段是不允许的,需要 Reindex 重建数据;
- 最好能对 Mapping 加入 meta 信息,更好的进行版本管理;
- 可以考虑将 Mapping 文件上传 git 进行管理;