1. 什么是数据建模?

  • 数据建模,是创建数据模型的过程
    • 数据模型,是抽象描述现实世界的一种工具和方法,是通过抽象的实体及实体之间联系的形式,用图形化的形式区描述业务规则的过程,从而表示现实世界中事务的相互关系的一种映射。
      • 实体可以分为事物实体和概念实体。例如:一个学生、一个程序员等是事物实体。一门课、一个班级等称为概念实体。
      • 实体的属性:每个实体都有自己的特征。例如:学生实体的属性为姓名、性别、年龄等。

2. 数据建模的过程?

数据建模大致分为三个阶段,概念建模阶段,逻辑建模阶段和物理建模阶段。

2.1 概念建模阶段

概念建模阶段,主要做三件事:

  • 客户交流
  • 理解需求
  • 形成实体

确定系统的核心需求和范围边界,设计实体与实体之间的关系。

在概念建模阶段,我们只需要关注实体即可,不用关注任何实现细节。很多人都希望在这个阶段把具体表结构,索引,约束,甚至是存储过程都想好,没必要!因为这些东西使我们在物理建模阶段需要考虑的东西,这个时候考虑还为时尚早。
概念模型在整个数据建模时间占比:10%左右。

2.2 逻辑建模阶段

逻辑建模阶段,主要做二件事:

  • 进一步梳理业务需求,
  • 确定每个实体的属性、关系和约束等。

逻辑模型是对概念模型的进一步分解和细化,描述了实体、实体属性以及实体之间的关系,是概念模型延伸,一般的逻辑模型有第三范式,星型模型和雪花模型。模型的主要元素为主题、实体、实体属性和关系。

逻辑模型的作用主要有两点。

  • 一是便于技术开发人员和业务人员或者用户进行沟通 交流,使得整个概念模型更易于理解,进一步明确需求。
  • 二是作为物理模型设计的基础,由于逻辑模型不依赖于具体的数据库实现,使用逻辑模型可以生成针对具体 数据库管理系统的物理模型,保证物理模型充分满足用户的需求。 逻辑模型在整个数据建模时间占比:60%—70%左右。

2.3 物理建模阶段

物理建模阶段,主要做一件事:

  • 结合具体的数据库产品(mysql/oracle/mongo/elasticsearch),在满足业务读写性能等需求的前提下确定最终的定义。

物理模型是在逻辑模型的基础上描述模型实体的细节,包括数据库产品对应的数据类型、长度、索引等因素,为逻辑模型选择一个最有的物理存储环境。

逻辑模型转化为物理模型的过程也就是实体名转化为表名,属性名转化为物理列名的过程。
在设计物理模型时,还需要考虑数据存储空间的分配,包括对列属性必须做出明确的定义。
物理模型在整个数据建模时间占比:20%—30%左右。

例如:客户姓名的数据类型是 varchar2,长度是20,存储在 Oracle 数据库中,并且建立索引用于提高该字段的查询效率。

一个好的数据模型:

  • 能让系统更好的集成、能简化接口。
  • 能简化数据冗余、减少磁盘空间、提升传输效率。
  • 兼容更多的数据,不会因为数据类型的新增而导致实现逻辑更改。
  • 能帮助更多的业务机会,提高业务效率。
  • 能减少业务风险、降低业务成本。

    举例: 借助logstash实现mysql到Elasticsearch的增量同步,如果数据建模阶段没有设计:时间戳或者自增ID,就几乎无法实现。

3. 如何对ES进行数据建模?

image.png

4. 如何对 ES 索引进行建模?

Elasticsearch 让索引的建模变的非常简单,当我们向 Elasticsearch 索引一条数据时,只是简单地把 JSON 文本放在请求体里,至于 JSON 里的 field 类型,存储到 ES 里是什么类型,中间是怎么做的映射,这些都不用关注,ES 自动就帮我们把索引创建出来了。

但随着数据量的增加,我们开始有了索引优化和搜索优化的需求之后,就会发现自动创建的索引在某些方面不能非常完美的适应我们的需求,我们开始考虑手动创建适合我们业务需求的索引。

而这些索引模型优化的工作可以通过设置 index mapping 配置来完成。

4.1 配置ES Mapping进行索引建模

image.png

  • 字段类型

    • Text
      • 用于全文本字段,文本会被 Analyzer 分词;
      • 默认不支持聚合分析及排序。需要设置 fielddata 为 true;
    • keyword
      • 用于 id,枚举及不需要分词的文本。例如电话号码,email 地址,手机号码,邮政编码,性别等;
      • 适用于 Filter(精确匹配),排序,聚合分析;
    • 设置多字段类型
      • 默认会为文本类型设置成 text,并且设置一个 keyword 的子字段;
      • 在处理人类语言时,通过增加 英文、拼音、标准 分词器,提高搜索结构;
    • 数值类型
      • 尽量先择贴近的类型。例如可以用 byte,就不要用 long;
    • 枚举类型
      • 设置为 keyword。即便是数字,页应该设置成 keyword,获取更好的性能;
    • 其他
      • 日期 / 布尔 / 地理信息
  • 检索

    • 如不需要检索,排序,聚合分析
      • Enable :false
    • 如不需要检索,支持 Terms 聚合
      • Index:false
    • 对需要检索的字段,可以通过如下配置,设定存储粒度
      • Index_options / Norms
  • 聚合及排序

    • 如不需要检索,排序,聚合分析
      • Enable:false
    • 如不需要排序,聚合分析
      • Doc_values / fielddata : false
    • 更新频繁,聚合查询频繁的 keyword 类型的字段
      • 推荐将 eager_global_ordinals : true
  • 额外的存储

    • 是否需要专门存储当前字段数据
      • Store:true,可以存储该字段的原始内容;
      • 一般结合 _source 的 enabled:false 时候使用
    • Disable _source:节约磁盘;适用于指标型数据
      • 一般建议先考虑增加压缩比
      • 无法看到 _source 字段,无法做 Reindex,无法做 Update;
      • Kibana 中无法做 discovery

