elasticsearch版本升级type属性的变化

type属性的由来

从Elasticsearch的第一个发布版本以来,每一个document都被存储在一个单独的index里,并被赋予了一个type,一个mapping代表一个type相关的数据类型以及索引类型。

例如,一个twitter索引可能有一个user类型和tweet类型。

每种type都有他自己的字段,所以user类型可能有一个full_name字段,一个user_name字段和一个email字段,而一个tweet类型可能有一个content字段,一个tweet_at字段,和user类型一样一个user_name字段。

每一个文档类型都有一个_type元字段来存储type名称,并且根据URL里指定的类型名称,查询(搜索)被限定在一个或多个类型(type)里:

GET /twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "nicola"
}
}
}
type为什么被干掉了
但是不知道何时起,有人将elasticsearch对标关系型数据库中的概念,这样便于理解,也便于处理问题,于是就有了下面的关系:

elasticsearch rdbms description
index db 数据库
type table 数据表
document row 数据行
field column 数据列
mapping schema 数据结构/类型

elasticsearch rdbms description
index db 数据库
type table 数据表
document row 数据行
field column 数据列
mapping schema 数据结构/类型

 

 

 

 

 

 

看上面的对照关系,一切都很完美,完全匹配,但是这也是一把双刃剑,玩惯了rdbms的人可能“误会”了elasticsearch,并按照rdbms的思想去构建elasticsearch,结果很快就发现了无数的坑,比如:

在关系型数据库里,table是相互独立的,一个table里的column和另外一个table的同名column没有关系,互不影响。但在type里字段却不是这样的。在一个Elasticsearch的index里,所有不同type的同名column内部使用的是同一个lucene字段存储。举例来说,user类型的user_name字段和tweet类型的user_name字段是存储在一个field里的,两个类型里的user_name必须有一样的field定义。

这可能导致一些问题,例如你希望同一个索引中"create_time"字段在一个类型里是存储日期值,在另外一个类型里存储字符串。

另外,按照Lucene存储的方式和特点,如果按照此种方式组织数据,会影响到底层的压缩比例和存储效率。

基于上面的原因,type在被误解后处于尴尬的地位,慢慢的版本迭代就被干掉了,在干掉一层数据结构后,es的数据结构变的简单明了,便于理解。

type的版本迭代

5.x及以前版本一个index有一个或者多个type
6.X版本一个index只有一个index
7.X版本移除了type,type相关的所有内容全部变成Deprecated,为了兼容升级和过渡,所有的7.X版本es数据写入后type字段都默认被置为_doc
8.X版本完全废弃type
type跨版本适配
针对6.X版本升级到7.X的数据,使用restful api查询es时不需要指定type即可以进行查询、结果与指定对应的type进行查询、type使用_doc进行查询效果是一样的
针对6.X版本升级到7.X的数据,使用restful api写入es时,不能指定type,如果处于某种原因必须指定type,则可以将type指定为_doc(比如使用6.X的restful api,这种场景详见一文讲解Elasticsearch java restful api 跨版本兼容解决方案),如果id相同,则数据会被覆盖,但是type保持原来的值,不会出现一个id对应多条数据的情况;如果id不相同,则会新写入一条type为_doc的数据
如果为了将来兼容和支持高版本的elasticsearch,建议使用restful client去支持elasticsearch相关的操作,并且尽量不要在api中有type这个参数,就算必须要需要,也建议在源生api中再封装一层,否则后续版本升级,适配的工作量会让你崩溃

在ElasticSearch升级到8.x之后,在自己使用kibana测试添加索引得时候,按照
正常得添加的时候,发现一直会报一个400错误,no handler found for uri。。。后来发现用系统默认的类型添加的时候就没问题,整整困扰了一天的原因是在el8以后不在支持索引,换成低版本的测试就没问题了

Elasticsearch7.X为什么移除类型(type)在Elasticsearch7.0.0及以后版本不再接受_default_ 映射。在6.x里创建的索引依然像在Elasticsearch6.X之前一样起作用。Types在7.0的API里是被舍弃的,在创建索引,设置映射,获取映射,设置模板,获取模板,获取字段映射API有着不兼容的改变。

