ElasticSearch | 数据建模 | 最佳实践

建议一 | 如何处理关联关系

  • 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 进行管理;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

友情链接更多精彩内容