4.2 一个数据建模的实例

通过具体的实例,解析上面的 ES Mapping 索引建模流程。

假设我们需要索引一本图书的信息(书名、简介、作者、发行日期、图书封面):

  1. # Index 一本书的信息
  2. PUT books/_doc/1
  3. {
  4. "title":"Mastering ElasticSearch 5.0",
  5. "description":"Master the searching, indexing, and aggregation features in ElasticSearch Improve users’ search experience with Elasticsearch’s functionalities and develop your own Elasticsearch plugins",
  6. "author":"Bharvi Dixit",
  7. "public_date":"2017",
  8. "cover_url":"https://images-na.ssl-images-amazon.com/images/I/51OeaMFxcML.jpg"
  9. }

ES 会自动为索引建模,为我们自动创建 Mapping:

#查询自动创建的Mapping
GET books/_mapping

{
  "books" : {
    "mappings" : {
      "properties" : {
        "author" : {
          ...
        },
        "cover_url" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "description" : {
            ...
        },
        "public_date" : {
          ...
        },
        "title" : {
          ...
        }
      }
    }
  }
}

优化字段设定
实际场景中,不推荐自动创建Mapping,应该像数据库那样,根据需求提前设计好表的结构和字段类型大小,提高性能,节省空间;

  • 确定字段类型

    • 图书的索引
      • 书名:支持全文和精确匹配,text & keyword;
      • 简介:支持全文,text;
      • 作者:精确值,keyword;
      • 发行日期:日期类型,date;
      • 图书封面:精确值,keyword;
      • 图书内容:支持搜索,高亮显示,text;
  • 是否需要搜索和聚合以及排序

    • 图书的索引
      • 图书封面:不支持搜索,支持 Term 聚合,index:false;
  • 是否需要禁止 _source 以及打开 store

    • 图书的索引
      • _source:false、每个字段中 store:true;
        • 图书内容过大,会导致 _source 的内容过大
        • Source Filtering 只是传输给客户端时进行过滤,Fetch 数据时,ES 节点还是会传输 _source 中的数据(无法执行 update 操作) ```json DELETE books PUT books { “mappings” : { “_source”: {“enabled”: false}, “properties” : { “author” : {“type” : “keyword”,”store”: true}, “cover_url” : {“type” : “keyword”,”index”: false,”store”: true}, “description” : {“type” : “text”,”store”: true}, “content” : {“type” : “text”,”store”: true}, “public_date” : {“type” : “date”,”store”: true}, “title” : { “type” : “text”, “fields” : {
           "keyword" : {
             "type" : "keyword",
             "ignore_above" : 100
           }
          
          }, “store”: true
          }
          
          } } }

Index 一本书的信息,包含Content

PUT books/_doc/1 { “title”:”Mastering ElasticSearch 5.0”, “description”:”Master the searching, indexing, and aggregation features in ElasticSearch Improve users’ search experience with Elasticsearch’s functionalities and develop your own Elasticsearch plugins”, “content”:”The content of the book……Indexing data, aggregation, searching. something else. something in the way…………”, “author”:”Bharvi Dixit”, “public_date”:”2017”, “cover_url”:”https://images-na.ssl-images-amazon.com/images/I/51OeaMFxcML.jpg“ }

查询结果中,不包含 _source 数据

POST books/_search


:::tips
由于图书内容过大,为了解决查询中字段过大引发的性能问题,禁止了 _source,在返回结果中不再包含 _source 文档源数据,那么要如何查询图书呢?

- 对需要显示的信息,可以在查询中指定 "stored_fields";
- 禁止 _source 字段后,还是支持使用 highlights API,高亮显示 content 中的匹配的信息;
```json
#搜索,通过store 字段显示数据,同时高亮显示 conent 的内容
POST books/_search
{
  "stored_fields": ["title","author","public_date"],
  "query": {
    "match": {
      "content": "searching"
    }
  },
  "highlight": {
    "fields": {
      "content":{}
    }
  }
}

:::

4.3 Mapping 字段的相关设置

  • Enable:设置成 false,仅做存储,不支持搜索和聚合分析(数据保存在 _source 中);
  • Index:是否构造倒排索引。设置成 false,无法被搜索,但还是支持 aggregation,并出现在 _source 中;
  • Norms:如果字段用来过滤和聚合分析,可以关闭,节约存储;
  • Doc_values:是否启用 doc_values,用于排序和聚合分析;
  • Field_data:如果要对 text 类型启用排序和聚合分析,fielddata 需要设置成 true;
  • Store:默认不存储,数据默认存储在 _source;
  • Coerce:默认开启,是否开启数据类型的自动转换(例如,字符串转数字);
  • Multifileds 多字段特性;
  • Dynamic:true / false /strict 控制 Mapping 的自动更新