index、type的初衷
之前es将index、type类比于关系型数据库(例如mysql)中database、table,这么考虑的目的是“方便管理数据之间的关系”。

【本来为了方便管理数据之间的关系,类比database-table 设计了index-type模型】

什么是类型(type)?

从Elasticsearch的第一个发布版本以来,每一个文档都被存储在一个单独的索引里,并被赋予了一个type,一个映射类型代表着一个被索引的文档或实体的类型,例如,一个twitter索引可能有一个user类型和tweet类型。

每种映射类型都有他自己的字段,所以user类型可能有一个full_name字段,一个user_name字段和一个email字段,而一个tweet类型可能有一个content字段,一个tweet_at字段,和user类型一样一个user_name字段。

每一个文档类型都有一个_type元字段来存储type名称,并且根据URL里指定的类型名称,查询(搜索)被限定在一个或多个类型(type)里:

GET twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}_type字段用来和文档的_id字段联合生成_uid字段,所以有着相同_id的不同类型的文档可以存在同一个索引里。类型也用来建立文档间的父子关系,所以question类型的文档可能是anser类型文档的父文档。
1、我们经常把二维数据库与ES作类比的方式是不正确的假设。把“index”类比为数据库,“type”类比为表。具体原因是,数据库的表是物理独立的,一个表的列跟另外一张表相同名称的列没有关系,而ES中并非如此,不同type映射类型中具有相同名称的字段在内部由相同的Lucene字段支持。

2、当您想要索引一个deleted字段在不同的type中数据类型不一样。一个类型中为日期字段,另外一个类型中为布尔字段时,这可能会导致ES的存储失败,因为这影响了ES的初衷设计。

3、另外,在一个index中建立很多实体,type,没有相同的字段,会导致数据稀疏,最终结果是干扰了Lucene有效压缩文档的能力,说白了就是影响ES的存储、检索效率。

为什么现在要移除type?
2.1 在关系型数据库中table是独立的(独立存储),但es中同一个index中不同type是存储在同一个索引中的(lucene的索引文件),因此不同type中相同名字的字段的定义(mapping)必须一致。

2.2 不同类型的“记录”存储在同一个index中,会影响lucene的压缩性能。

【总结:
es基于Lucene的索引文件扩展type结构,也受限制与同一个index里的不同的type存储再同样一个索引文件里

这样不同type里的相同名字的field mapping必须一致,事实上上数据库中的不同的table表是独立存储的,不同的table里的字段是 独立设计的 于是type的用途非常有限,比如下面的替换方案】

替换策略

3.1 一个index只存储一种类型的“记录”

这种方案的优点:

a)lucene索引中数据比较整齐(相对于稀疏),利于lucene进行压缩。

b)文本相关性打分更加精确(tf、idf,考虑idf中命中文档总数)

3.2 用一个字段来存储type

如果有很多规模比较小的数据表需要建立索引,可以考虑放到同一个index中,每条记录添加一个type字段进行区分。

这种方案的优点:

a)es集群对分片数量有限制,这种方案可以减少index的数量。

方案1:去掉type,全部使用独立的index;问题:index太多影响es集群分片效果。
方案2:如果数据量不大,可以把一个index下不同的type 合并成一个index;通过一个field字段比如就叫 _type 来区分之前的index-type
迁移方案
之前一个index上有多个type,如何迁移到3.1、3.2方案?

先针对实际情况创建新的index,[3.1方案]有多少个type就需要创建多少个新的index,[3.2方案]只需要创建一个新的index。
调用_reindex将之前index上的数据同步到新的索引上;第二个方案通过_reindex 配合脚本区分不同的type字段
Elasticsearch 移除 type 之后的新姿势
随着 7.0 版本的即将发布,type 的移除也是越来越近了,在 6.0 的时候,已经默认只能支持一个索引一个 type 了,7.0 版本新增了一个参数 include_type_name ,即让所有的 API 是 type 相关的,这个参数在 7.0 默认是 true,不过在 8.0 的时候,会默认改成 false,也就是不包含 type 信息了,这个是 type 用于移除的一个开关。 

posted on 2022-09-05 14:51  书梦一生  阅读(664)  评论(0编辑  收藏  举报

导航