Elasticsearch实践(三):Mapping
版本:Elasticsearch 6.2.4。
Mapping类似于数据库中的表结构定义,主要作用如下:
- 定义Index下字段名(Field Name)
- 定义字段的类型,比如数值型,字符串型、布尔型等
- 定义倒排索引的相关配置,比如是否索引、记录postion等
Mapping完整的内容可以分为四部分内容:
- 字段类型(Field datatypes)
- 元字段(Meta-Fields)
- Mapping参数配置(Mapping parameters)
- 动态Mapping(Dynamic Mapping)
自动Mapping
如果没有手动设置Mapping,Elasticsearch默认会自动解析出类型,且每个字段以第一次出现的为准。
下面我们先看一下Elasticsearch默认创建的Mapping是什么样的。
首先我们创建一个索引:
PUT /user/
查询索引信息:
GET /user
结果:
{
"user": {
"aliases": {},
"mappings": {},
"settings": {
"index": {
"creation_date": "1540044686190",
"number_of_shards": "5",
"number_of_replicas": "1",
"uuid": "_K5b8w7jRiuthf7QeQZhdw",
"version": {
"created": "5060299"
},
"provided_name": "user"
}
}
}
}
增加一条数据:
PUT /user/doc/1
{
"name":"Allen Yer",
"job":"php",
"age":22
}
PUT /user/doc/2
{
"name":"Allen Yer",
"job":0,
"age":22
}
查询数据是否新增成功:
GET /user/doc/_count
结果:
{
"count": 2,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
}
}
count为2,说明新增成功。然后我们查询下 mapping :
{
"user": {
"mappings": {
"doc": {
"properties": {
"age": {
"type": "long"
},
"job": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
}
}
}
发现自动为每个字段设置了类型:
- name: text类型,另外额外增加了
name.keyword
字段,keyword
类型; - job:text类型,另外额外增加了
job.keyword
字段,keyword
类型;虽然第二次数据新增是数字类型,但还是以第一次为主; - age:long类型。
大家可以把索引删掉,将新增数据调整为先新增第2条,再新增第一条,发现报错了:
DELETE /user
PUT /user/doc/2
{
"name":"Allen Yer",
"job":0,
"age":22
}
PUT /user/doc/1
{
"name":"Allen Yer",
"job":"php",
"age":22
}
报错:
{
"error": {
"root_cause": [
{
"type": "mapper_parsing_exception",
"reason": "failed to parse [job]"
}
],
"type": "mapper_parsing_exception",
"reason": "failed to parse [job]",
"caused_by": {
"type": "number_format_exception",
"reason": "For input string: \"php\""
}
},
"status": 400
}
也能说明以第一次为主以字段第一次的值类型为准。这也说明了默认创建mapping可能不是我们想要的,这就需要手动创建mapping,好处有:
- 提前指定字段(通过设置甚至可以达到禁止自动增加字段的效果)
- 合理设置字段类型,防止分词过多或者解析不合理。分词过大会导致磁盘空间占用大。
手动创建mapping
这次我们删掉mapping,并手动创建一个:
DELETE /user
PUT /user/
{
"mappings": {
"doc": {
"properties": {
"name": {
"type": "text",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
},
"age": {
"type": "long",
"index": false
},
"job": {
"type": "keyword"
},
"intro":{
"type":"text"
},
"create_time": {
"type": "date",
"format": "epoch_second"
}
}
}
}
}
字段类型说明:
- name:text类型,会进行分词,支持模糊检索。
- name.keyword : 这相当于是嵌套了一个字段,keyword类型,只能精确匹配,不支持分词。超过256字符长度不索引,也就没法搜索到。
- age:long类型,支持精确匹配。
- job:keyword类型,只能精确匹配,不支持分词。
- intro:text类型,会进行分词,支持模糊检索。
- create_time:date类型,支持10位时间戳。
注意:mapping生成后是不允许修改(包括删除)的。所以需要提前合理的的定义mapping。
字段类型
Elasticsearch支持文档中字段的许多不同数据类型:
普通数据类型
字符串类型
有text
和 keyword
2种 。其中 text
支持分词,用于全文搜索;keyword
不支持分词,用于聚合和排序。在旧的ES里这两个类型由string
表示。
如果安装了IK分词插件,我们可以为text
类型指定IK分词器。一般来说,对于字符串类型,如果:
- 模糊搜索+精确匹配,一般是name或者title字段:
"name": {
"type": "text",
"analyzer": "ik_smart",
"fields": {
"keyword": {
"type": "keyword",
"ignore_above": 256
}
}
}
- 模糊搜索,一般是内容详情字段:
"content": {
"type": "text",
"analyzer": "ik_smart"
}
- 精确匹配:
"name": {
"type": "keyword"
}
- 不需要索引:
"url": {
"type": "keyword",
"index": false
}
数字类型
支持 long,integer,short,byte,double,float,half_float,scaled_float。具体说明如下:
long
带符号的64位整数,其最小值为-2^63
,最大值为(2^63)-1
。integer
带符号的32位整数,其最小值为-2^31
,最大值为(23^1)-1
。short
带符号的16位整数,其最小值为-32,768,最大值为32,767。byte
带符号的8位整数,其最小值为-128,最大值为127。double
双精度64位IEEE 754浮点数。float
单精度32位IEEE 754浮点数。half_float
半精度16位IEEE 754浮点数。scaled_float
缩放类型的的浮点数。需同时配置缩放因子(scaling_factor)一起使用。
对于整数类型(byte,short,integer和long)而言,我们应该选择这是足以使用的最小的类型。这将有助于索引和搜索更有效。
对于浮点类型(float、half_float和scaled_float),-0.0
和+0.0
是不同的值,使用term
查询查找-0.0
不会匹配+0.0
,同样range
查询中上边界是-0.0
不会匹配+0.0
,下边界是+0.0
不会匹配-0.0
。
其中scaled_float
,比如价格只需要精确到分,price
为57.34
的字段缩放因子为100
,存起来就是5734
。优先考虑使用带缩放因子的scaled_float
浮点类型。
示例:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"status": {
"type": "byte"
},
"year": {
"type": "short"
},
"id": {
"type": "long"
},
"price": {
"type": "scaled_float",
"scaling_factor": 100
}
}
}
}
}
日期类型
类型为 date
。
JSON本身是没有日期类型的,因此Elasticsearch中的日期可以是:
- 包含格式化日期的字符串。
- 一个13位long类型表示的毫秒时间戳( milliseconds-since-the-epoch)。
- 一个integer类型表示的10位普通时间戳(seconds-since-the-epoch)。
在Elasticsearch内部,日期类型会被转换为UTC(如果指定了时区)并存储为long类型表示的毫秒时间戳。
日期类型可以使用使用format
自定义,默认缺省值:"strict_date_optional_time||epoch_millis"
:
"postdate": {
"type": "date",
"format": "strict_date_optional_time||epoch_millis"
}
format
有很多内置类型,这里列举部分说明:
- strict_date_optional_time, date_optional_time
通用的ISO日期格式,其中日期部分是必需的,时间部分是可选的。例如 "2015-01-01"或"2015/01/01 12:10:30"。 - epoch_millis
13位毫秒时间戳 - epoch_second
10位普通时间戳
其中strict_
开头的表示严格的日期格式,这意味着,年、月、日部分必须具有前置0。
当然也可以自定义日期格式,例如:
"postdate":{
"type":"date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
}
注意:如果新文档的字段的值与format里设置的类型不兼容,ES会返回失败。示例:
PUT my_index
{
"mappings": {
"_doc": {
"properties": {
"date": {
"type": "date",
"format":"epoch_millis"
}
}
}
}
}
PUT my_index/_doc/1
{
"date":1543151405000
}
PUT my_index/_doc/2
{
"date":1543151405
}
PUT my_index/_doc/3
{
"date":"2018-11-25 21:10:43"
}
GET my_index/_doc/_search
第3条数据插入失败,因为只接受长整数的时间戳,字符串类型的日期是不匹配的。第2条的值只有10位数,虽然值是不正确的,但是在epoch_millis
的取值范围内,所以也是成功的。
布尔类型
类型为 boolean
。
二进制类型
类型为 binary
。
范围类型
integer_range,float_range,long_range,double_range,date_range
复杂类型
- 数组数据类型
在ElasticSearch中,没有专门的数组(Array)数据类型,但是,在默认情况下,任意一个字段都可以包含0或多个值,这意味着每个字段默认都是数组类型,只不过,数组类型的各个元素值的数据类型必须相同。在ElasticSearch中,数组是开箱即用的(out of box),不需要进行任何配置,就可以直接使用。,例如:
字符型数组: [ "one", "two" ]
整型数组:[ 1, 2 ]
数组型数组:[ 1, [ 2, 3 ]]
等价于[ 1, 2, 3 ]
对象数据类型
object 对于单个JSON对象。JSON天生具有层级关系,文档可以包含嵌套的对象。嵌套数据类型
nested 对于JSON对象的数组
Geo数据类型
地理点数据类型
geo_point 对于纬度/经度点Geo-Shape数据类型
geo_shape 对于像多边形这样的复杂形状
专用数据类型
IP数据类型
ip 用于IPv4和IPv6地址完成数据类型
completion 提供自动完成的建议令牌计数数据类型
token_count 计算字符串中的标记数mapper-murmur3
murmur3 在索引时计算值的哈希值并将它们存储在索引中过滤器类型
接受来自query-dsl的查询join 数据类型
为同一索引中的文档定义父/子关系
多字段
为不同目的以不同方式索引相同字段通常很有用。例如,string可以将字段映射为text用于全文搜索的keyword字段,以及用于排序或聚合的字段。或者,您可以使用standard分析仪, english分析仪和 french分析仪索引文本字段。
元字段
_all
该字段用于在没有指定具体字段的情况下进行模糊搜索,可以搜索全部字段的内容。
原理是将所有字段的内容视为字符串,拼在一起放在一个_all
字段上,但这个字段默认是不被存储的,可以被搜索。在query_string
与 simple_query_string
查询(Kibana搜索框用的这种查询方式)默认也是查询_all
字段。
6.x
版本被默认关闭。
相关设置:
PUT my_index
{
"mappings": {
"my_type": {
"_all": {
"enabled": true,
"store": false
},
"properties": {}
}
},
"settings": {
"index.query.default_field": "_all"
}
}
上述配置在5.x
版本是默认配置:
- 默认开启
_all
字段 - 默认不存储
_all
字段 - 默认搜索
_all
字段
如果从CPU性能及磁盘空间考虑,可以考虑可以完全禁用或基于每个字段自定义_all
字段。
假设_all
字段被禁用,则URI搜索请求、 query_string
和simple_query_string
查询将无法将其用于查询。我们可以将它们配置为其他字段:通过定义 index.query.default_field
属性。
_source
这个字段用于存储原始的JSON文档内容,本身不会被索引,但是搜索的时候被返回。如果没有该字段,虽然还能正常搜索,但是返回的内容不知道对应的是什么。
示例:
GET /user/doc/_search?q=name
结果:
{
"took": 4,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 1,
"max_score": 0.2876821,
"hits": [
{
"_index": "user",
"_type": "doc",
"_id": "1",
"_score": 0.2876821,
"_source": {
"name": "this is test name",
"age": 22,
"job": "java",
"intro": "the intro can not be searched by singal",
"intro2": "去朝阳公园",
"create_time": 1540047542
}
}
]
}
}
搜索结果就包含_source
字段,存储的是原始文档内容。如果被禁用,只知道有匹配内容,但是无法知道返回的是什么。所以需要谨慎关闭该字段。
如果想禁用该字段,可以在创建Mapping的时候,设置_:
{
"mappings": {
"_doc": {
"_source": {
"enabled": false
}
}
}
}
_type
ElasticSearch里面有 index 和 type 的概念:index称为索引,type为文档类型,一个index下面有多个type,每个type的字段可以不一样。这类似于关系型数据库的 database 和 table 的概念。
但是,ES中不同type下名称相同的filed最终在Lucene中的处理方式是一样的。所以后来ElasticSearch团队想去掉type,于是在6.x版本为了向下兼容,一个index只允许有一个type。
该字段再在6.0.0中弃用。在Elasticsearch 6.x 版本中创建的索引只能包含单个type。在5.x中创建的含有多个type的索引将继续像以前一样在Elasticsearch 6.x中运行。type 将在Elasticsearch 7.0.0中完全删除。
详见:https://www.elastic.co/guide/en/elasticsearch/reference/current/removal-of-types.html
参考
1、Mapping | Elasticsearch Reference [6.4] | Elastic
https://www.elastic.co/guide/en/elasticsearch/reference/current/mapping.html
2、Elasticsearch 6.x Mapping设置 - 小旋锋
https://mp.weixin.qq.com/s/pBPH-wccdY1oslpqGgAHBg
3、整理的es中的mapping方面的内容 - 辛星,前进的路上. - CSDN博客
https://blog.csdn.net/xinguimeng/article/details/51588583
4、[译]ElasticSearch数据类型--string类型已死, 字符串数据永生 - 牧曦之晨 - SegmentFault 思否
https://segmentfault.com/a/1190000008897731
5、ElasticSearch的_all域 | 学步园
https://www.xuebuyuan.com/2053874.html
6、图解Elasticsearch中的_source、_all、store和index属性 - 1.01^365=37.78 (Lucene、ES、ELK开发交流群: 370734940) - CSDN博客
https://blog.csdn.net/napoay/article/details/62233031
7、Elasticsearch - 自动检测及动态映射Dynamic Mapping - 上善若水,水善利万物而不争。 - CSDN博客
https://blog.csdn.net/xifeijian/article/details/51090338
8、Field datatypes | Elasticsearch Reference [6.2] | Elastic
https://www.elastic.co/guide/en/elasticsearch/reference/6.2/mapping-types.html
Elasticsearch实践(三):Mapping的更多相关文章
- 第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理
第三百六十四节,Python分布式爬虫打造搜索引擎Scrapy精讲—elasticsearch(搜索引擎)的mapping映射管理 1.映射(mapping)介绍 映射:创建索引的时候,可以预先定义字 ...
- ElasticSearch第三步-中文分词
ElasticSearch系列学习 ElasticSearch第一步-环境配置 ElasticSearch第二步-CRUD之Sense ElasticSearch第三步-中文分词 ElasticS ...
- elasticsearch中的mapping映射配置与查询典型案例
elasticsearch中的mapping映射配置与查询典型案例 elasticsearch中的mapping映射配置示例比如要搭建个中文新闻信息的搜索引擎,新闻有"标题".&q ...
- WebSocket原理与实践(三)--解析数据帧
WebSocket原理与实践(三)--解析数据帧 1-1 理解数据帧的含义: 在WebSocket协议中,数据是通过帧序列来传输的.为了数据安全原因,客户端必须掩码(mask)它发送到服务器的所有 ...
- Linux及安全实践三——程序破解
Linux及安全实践三--程序破解 一.基本知识 常用指令机器码 指令 作用 机器码 nop 无作用(no operation) 90 call 调用子程序,子程序以ret结尾 e8 ret 返回程序 ...
- nodejs 实践:express 最佳实践(三) express 解析
nodejs 实践:express 最佳实践(三) express 解析 nodejs 发展很快,从 npm 上面的包托管数量就可以看出来.不过从另一方面来看,也是反映了 nodejs 的基础不稳固, ...
- ElasticSearch(三):通分词器(Analyzer)进行分词(Analysis)
ElasticSearch(三):通过分词器(Analyzer)进行分词(Analysis) 学习课程链接<Elasticsearch核心技术与实战> Analysis与Analyzer ...
- ElasticSearch实践系列(三):探索数据
前言 经过前两篇文章得实践,我们已经了解了ElasticSearch的基础知识,本篇文章让我来操作一些更真实的数据集.我们可以利用www.json-generator.com/生成如下的文档结构: { ...
- 贷前系统ElasticSearch实践总结
贷前系统负责从进件到放款前所有业务流程的实现,其中涉及一些数据量较大.条件多样且复杂的综合查询,引入ElasticSearch主要是为了提高查询效率,并希望基于ElasticSearch快速实现一个简 ...
随机推荐
- 使用kbmmw中的随机数替换delphi 10.3 自带的随机数
我们在开发中经常会使用随机数模拟各种随机条件,例如生成唯一的密码和令牌. 在计算机中,一般采用PRNG(伪随机序列发生器)模拟真实随机数.既然是随机,就要要没有任何规律, 在取值范围内均匀.独立.以确 ...
- JB的IDE可视化MongoDB、MySQL数据库信息
一.问题: 在使用JB的IDE的时候(pycharm.IDEA等)可视化mysql和mongodb的数据库信息,效果如下 MySQL: MongoDB: 可视化数据表关系: 二.方法: 1.MySQ ...
- npm -S -D -g i 有什么区别
npm i module_name -S = > npm install module_name --save 写入到 dependencies 对象 //开发环境能使用,生产环境也能使用or ...
- JQuery跳出each循环的方法
一.jquery each循环,要实现break和continue的功能: break----用return false; continue --用return ture; 二.jquery怎么跳出当 ...
- LOJ-10091(强连通分量)
题目链接:传送门 思路: 多少头牛收到所有牛头牛的喜欢,喜欢具有传递性,所以将互相喜欢的牛视为一个点,就是有向图的 缩点,收到所有牛的喜欢要求这个“点”没有出度,所以缩点之后统计所有没有出度的点就是结 ...
- 第一次OO总结
作业1——多项式加减法 看到这个名字就开始瑟瑟发抖了,毕竟一年前用C语言让我写这么一个程序都很头疼,什么堆栈啊还有结构都稀里糊涂的,更别说用一个完全没接触过的语言来完成最简单的一次作业.像我这样越老心 ...
- 洛谷P1443 马的遍历
https://www.luogu.org/problemnew/show/P1443 很经典的搜索题了,蒟蒻用广搜打的 不说了,上代码! #include<bits/stdc++.h> ...
- Javascript Engine, Java VM, Python interpreter, PyPy – a glance
提要: url anchor (ajax) => javascript engine (1~4 articles) => java VM vs. python interpreter =& ...
- Chrome 的 PNaCl 还活着么?
WebAssembly Migration Guide Given the momentum of cross-browser WebAssembly support, we plan to focu ...
- 前端基础之 html
---恢复内容开始--- web服务本质 import socket sock=socket.socket() sock.bind(()) sock.listen() where True: conn ...