11.1 Mapping概述
前文已经把ElasticSearch的核心概念和关系数据库做了一个对比,索引(index)相当于数据库,类型(type)相当于数据表,映射(Mapping)相当于数据表的表结构。ElasticSearch中的映射(Mapping)用来定义一个文档,可以定义所包含的字段以及字段的类型、分词器及属性等等。
映射可以分为动态映射和静态映射。 (1)动态映射 我们知道,在关系数据库中,需要事先创建数据库,然后在该数据库实例下创建数据表,然后才能在该数据表中插入数据。而ElasticSearch中不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型,这种机制称之为动态映射。
(2)静态映射 当然,在ElasticSearch中也可以事先定义好映射,包含文档的各个字段及其类型等,这种方式称之为静态映射。
11.2 动态映射实例
(1)新建索引
代码语言:javascript复制PUT book
代码语言:javascript复制{
"acknowledged": true,
"shards_acknowledged": true,
"index": "book"
}
(2)查看空mapping
代码语言:javascript复制GET book/_mapping
代码语言:javascript复制{
"book": {
"mappings": {}
}
}
(3)插入文档 it类型表示IT类书籍
代码语言:javascript复制PUT book/it/1
{
"bookId":1,
"bookName":"Java程序设计",
"publishDate":"2018-01-12"
}
代码语言:javascript复制{
"_index": "book",
"_type": "it",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
(4)再次查看映射
代码语言:javascript复制GET book/_mapping
代码语言:javascript复制{
"book": {
"mappings": {
"it": {
"properties": {
"bookId": { "type": "long" },
"bookName": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } },
"publishDate": { "type": "date" } }
}
}
}
}
(5)解读 bookId字段推测为long型,bookName字段推测为text类型,publishDate字段推测为date类型,这些推测都是我们可以接受的。可见ElasticSearch的动态映射十分强大。
11.3 动态映射规则
动态映射可以帮助我们在创建索引后直接将文档数据写入ElasticSearch,让我们尽快享受到ElasticSearch检索功能。在实际项目中,如果在导入数据前不能确定包含哪些字段或者不方便确定字段类型,可以使用动态映射。当向ElasticSearch写入一个新文档时,需要一个之前没有的字段,会通过动态映射来推断该字段类型。
ElasticSearch动态映射规则如下。
JSON数据 | 自动推测的类型 |
---|---|
null | 没有字段被添加 |
true或false | boolean型 |
小数 | float型 |
数字 | long型 |
日期 | date或text |
字符串 | text |
数组 | 由数组第一个非空值决定 |
JSON对象 | object类型 |
11.4 静态映射
动态映射的自动类型推测功能并不是100%正确的,这就需要静态映射机制。静态映射与关系数据库中创建表语句类型,需要事先指定字段类型。相对于动态映射,静态映射可以添加更加详细字段类型、更精准的配置信息等。
(1)新建映射 在6.x中创建的索引只允许每个索引有单一类型。任何名字都可以用于这个类型,但是只能有一个。
代码语言:javascript复制PUT books
{
"mappings":{
"it": {
"properties": {
"bookId": {"type": "long"},
"bookName": {"type": "text"},
"publishDate": {"type": "date"}
}
}
}
}
代码语言:javascript复制{
"acknowledged": true,
"shards_acknowledged": true,
"index": "books"
}
(2)查看映射
代码语言:javascript复制GET books/_mapping
代码语言:javascript复制{
"books": {
"mappings": {
"it": {
"properties": {
"bookId": { "type": "long" },
"bookName": { "type": "text" },
"publishDate": { "type": "date" } }
}
}
}
}
(3)插入文件数据
代码语言:javascript复制PUT books/it/1
{
"bookId":"1",
"bookName":"Java",
"publishDate":"2018-01-12"
}
代码语言:javascript复制{
"_index": "books",
"_type": "it",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
(4)检索
代码语言:javascript复制GET books/it/1
代码语言:javascript复制{
"_index": "books",
"_type": "it",
"_id": "1",
"_version": 1,
"found": true,
"_source": {
"bookId": "1",
"bookName": "Java",
"publishDate": "2018-01-12"
}
}
11.5 静态 动态
代码语言:javascript复制PUT books/it/2
{
"bookId":"2",
"bookName":"Hadoop",
"author":"chengyuqiang",
"publishDate":"2018-01-13"
}
代码语言:javascript复制{
"_index": "books",
"_type": "it",
"_id": "2",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 2
}
代码语言:javascript复制GET books/_mapping
代码语言:javascript复制{
"books": {
"mappings": {
"it": {
"properties": {
"author": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } },
"bookId": { "type": "long" },
"bookName": { "type": "text" },
"publishDate": { "type": "date" } }
}
}
}
}
11.6 type设计失误
类型是Elasticsearch的一个设计失误,6.0开始后面的版本将不再支持,官方说明请参见 https://www.elastic.co/guide/en/elasticsearch/reference/6.0/removal-of-types.html#_alternatives_to_mapping_types
(1)为什么映射类型被删除? 最初,我们谈到了与SQL数据库中的“数据库”类似的“索引”,“类型”与“表”相当。
这是一个不好的比喻,导致错误的假设。在一个SQL数据库中,表格是相互独立的。一个表中的列与另一个表中的相同名称的列没有关系。映射类型的字段不是这种情况。
在Elasticsearch索引中,在不同映射类型中具有相同名称的字段在内部由相同的Lucene字段支持。换句话说,使用上面的例子,类型中的user_name字段和user类型中的字段存储在完全相同的user_name字段中tweet,并且两个 user_name字段在两种类型中都必须具有相同的映射(定义)。
例如,当你想要deleted成为 date一个类型的boolean字段和另一个类型的字段在同一个索引中时,这可能会导致挫败感。
最重要的是,在同一索引中存储具有少量或不共有字段的不同实体会导致数据稀疏并干扰Lucene高效压缩文档的能力。
由于这些原因,我们决定从Elasticsearch中删除映射类型的概念。
(2)排除映射类型的规划 这对我们的用户来说是一个很大的改变,所以我们尽可能地让它变得无痛苦。变化将如下展开:
Elasticsearch 5.6.0 index.mapping.single_type: true在索引上 设置将启用将在6.0中实施的单类型索引行为。 本join场替代亲子可在5.6中创建索引。 Elasticsearch 6.x 在5.x中创建的索引将继续在6.x中运行,就像在5.x中一样。 在6.x中创建的索引只允许每个索引有单一类型。任何名字都可以用于这个类型,但是只能有一个。 该_type名称不能再与_id该_uid 字段组合。该_uid领域已成为该_id领域的别名。 新的指标不再支持老式的父母/孩子,而应该使用该join领域。 的default映射类型已弃用。 Elasticsearch 7.x type网址中 的参数是可选的。例如,索引文档不再需要文档type。 这些GET|PUT _mappingAPI支持一个查询字符串参数(include_type_name),它指示了主体是否应该为类型名称包含一个图层。它默认为true。7.x没有明确类型的索引将使用虚拟类型名称_doc。 的default映射类型被去除。 Elasticsearch 8.x 该type网址不再支持该参数。 该include_type_name参数默认为false。 Elasticsearch 9.x 该include_type_name参数被删除。