删除映射类型
在Elasticsearch 7.0.0或更高版本中创建的索引不再接受_default_
映射,索引在6.x中创建将继续在Elasticsearch 6.x中运行,类型在api 7.0中是不受支持的,它会中断对索引创建、put映射、get映射、put模板、get模板和get字段映射API的更改。
什么是映射类型?
自从第一次发布Elasticsearch以来,每个文档都存储在一个索引中,并分配了一个映射类型,映射类型用于表示被索引的文档或实体的类型,例如twitter
索引可能具有user
类型和tweet
类型。
每个映射类型都可以有自己的字段,因此user
类型可以有full_name
字段、user_name
字段和email
字段,而tweet
类型可以有content
字段、tweeted_at
字段,和user
类型一样,还有user_name
字段。
每个文档都有一个包含类型名称的_type
元字段,通过在URL中指定类型名称,可以将搜索限制为一个或多个类型:
GET twitter/user,tweet/_search
{
"query": {
"match": {
"user_name": "kimchy"
}
}
}
_type
字段与文档的_id
相结合生成_uid
字段,因此具有相同_id
的不同类型的文档可以存在于一个索引中。
还使用映射类型在文档之间建立父子关系,因此类型为question
的文档可以是类型为answer
的文档的父文档。
为什么要删除映射类型?
最初,讨论了“索引”类似于SQL数据库中的“数据库”,以及“类型”等价于“表”。
这是一个错误的类比,导致了错误的假设,在SQL数据库中,表是相互独立的,一个表中的列与另一个表中具有相同名称的列没有关系,这与映射类型中的字段不同。
在Elasticsearch索引中,不同映射类型中具有相同名称的字段在内部由相同的Lucene字段支持,换句话说,使用上面的示例,user
类型中的user_name
字段存储在与tweet
类型中的user_name
字段完全相同的字段中,而且两个user_name
字段在这两种类型中必须具有相同的映射(定义)。
例如,当你想要删除一个类型中的date
字段和同一个索引中的另一个类型中的boolean
字段时,这可能会导致失败。
最重要的是,存储在同一索引中具有很少或没有共同字段的不同实体会导致数据稀疏,并影响Lucene有效压缩文档的能力。
基于这些原因,决定将映射类型的概念从Elasticsearch中移除。
映射类型的替代方案
每种文档类型的索引
第一种选择是为每个文档类型都有一个索引,你可以将tweets
存储为tweets
和user
索引,而不是将tweets
和users
存储在单个twitter
索引中,索引之间是完全独立的,因此索引之间不存在字段类型的冲突。
这种方法有两个好处:
- 数据更可能是密集的,因此受益于Lucene中使用的压缩技术。
- 用于在全文搜索中得分的统计术语更可能准确,因为同一索引中的所有文档都表示一个实体。
每个索引都可以根据它将包含的文档数量适当调整大小:你可以为users
使用较少的主碎片,而为tweet
使用较多的主碎片。
自定义类型字段
当然,集群中可以存在多少主碎片是有限制的,因此你可能不希望为了一个只有几千个文档的集合而浪费整个碎片,在本例中,你可以实现自己的自定义类型字段,其工作方式与旧的_type
类似。
让我们以上面的user
/tweet
为例,最初,工作流应该是这样的:
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
字段外,父—子特性将继续像以前一样工作。
删除映射类型的时间表
对于用户来说,这是一个巨大的变化,所以已经尝试让它尽可能地不那么痛苦,更改将按如下方式进行:
Elasticsearch 5.6.0
- 在索引上设置
index.mapping.single_type: true
将启用在6.0中强制执行的单类型/索引行为。 - 在5.6中创建的索引中可以使用父—子
join
字段替换。
Elasticsearch 6.x
- 在5.x中创建索引将继续在6.x中运行就像5.x。
- 索引在6.x中创建只允许每个索引使用单一类型,类型可以使用任何名称,但只能有一个,首选的类型名称是
_doc
,因此索引API具有与7.0中相同的路径:PUT {index}/_doc/{id} and POST {index}/_doc
。 -
_type
名称不能再与_id
组合以形成_uid
字段,_uid
字段已成为_id
字段的别名。 - 新的索引不再支持旧式的父/子索引,而是应该使用
join
字段。 -
_default_
映射类型已弃用。 - 在6.8中,索引创建、索引模板和映射API支持查询字符串参数(
include_type_name
),该参数指示请求和响应是否应该包含类型名称。它默认为true
,应该设置为一个显式值,以便准备升级到7.0,未设置include_type_name
将导致一个弃用警告,没有显式类型的索引将使用虚拟类型名称_doc
。
Elasticsearch 7.x
- 在请求中指定类型已弃用,例如,索引文档不再需要文档
type
,对于显式id,新的索引API是PUT {index}/_doc/{id}
,对于自动生成的id则是POST {index}/_doc
,注意,在7.0中,_doc
是路径的一个永久部分,它表示端点名称,而不是文档类型。 - 索引创建、索引模板和映射API中的
include_type_name
参数默认为false
,完全设置该参数将导致一个弃用警告。 - 删除
_default_
映射类型。
Elasticsearch 8.x
- 不再支持在请求中指定类型。
- 删除
include_type_name
参数。
将多类型索引迁移到单类型
Reindex API可用于将多类型索引转换为单类型索引,下面的例子可以在Elasticsearch 5.6或Elasticsearch 6.x中使用,在6.x,不需要指定index.mapping.single_type
作为默认值。
每种文档类型的索引
第一个示例将twitter
索引拆分为tweets
索引和users
索引:
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"
}
}
自定义类型字段
下一个示例添加一个自定义类型字段,并将其设置为原始_type
的值,它还将类型添加到_id
中,以防有任何不同类型的文档具有冲突的id
:
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';
"""
}
}
7.0中的无类型API
在Elasticsearch 7.0中,每个API都支持无类型请求,指定类型将产生一个弃用警告。
即使目标索引包含自定义类型,无类型API也可以工作,例如,如果索引具有自定义类型名称my_type
,则可以使用无类型index
调用向其添加文档,并使用无类型get
调用加载文档。
索引API
索引创建、索引模板和映射API支持一个新的include_type_name
URL参数,该参数指定请求和响应中的映射定义是否应该包含类型名称,版本6.8中的参数默认为true
,以匹配在映射中使用类型名称的7.0之前的行为,它在7.0版本中默认为false
,将在8.0版本中删除。
它应该在6.8中明确设置,以便准备升级到7.0,为了避免6.8中的弃用警告,可以将参数设置为true
或false
,在7.0中,设置include_type_name
将导致一个弃用警告。
查看一些与Elasticsearch交互的例子,这个选项设置为false
:
PUT index?include_type_name=false
{
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
- 映射直接包含在
mappings
键下,没有类型名称。
PUT index/_mappings?include_type_name=false
{
"properties": {
"bar": {
"type": "text"
}
}
}
- 映射直接包含在
mappings
键下,没有类型名称。
GET index/_mappings?include_type_name=false
上面的调用返回:
{
"index": {
"mappings": {
"properties": {
"foo": {
"type": "keyword"
},
"bar": {
"type": "text"
}
}
}
}
}
- 映射直接包含在
mappings
键下,没有类型名称。
文档API
在7.0中,必须使用{index}/_doc
路径调用索引API,以便自动生成_id
,使用显式id
调用{index}/_doc/{id}
。
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
和delete
API使用路径{index}/_doc/{id}
:
GET index/_doc/1
在7.0中,_doc
表示端点名称,而不是文档类型,_doc
组件是文档index
、get
和delete
API路径的永久部分,在8.0中不会被删除。
对于同时包含类型和端点名(如_update
)的API路径,在7.0中端点将立即跟随索引名:
POST index/_update/1
{
"doc" : {
"foo" : "qux"
}
}
GET /index/_source/1
类型也不应该再出现在请求体中,下面的bulk
索引示例省略了URL和单个批量命令中的类型:
POST _bulk
{ "index" : { "_index" : "index", "_id" : "3" } }
{ "foo" : "baz" }
{ "index" : { "_index" : "index", "_id" : "4" } }
{ "foo" : "qux" }
搜索API
在调用诸如_search
、_msearch
或_explain
之类的搜索API时,URL中不应该包含类型,此外,_type
字段不应该用于查询、聚合或脚本。
响应中的类型
文档和搜索API将继续在响应中返回_type
键,以避免中断响应解析,然而,键被认为是不赞成的,不应该再被引用,类型将在8.0中从响应中完全删除。
注意,当使用废弃的类型化API时,索引的映射类型将作为正常返回,但是无类型API将在响应中返回虚拟类型_doc
,例如,下面的无类型get
调用总是返回_doc
作为类型,即使映射有一个像my_type
这样的自定义类型名:
PUT index/my_type/1
{
"foo": "baz"
}
GET index/_doc/1
{
"_index" : "index",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found": true,
"_source" : {
"foo" : "baz"
}
}
索引模版
建议通过将include_type_name
设置为false
来重新添加索引模板,使其无类型,在底层,无类型模板在创建索引时将使用虚拟类型_doc
。
如果将无类型模板用于类型化索引创建调用,或者将类型化模板用于无类型索引创建调用,则仍将应用模板,但索引创建调用将决定是否应该有类型。例如在下面的示例中,index-1-01
将具有一个类型,尽管它匹配一个没有类型的模板,而index-2-01
将具有无类型,尽管它匹配一个定义了类型的模板,index-1-01
和index-2-01
都将从匹配的模板中继承foo
字段。
PUT _template/template1
{
"index_patterns":[ "index-1-*" ],
"mappings": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
PUT _template/template2?include_type_name=true
{
"index_patterns":[ "index-2-*" ],
"mappings": {
"type": {
"properties": {
"foo": {
"type": "keyword"
}
}
}
}
}
PUT index-1-01?include_type_name=true
{
"mappings": {
"type": {
"properties": {
"bar": {
"type": "long"
}
}
}
}
}
PUT index-2-01
{
"mappings": {
"properties": {
"bar": {
"type": "long"
}
}
}
}
在隐式索引创建的情况下,因为文档在索引中被索引,而索引还不存在,所以总是使用模板,这通常不是一个问题,因为无类型索引调用要处理有类型的索引。
混合版本的集群
在由6.8和7.0节点组成的集群中,应该在索引创建之类的索引API中指定参数include_type_name
,这是因为参数在6.8和7.0之间有不同的默认值,所以相同的映射定义对两个节点版本都无效。
诸如bulk
和update
之类的无类型文档API仅在7.0版本时可用,不能用于6.8节点,对于执行文档查找的查询的无类型版本,如terms
,也是如此。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。