为什么es不在使用type了, 让我们来了解下原因。
什么是映射type
在7.0之前所有发布的版本中,每个文档存储在单独的映射类型里面。一个映射类型被代表了一个文档的类型或者实体索引。例如一个商品
索引他可能有电器
类型和生鲜
类型。
每个映射类型有自己的属性,电器
类型可能有名称、生产日期、保修时间等属性,生鲜
类型可能有名称、过期时间、最近使用时间等。每个文档都有_type
属性来指定属于哪个映射类型,搜索的时候可以在url里面指定一个或者多个type。
GET product/electric,fresh/_search
{
"query": {
"match": {
"name": "好"
}
}
}
_type属性和文档中的_id一起生成一个_uid属性,因此在同一个索引中可能存在相同的_id。
有时候映射类型可以用来指定文档的父子关系,如question
类型的文档可以是answer
类型文档的父文档。
为什么映射类型被移除
一开始,我们把索引比作是关系型数据库中的数据库,映射type比作了表。其实这个比喻是错误的,在关系型数据库中表是相互独立的,不同表中相同的列是没有关联关系的,这个与映射type是不一样的。
在es的索引中,不同的映射类型中存在相同的属性名,他们底层都是使用同一个Lucene属性。比如上面的商品例子中,电器和生鲜都有name字段,他们必须要有相同的映射类型才可以。例如在同一个索引中,deleted属性你在A类型中想用date来表示,在B类型中想用boolean来表示,像这种情况就不支持了。
最重要的是同一个索引中共同字段比较少或者没有,那么会导致数据太稀疏,这会影响Lucene有效压缩文档的能力,导致你的搜索很慢。
就是因为这些原因,es官方决定删除映射type这个概念。
替换方案
一个文档一个索引
把之前的电器类型和生鲜类型分别建立电器索引和生鲜索引。因为索引是相互独立的,不存在相同字段的冲突问题。使用这种方式有2个好处:
1、数据更加密集,有利于Lucene的压缩。
2、做统计的时候数据会更加准确,因为数据都在同一个索引中。
每个索引都可以根据自己实际需要存储多大的数据来进行调整,你可以对不同的索引设置不同的分片和副本。
自定义类型属性
上面的方式,会浪费分片,因为每个集群中的分片是有限制的,如果你不想为了几千个文档而浪费了不必要的分片,那么你可以自定义类型属性。
没有使用自定义类型示例:
PUT twitter
{
"mappings": {
"user": {
"properties": {
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" }
}
},
"tweet": {
"properties": {
"content": { "type": "text" },
"user_name": { "type": "keyword" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/user/kimchy
{
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/tweet/1
{
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
使用自定义类型示例:
PUT twitter
{
"mappings": {
"_doc": {
"properties": {
"type": { "type": "keyword" },
"name": { "type": "text" },
"user_name": { "type": "keyword" },
"email": { "type": "keyword" },
"content": { "type": "text" },
"tweeted_at": { "type": "date" }
}
}
}
}
PUT twitter/_doc/user-kimchy
{
"type": "user",
"name": "Shay Banon",
"user_name": "kimchy",
"email": "shay@kimchy.com"
}
PUT twitter/_doc/tweet-1
{
"type": "tweet",
"user_name": "kimchy",
"tweeted_at": "2017-10-24T09:00:00Z",
"content": "Types are going away"
}
GET twitter/_search
{
"query": {
"bool": {
"must": {
"match": {
"user_name": "kimchy"
}
},
"filter": {
"match": {
"type": "tweet"
}
}
}
}
}
没有父子关系映射type
以前会把一个映射类型表示父,另外一些映射类型表示子,没有了type,就没有这种语法了。如果你想继续表示这种父子关系,可以使用join属性。如
PUT my_index
{
"mappings": {
"properties": {
"my_join_field": {
"type": "join",
"relations": {
"question": "answer"
}
}
}
}
}
移除映射type
es对这块迁移,做了很多版本的兼容,es5.6.0之后的版本会慢慢的不在支持映射type。在es8中,彻底不支持映射类型。之前的版本你可以通过设置来开启,但是会有警告日志。
多type迁移到单type
es官方也考虑到迁移的问题,为了方便用户迁移,他们提供了Reindex接口,该接口可以把多类型索引迁移到单类型索引,大大简化了迁移过程。
一个索引一个类型
把原本一个索引两个类型的改为一个索引一个文档
PUT users
{
"settings": {
"index.mapping.single_type": true
},
"mappings": {
"_doc": {
"properties": {
"name": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"email": {
"type": "keyword"
}
}
}
}
}
PUT tweets
{
"settings": {
"index.mapping.single_type": true
},
"mappings": {
"_doc": {
"properties": {
"content": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"tweeted_at": {
"type": "date"
}
}
}
}
}
POST _reindex
{
"source": {
"index": "twitter",
"type": "user"
},
"dest": {
"index": "users"
}
}
POST _reindex
{
"source": {
"index": "twitter",
"type": "tweet"
},
"dest": {
"index": "tweets"
}
}
自定义类型
将自定义类型的索引进行迁移。
PUT new_twitter
{
"mappings": {
"_doc": {
"properties": {
"type": {
"type": "keyword"
},
"name": {
"type": "text"
},
"user_name": {
"type": "keyword"
},
"email": {
"type": "keyword"
},
"content": {
"type": "text"
},
"tweeted_at": {
"type": "date"
}
}
}
}
}
POST _reindex
{
"source": {
"index": "twitter"
},
"dest": {
"index": "new_twitter"
},
"script": {
"source": """
ctx._source.type = ctx._type;
ctx._id = ctx._type + '-' + ctx._id;
ctx._type = '_doc';
"""
}
}
这里对_id进行了处理,防止id重复。
es7中接口举例
在es7中索引接口都不需要指定type,如果你指定了会有弃用的警告日志。
索引接口
PUT index?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
PUT index/_mappings?include_type_name=false
{
"properties": {
"bar": {
"type": "text"
}
}
}
文档接口
PUT index/_doc/1
{
"foo": "baz"
}
返回值
{
"_index": "index",
"_id": "1",
"_type": "_doc",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
查询文档
GET index/_doc/1
POST index/_update/1
{
"doc" : {
"foo" : "qux"
}
}
GET /index/_source/1
POST _bulk
{ "index" : { "_index" : "index", "_id" : "3" } }
{ "foo" : "baz" }
{ "index" : { "_index" : "index", "_id" : "4" } }
{ "foo" : "qux" }
搜索接口
GET /twitter/_search
{
"query" : {
"term" : { "user" : "kimchy" }
}
}
到此我们大概知道了es为什么要弃用映射type了。
注意:本文归作者所有,未经作者允许,不得转载