文章目录
- 数据建模简介
- ES数据建模配置相关介绍
- Mapping字段的相关设置
- Mapping字段属性的设定流程
- 是何种类型?
- 是否需要检索
- 是否需要排序和聚合分析
- 是否需要另行存储?
- ES数据建模实例
- Nested_Object
- 关联关系处理
- 关联关系处理之Nested Object
- Parent_Child
- nested_vs_parent_child
- reindex
- Reindex-_update_by_query
- Reindex-_reindex
- Reindex-Task
- 其他建议
- 防止字段过多
- key/value的方式详解
- 防止字段过多
数据建模简介
数据建模
·英文为Data Modeling ,为创建数据模型的过程
·数据模型( Data Model )
- 对现实世界进行抽象描述的一种工具和方法
- 通过抽象的实体及实体之间联系的形式去描述业务规则,从而实现对现实世界的映射
数据建模的过程
.概念模型
- 确定系统的核心需求和范围边界,设计实体和实体间的关系
·逻辑模型
- 进一步梳理业务需求,确定每个实体的属性、关系和约束等
·物理模型
- 结合具体的数据库产品,在满足业务读写性能等需求的前提下确定最终的定义
- mysql,MongoDB,elasticsearch等
- 第三范式
数据建模的意义
ES数据建模配置相关介绍
ES是基于Lucene以倒排索引为基础实现的存储体系,不遵循关系型数据库中的范式约定
Mapping字段的相关设置
enabled
- true | false
- 仅存储,不做搜索或聚合分析
. index
index_options
- docs | freqs I positions | offsets
- 存储倒排索引的哪些信息
norms
- true | false
- 是否存储归一化相关参数,如果字段仅用于过滤和聚合分析,可关闭
doc values
- true | false
- 是否启用doc values ,用于排序和聚合分析
field data
- false I true
- 是否为text类型启用fielddata ,实现排序和聚合分析
store
coerce
- true l false
- 是否开启自动数据类型转换功能,比如字符串转为数字、浮点转为整型等
multifields多字段
dynamic
- true | false | strict
- 控制mapping自动更新
date_detection
Mapping字段属性的设定流程
是何种类型?
·字符串类型
- 需要分词则设定为text类型,否则设置为keyword类型
·枚举类型
- 基于性能考虑将其设定为keyword类型,即便该数据为整型
·数值类型
- 尽量选择贴近的类型,比如byte即可表示所有数值时,即选用byte ,不要用long
·其他类型
是否需要检索
完全不需要检索、排序、聚合分析的字段
不需要检索的字段
需要检索的字段,可以通过如下配置设定需要的存储粒度
- index-options结合需要设定
- norms不需要归一化数据时关闭即可
是否需要排序和聚合分析
不需要排序或者聚合分析功能
- doc values设定为false
- fielddata设定为false
是否需要另行存储?
是否需要专门存储当前字段的数据?
- store设定为true ,即可存储该字段的原始内容(与_source中的不相关)
- 一般结合_source的enabled设定为false时使用
ES数据建模实例
·博客文章 blog_index
- 标题title
- 发布日期publish-date
- 作者author
- 摘要abstract
- 网络地址url
blog_index的mapping设置如下:
加了一个字段:
博客文章 blog_index
- 标题title
- 发布日期publish-date
- 作者author
- 摘要abstract
- 内容 content(非常大)
- 网络地址url
blog_index的mapping设置如下(都加了store:true专门存储每个字段原始值;不存入_source中了):
查询不返回content
Nested_Object
关联关系处理
.ES不擅长处理关系型数据库中的关联关系,比如文章表blog与评论表comment之间通过blogid关联,在ES中可以通过如下两种手段变相解决
- Nested Object
- Parent/Child
·评论Comment
- 文章Id blog-id
- 评论人username
- 评论日期date
- 评论内容content
关系型数据库中的设计:
关联关系处理之Nested Object
ES中的设计:
问题:查询结果不是预期的
Comments默认是Object Array ,存储结构类似下面的形式:
Nested Object可以解决这个问题:
再次进行查询即是我们想要的结果:
Nested Object Array的存储结构类似下面的形式:可以解决这个问题
Parent_Child
ES还提供了类似关系数据库中join的实现方式,使用join数据类型实现
关联关系处理之Parent/Child
常见 query语法包括如下几种:
- parent_id返回某父文档的子文档
- has_child返回包含某子文档的父文档
- has_parent返回包含某父文档的子文档
-parent_id返回某父文档的子文档
-has_child返回包含某子文档的父文档
-has_parent返回包含某父文档的子文档
nested_vs_parent_child
reindex
指重建所有数据的过程,一般发生在如下情况:
- mapping设置变更,比如字段类型变化、分词器字典更新等
- index设置变更,比如分片数更改等
- 迁移数据
ES提供了现成的API用于完成该工作
- update-by.query在现有索引上重建
- _reindex在其他索引上重建
Reindex-_update_by_query
https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update-by-query.html
Reindex-_reindex
Reindex-Task
数据重建的时间受源索引文档规模的影响,当规模越大时,所需时间越多,此时需要通过设定url参数wait_for_completion为false来异步执行, ES以task来描述此类执行任务.
ES提供了Task API来查看任务的执行进度和相关数据
其他建议
对Mapping进行版本管理
- 包含在代码或者以专门的文件进行管理,添加注释,并加入Git等版本管理仓库中,方便回顾
- 为每个增加一个metadata字段,在其中维护一些文档相关的元数据,方便对数据进行管理
防止字段过多
·字段过多主要有如下的坏处:
- 难于维护,当字段成百上千时,基本很难有人能明确知道每个字段的含义
- mapping的信息存储在cluster state里面,过多的字段会导致mapping过大,最终导致更新变慢
·通过设置index.mapping.total_fields.limit可以限定索引中最大字段数,默认是1000
·可以通过key/value的方式解决字段过多的问题,但并不完美
key/value的方式详解
设置变化
字段会变少:
查询会变得复杂:
虽然通过这种方式可以极大地减少Field数目,但也有一些明显的坏处
- query语句复杂度飙升,且有一些可能无法实现,比如聚合分析相关的
- 不利于在Kibana中做可视化分析
防止字段过多
·一般字段过多的原因是由于没有高质量的数据建模导致的,比如dynamic设置为true
·考虑拆分多个索引来解决问题