Elasticsearch 通关教程(二): 索引映射Mapping问题
数据库建表的时候,我们的DDL语句一般都会指定每个字段的存储类型,例如:varchar,int,datetime等等,目的很明确,就是更精确的存储数据,防止数据类型格式混乱。
CREATE TABLE `shop_` (
`id_` varchar(36) NOT NULL COMMENT 'id',
`shop_name_` varchar(50) DEFAULT NULL COMMENT '商品名称',
`shop_integral_` int(11) DEFAULT NULL COMMENT '兑换所需积分',
`shop_money_` decimal(10,0) DEFAULT NULL COMMENT '劵面金额',
`start_time_` datetime DEFAULT NULL COMMENT '有效开始时间',
`end_time_` datetime DEFAULT NULL COMMENT '有效结束时间',
`is_delete_` int(1) DEFAULT '1' COMMENT '是否删除-1:有效,0:删除',
PRIMARY KEY (`id_`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
在 Elasticsearch中也是这样,创建索引的时候一般也需要指定索引的字段类型,这种方式成为映射(Mapping)。
字段类型
映射(Mapping)针对的是文档的字段,数据库中有varchar,int,datetime等数据类型,那么我们ElasticSearch中又有哪些字段类型,每个字段类型都代表什么意思呢?
ElasticSearch更新频繁,以下内容是针对6.x版本的,对于5.x版本以及之前的版本可能有所不同,未来7.x版本也许也会有所改变,本篇不能做到面面俱到,所以大家可以针对自己的版本查阅官方文档。
Elasticsearch支持文档字段的多种不同数据类型,根据官方文档的分类,可以划分为以下几个类别:
核心数据类型,复杂数据类型,Geo(地理)数据类型,专用数据类型和多字段。
核心数据类型
- 字符串类型
主要包括:text 和 keyword。 - 数字类型
主要包括:long, integer, short, byte, double, float, half_float, scaled_float - 日期类型
- 布尔类型
- 二进制类型
- 范围数据类型
integer_range, float_range, long_range, double_range, date_range
这里我们重点介绍下 text 和 keyword 的区别:
text 用于索引全文值的字段,例如电子邮件正文或产品说明。这些字段是analyzed,它们通过分词器传递 ,以在被索引之前将字符串转换为单个术语的列表。分析过程允许Elasticsearch搜索单个单词中 每个完整的文本字段。文本字段不用于排序,很少用于聚合(尽管 重要的文本聚合 是一个值得注意的例外)。
keyword 用于索引结构化内容的字段,例如电子邮件地址,主机名,状态代码,邮政编码或标签。它们通常用于过滤,排序,和聚合。keyword字段只能按其确切值进行搜索。如果您需要索引电子邮件正文或产品说明等全文内容,则可能应该使用text字段。
有时候一个字段同时拥有全文类型(text)和关键字类型(keyword)是有用的:一个用于全文搜索,另一个用于聚合和排序。这可以通过多字段类型来实现。
复杂数据类型
Geo数据类型
- 地理点数据类型
geo_point 对于纬度/经度点 - Geo-Shape数据类型
geo_shape 对于像多边形这样的复杂形状
专用数据类型
多字段
有时候单纯的一个字段类型满足不了我们复杂的需求,为了不同的目的,以不同的方式索引同一个字段通常很有用。多字段也是ES的一种数据类型,只不过结合了更多的功能。
例如,对于字符串字段,我们既可以将它映射为text类型用于全文搜索,亦可以将它映射为keyword类型用于排序或聚合,或者,还可以使用标准分词器、英语分词器和其他语言分词器索引文本字段。
大多数数据类型都通过fields
参数支持多字段。例如对于城市名称的多字段映射,可以这样写:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"cityName": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
}
Elasticsearch的字段类型讲解完了,我们接下来正式介绍 ES的映射,ES是如何将索引文档和数据类型进行关联的,创建索引前是否必须制定索引文档的数据类型呢?
映射
映射是定义一个文档及其包含的字段如何存储和索引的过程。例如,使用映射来定义:
- 应将哪些字符串字段视为全文字段。
- 哪些字段包含数字,日期或地理位置。
- 是否应将文档中所有字段的值索引到catch-all _all字段中。
- 日期值的格式。
- 自定义规则以控制动态添加字段的映射。
其实在 ElasticSearch中可以不需要事先定义映射(Mapping),文档写入ElasticSearch时,会根据文档字段自动识别类型,但是通过这种自动识别的字段不是很精确,对于一些复杂的需要分词的就不适合了。
根据是否自动识别映射类型,我们可以将映射分为动态映射和静态映射。
动态映射,即不事先指定映射类型(Mapping),文档写入ElasticSearch时,ES会根据文档字段自动识别类型,这种机制称之为动态映射。
静态映射,即人为事先定义好映射,包含文档的各个字段及其类型等,这种方式称之为静态映射,亦可称为显式映射。
动态映射
Elasticsearch最重要的功能之一是它试图摆脱你的方式,让你尽快开始探索你的数据。Elasticsearch试图让你成功安装环境之后就可以直接使用。要索引文档,您不必首先创建索引、定义映射类型和定义字段,其实您只需索引一个文档数据,然后索引、类型和字段将自动生效。
索引一个图书的文档:
PUT /library/book/1
{
"bookId":1,
"bookName":"Java核心技术 卷I",
"publishDate":"2014-03-12"
}
返回结果如下,表示成功
{
"_index": "library",
"_type": "book",
"_id": "1",
"_version": 1,
"result": "created",
"_shards": {
"total": 2,
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_primary_term": 1
}
我们看下mapping映射信息
GET library/_mapping
得到如下映射信息,重点关注mapping节点的内容
{
"library": {
"mappings": {
"book": {
"properties": {
"bookId": {
"type": "long"
},
"bookName": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"publishDate": {
"type": "date"
}
}
}
}
}
}
可以看到,我们并没有创建索引映射,Elasticsearch自动根据文档数据为我们映射了字段类型,bookId的映射类型为long,bookName的映射类型为多字段的即为text,同时也为keyword,publishDate的映射类型为date。可以看到ES的动态映射功能还是蛮强大的。
默认情况下,当在文档中找到以前未见过的字段时,Elasticsearch会自动将这个新字段添加到类型映射中。我们可以在文档和object级别禁用这项功能,具体操作方式就是通过将dynamic
参数设置为false
或strict
,设为false是忽略新字段,而设为strict是如果遇到未知字段,就抛出异常。
假设启用了动态字段映射功能,则使用一些简单的规则来确定字段应具有的数据类型:
JSON datatype | Elasticsearch datatype |
---|---|
null | 没有字段添加 |
true or false | boolean |
integer | long |
object | object |
array | 依赖于数组中首个非空值 |
string | 可以是日期字段、double或long字段,也可以是带有关键字子字段的文本字段。 |
上面这些是可以动态检测到的字段数据类型,而其他的以外的字段必须要显式映射数据类型了。
对于string字符串字段,动态映射的结果会有多种,可能映射为日期类型,也可能映射为double或long类型,也可能映射为带有关键字的text类型,具体结果要看配置的检测类型,是日期检测还是数字检测。
日期检测
如果date_detection
启用(默认),则检查新字符串字段以查看其内容是否与dynamic_date_formats
指定的任何日期模式匹配 。如果找到匹配项,那么则添加为具有对应格式的date新字段。
默认值为
dynamic_date_formats:[ "strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]
例如:
PUT my_index/_doc/1
{
"create_date": "2015/09/02"
}
通过GET my_index/_mapping
得到的结果为:
{
"my_index": {
"mappings": {
"_doc": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
},
"create_date": {
"type": "date",
"format": "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
}
}
}
}
}
}
动态日期检测可以通过设置date_detection
为false
来禁用:
PUT my_index
{
"mappings": {
"_doc": {
"date_detection": false
}
}
}
PUT my_index/_doc/1
{
"create": "2015/09/02"
}
禁用之后,重新获取映射类型,得到如下结果:
{
"my_index": {
"mappings": {
"_doc": {
"date_detection": false,
"properties": {
"create": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
这时,create_date字段已被添加为文本字段。我们也可以自定义检测到的日期格式,通过dynamic_date_formats
可以自定义以支持您自己的日期格式:
PUT my_index
{
"mappings":{
"_ doc":{
"dynamic_date_formats":["MM / dd / yyyy"]
}
}
}
数字检测
虽然JSON支持本机浮点和整数数据类型,但某些应用程序或语言有时可能将数字呈现为字符串。通常,正确的解决方案是显式映射这些字段,但可以启用数字检测(默认情况下禁用)以自动执行此操作:
PUT my_index
{
"mappings":{
"_ doc":{
"numeric_detection":true
}
}
}
PUT my_index / _doc / 1
{
"my_float":"1.0",
"my_integer":"1"
}
其中my_float字段将添加为float字段,my_integer字段将添加为long字段。
除了上面列出的选项外,还可以进一步自定义动态字段映射规则dynamic_templates
,动态模板允许您定义可应用于动态添加字段的自定义映射,具体取决于:
- Elasticsearch检测到 的数据类型match_mapping_type。
- 字段的名称,带match和unmatch或match_pattern。
- 字段的完整虚线路径,带path_match和path_unmatch。
更多具体内容可参考官方文档,Dynamic templates一章这里就不多叙述了。
静态映射(显式映射)
动态映射的自动类型推测功能并不是100%正确的,这就需要静态映射机制。静态映射与关系数据库中创建表语句类型,需要事先指定字段类型。相对于动态映射,静态映射可以添加更加详细字段类型、更精准的配置信息等。
既然可以自定义映射字段类型,那么那些复杂的字段类型和分词器我们都可以根据自己需求添加了,以提供了字段映射使用的各种映射参数的详细说明,这些映射参数对于某些或所有字段数据类型是通用的,内容太多,这里感兴趣的读者可以点击具体链接阅读。
映射参数 | 说明 |
---|---|
analyzer | 分析器 |
normalizer | 在 Elasticsearch 中处理字符串类型的数据时,如果我们想把整个字符串作为一个完整的 term 存储,我们通常会将其类型 type 设定为 keyword。但有时这种设定又会给我们带来麻烦,比如同一个数据再写入时由于没有做好清洗,导致大小写不一致,比如 apple、Apple两个实际都是 apple,但当我们去搜索 apple时却无法返回 Apple的文档。要解决这个问题,就需要 Normalizer出场了。 |
boost | 单个字段可以自动提升以计数更多的相关性得分 |
coerce | 强制尝试清除脏值以适合字段的数据类型。数据并不总是干净的,根据它的生成方式,数字可能会在JSON正文中呈现为真正的JSON数字,例如5,但它也可能呈现为字符串,例如"5"。或者,应该是整数的数字可以替代地呈现为浮点,例如5.0,或甚至 "5.0"。 |
copy_to | copy_to参数允许您创建自定义 _all字段,可以将多个字段的值复制到组字段中,然后可以将其作为单个字段进行查询。 |
doc_values | |
dynamic | 设置动态映射 |
enabled | enabled设置只能应用于映射类型和 object字段,导致Elasticsearch完全跳过对字段内容的解析 |
fielddata | |
eager_global_ordinals | |
format | 格式化日期 |
ignore_above | |
ignore_malformed | |
index_options | |
index | |
fields | |
norms | |
null_value | 当字段设置为null,(或空数组或null值数组)时,它被视为该字段没有值。不能被索引或搜索 |
position_increment_gap | |
properties | |
search_analyzer | |
similarity | |
store | |
term_vector |
Elasticsearch 通关教程(二): 索引映射Mapping问题的更多相关文章
- Elasticsearch入门教程(二):Elasticsearch核心概念
原文:Elasticsearch入门教程(二):Elasticsearch核心概念 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:ht ...
- Elasticsearch 通关教程(七): Elasticsearch 的性能优化
硬件选择 Elasticsearch(后文简称 ES)的基础是 Lucene,所有的索引和文档数据是存储在本地的磁盘中,具体的路径可在 ES 的配置文件../config/elasticsearch. ...
- Elasticsearch通关教程(一): 基础入门
简介 Elasticsearch是一个高度可扩展的.开源的.基于 Lucene 的全文搜索和分析引擎.它允许您快速,近实时地存储,搜索和分析大量数据,并支持多租户. Elasticsearch也使用J ...
- Elasticsearch 通关教程(三): 索引别名Aliases问题
业务问题 业务需求是不断变化迭代的,也许我们之前写的某个业务逻辑在下个版本就变化了,我们可能需要修改原来的设计,例如数据库可能需要添加一个字段或删减一个字段,而在搜索中也会发生这件事,即使你认为现在的 ...
- Elasticsearch 通关教程(四): 分布式工作原理
前言 通过前面章节的了解,我们已经知道 Elasticsearch 是一个实时的分布式搜索分析引擎,它能让你以一个之前从未有过的速度和规模,去探索你的数据.它被用作全文检索.结构化搜索.分析以及这三个 ...
- Elasticsearch通关教程(五):如何通过SQL查询Elasticsearch
前言 这篇博文本来是想放在全系列的大概第五.六篇的时候再讲的,毕竟查询是在索引创建.索引文档数据生成和一些基本概念介绍完之后才需要的.当前面的一些知识概念全都讲解完之后再讲解查询是最好的,但是最近公司 ...
- Elasticsearch 通关教程(六): 自动发现机制 - Zen Discoveryedit
发现方式 Zen discovery是内建的.默认的.用于Elasticsearch的发现模块.它提供了单播和基于文件的发现,可以通过插件扩展到支持云环境和其他形式的发现. Zen Discovery ...
- elasticsearch 5.6.4自动创建索引与mapping映射关系 +Java语言
由于业务上的需求 ,最近在研究elasticsearch的相关知识 ,在网上查略了大部分资料 ,基本上对elasticsearch的数据增删改都没有太大问题 ,这里就不做总结了 .但是,在网上始终没 ...
- Elasticsearch入门教程(三):Elasticsearch索引&映射
原文:Elasticsearch入门教程(三):Elasticsearch索引&映射 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文 ...
随机推荐
- shell从入门到精通进阶之一:Shell基础知识
1.1 简介 Shell是一个C语言编写的脚本语言,它是用户与Linux的桥梁,用户输入命令交给Shell处理,Shell将相应的操作传递给内核(Kernel),内核把处理的结果输出给用户. 下面是处 ...
- Magicodes.WeiChat——发送模板消息
在微信开发中,经常会使用到模板消息.因此框架中对此进行了一些封装,并且提供了后台操作界面以及日志查看等功能,下面开始逐步介绍开发操作以及使用. 微信公众平台配置 首先,需要申请开通模板消息功能,如下图 ...
- [三]java8 函数式编程Stream 概念深入理解 Stream 运行原理 Stream设计思路
Stream的概念定义 官方文档是永远的圣经~ 表格内容来自https://docs.oracle.com/javase/8/docs/api/ Package java.util.s ...
- 图解ARP协议(二)ARP攻击原理与实践
一.ARP攻击概述 在上篇文章里,我给大家普及了ARP协议的基本原理,包括ARP请求应答.数据包结构以及协议分层标准,今天我们继续讨论大家最感兴趣的话题:ARP攻击原理是什么?通过ARP攻击可以做什么 ...
- [UOJ310] 黎明前的巧克力
Sol 某比赛搬了这题. 首先选择两个不交非空子集且异或和为0的方案数,等价于选择一个异或和为0的集合,并把它分成两部分的方案数. 这显然可以DP来算,设 \(f[i][j]\) 表示前\(i\)个数 ...
- Redis in python
什么是Redis 数据库类型分为两种,关系型和非关系型,Redis是一个非常重要的非关系型数据库. 既然是数据库,就是存储数据的一个空间,或者说是一个软件,非关系就是不再按照一对一多对多等结构进行外键 ...
- 第39章 引用令牌 - Identity Server 4 中文文档(v1.0.0)
访问令牌有两种形式 - 自包含或引用. JWT令牌将是一个自包含的访问令牌 - 它是一个带有声明和过期的受保护数据结构.一旦API了解了密钥材料,它就可以验证自包含的令牌,而无需与发行者进行通信.这使 ...
- Wcf传递的参数实际不为空,但是接收时显示为空。
问题原因:参数大小写不一致引起,服务端接收参数为空 客户端引用 服务端定义
- Java开发笔记(三十三)字符包装类型
正如整型int有对应的包装整型Integer那样,字符型char也有对应的包装字符型Character.初始化字符包装变量也有三种方式,分别是:直接用等号赋值.调用包装类型的valueOf方法.使用关 ...
- 都2019年了,还问GET和POST的区别
摘要: 对比GET与POST. 原文:都9102年了,还问GET和POST的区别 作者:程淇铭 Fundebug经授权转载,版权归原作者所有. 1. 前言 最近看了一些同学的面经,发现无论什么技术岗位 ...