Elasticsearch从入门到放弃:瞎说Mapping
前面我们聊了 Elasticsearch 的索引、搜索和分词器,今天再来聊另一个基础内容—— Mapping。
Mapping 在 Elasticsearch 中的地位相当于关系型数据库中的 schema,它可以用来定义索引中字段的名字、定义字段的数据类型,还可以用来做一些字段的配置。从 Elasticsearch 7.0开始,Mapping 中不在乎需要定义 type 信息了,具体原因可以看官方的解释。
字段的数据类型
我们刚刚提到 Mapping 中可以定义字段的数据类型,这可能是 Mapping 最常用的功能了,所以我们先来看看 Elasticsearch 都支持哪些数据类型。
- 简单类型:text、keyword、date、long、double、boolean、ip
- 复杂类型:对象类型、嵌套类型
- 特殊类型:用于描述地理位置的 geo_point、geo_shape
Elasticsearch 支持的数据类型远不止这些,由于篇幅原因,这里就不一一列举了。我找几个工作中常见的来介绍一下。
首先就是字符串了,Elasticsearch 中的字符串有 text 和 keyword 两种。其中 text 类型的字符串是可以被全文检索的,它会被分词器作用,
PUT my_index
{
"mappings": {
"properties": {
"full_name": {
"type": "text"
}
}
}
}
在设置字段类型为 text 时,还可以利用一些参数对这个字段进行更进一步的定制。
index:标记这个字段是否能被搜索,默认是 true
search_analyzer:被搜索时所使用的分词器,默认使用 setting 中设置的分词器
fielddata:字段是否允许在内存中进行排序、聚合,默认是 false
meta:关于字段的一些元数据
像一些id、邮箱、域名这样的字段,我们就需要使用 keyword 类型了。因为 keyword 类型可以支持排序、聚合,并且只能支持精确查询。
有些同学可能会把 ID 设置为数字类型,这也是没问题的,数字类型和 keyword 各有各的好处,使用数字类型可以进行范围查找,而使用 keyword 类型则有更高的查询效率。具体用哪种还要看使用场景。
日期类型在 Elasticsearch 中有三种表现形式
- 可以格式化成日期类型的字符串,如
"2020-07-26"和"2015/01/01 12:10:30"这样的 - 毫秒级时间戳用 long 类型表示
- 秒级时间戳用 integer 类型表示
在 Elasticsearch 内部,日期类型是以 long 类型的毫秒级时间戳存储的,时区使用的是0时区。
我们可以自定义时间格式,默认使用的是strict_date_optional_time||epoch_millis
strict_date_optional_time_nanos是通用的日期格式解析,至少要包含年份,如果要包含时间,则用T分隔,例如yyyy-MM-dd'T'HH:mm:ss.SSSSSSZ或 yyyy-MM-dd。
如果想要同时支持多种日期格式,可以使用format字段
PUT my_index
{
"mappings": {
"properties": {
"date": {
"type": "date",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis"
}
}
}
}
Mapping参数
刚才我们提到配置 Mapping 的日期格式的参数format,Mapping 还提供了很多其他的参数。
- analyzer
- boost
- coerce
- copy_to
- doc_values
- dynamic
- eager_global_ordinals
- enabled
- fielddata
- fields
- format
- ignore_above
- ignore_malformed
- index_options
- index_phrases
- index_prefixes
- index
- meta
- normalizer
- norms
- null_value
- position_increment_gap
- properties
- search_analyzer
- similarity
- store
- term_vector
我们来介绍几个常用的字段。
fields
首先是fields,它可以使同一个字段通过不同的方式实现不同的目的。
例如,我们可以对一个字符串字段设置为text类型,用于全文检索,同时可以利用fields设置为keyword类型,用于排序和聚合。
PUT my-index-000001
{
"mappings": {
"properties": {
"city": {
"type": "text",
"fields": {
"raw": {
"type": "keyword"
}
}
}
}
}
}
查询时我们就可以使用city进行全文检索,使用city.raw进行排序和聚合。
GET my-index-000001/_search
{
"query": {
"match": {
"city": "york"
}
},
"sort": {
"city.raw": "asc"
},
"aggs": {
"Cities": {
"terms": {
"field": "city.raw"
}
}
}
}
enabled
有些时候,我们只想把某个字段作为数据存储来使用,并不需要用来做搜索,这时,我们就可以将这个字段禁用掉,字段被禁用以后,它所保存的值也不受 mapping 指定的类型控制。
PUT my-index-000001
{
"mappings": {
"properties": {
"user_id": {
"type": "keyword"
},
"last_updated": {
"type": "date"
},
"session_data": {
"type": "object",
"enabled": false
}
}
}
}
上面的例子中,我们禁用掉了 session_data 这个字段,这时,你既可以往 session_data 字段中存储 JSON 格式的数据,也可以存储非 JSON 格式的数据。
除了针对于单个字段的禁用以外,我们还可以直接禁用掉整个 mapping。我们来重新创建一个index
PUT my-index-000002
{
"mappings": {
"enabled": false
}
}
这时,文档所有的字段都不会被索引,只是用来存储。
需要注意的是,无论是具体字段中还是整个 mapping 的 enabled 属性都不可以被修改,因为一旦设置为 false,Elasticsearch 就不会对字段进行索引了,也不会校验数据的合法性,如果产生了脏数据以后再设置为 true,就会造成程序错误。
null_value
null 在 Elasticsearch 中是不可以被索引或搜索的,这里我们所说的 null 并不是狭义上某种语言的 null,而是所有的空值。例如所有值都是 null 的数组,总之,这里的定义就是没有值。
对于有需要搜索空值的业务怎么办呢?Elasticsearch 为我们提供了 null_value 这个参数,它可以指定一个值,搜索时使用这个值来替代空值。
举个栗子
PUT my-index-000001
{
"mappings": {
"properties": {
"status_code": {
"type": "keyword",
"null_value": "NULL"
}
}
}
}
我们给 status_code 字段设置了 null_value 为 "NULL"。这里需要注意, null_value 的类型必须与要查找的数据类型相同,如果在这个例子中 status_code 的类型是long,那么就不能把null_value 设置为 "NULL"。
dynamic
对于新增加的字段:
- dynamic 设置为 true 时,一旦有新增字段的文档写入,Mapping 也会被更新
- dynamic 设置为 false 时,Mapping 不会被更新,新增字段无法被索引,但信息会出现在
_source中 - dynamic 设置为 strict 时,文档写入失败
对于已有的字段,一旦已经有数据写入,就不再支持修改字段定义
Dynamic Mapping
我们在创建索引时,可以不用手动写 Mappings, Elasticsearch 会帮我们自动识别出字段的类型。我们称之为 Dynamic Mapping。不过有时推算的可能不是很准确。
Elasticsearch 自动识别类型是基于 JSON 的。数据类型的对应关系如下(表格来自 elastic 官网)
| JSON data type | Elasticsearch data type |
|---|---|
null |
No field is added. |
true or false |
boolean field |
| floating point number | float field |
| integer | long field |
| object | object field |
| array | Depends on the first non-null value in the array. |
| string | Either a date field (if the value passes date detection), a double or long field (if the value passes numeric detection) or a text field, with a keyword sub-field. |
Elasticsearch 支持的字段映射的数据类型在这个文档中,除了这些,其他的类型映射都需要显示的指定了。
关于日期类型,默认是可以映射的,但是 Elasticsearch 只能识别几种格式的日期yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis。如果关掉了 date_detection 开关,那么就只能识别为字符串了。
PUT my-index-000001
{
"mappings": {
"date_detection": false
}
}
当然,你也可以根据需要自己指定要识别的日期格式,只需要使用 dynamic_date_formats 参数即可。
PUT my-index-000001
{
"mappings": {
"dynamic_date_formats": ["MM/dd/yyyy"]
}
}
Elasticsearch 还提供了一种把字符串型的数字识别为数字的能力,它是由 numeric_detection 开关控制的。
PUT my-index-000005
{
"mappings": {
"numeric_detection": true
}
}
PUT my-index-000005/_doc/1
{
"my_float": "1.0",
"my_integer": "1"
}
在这个例子中,my_float 会被识别为 float 类型,而 my_integer 会被识别为 long 类型。
Dynamic template
dynamic template 允许我们自定义 mapping ,并应用到具体索引上。dynamic template 的定义一般是这样的
"dynamic_templates": [
{
"my_template_name": {
... match conditions ...
"mapping": { ... }
}
},
...
]
my_template_name 可以是任意字符串。
match conditions 包括match_mapping_type, match, match_pattern, unmatch, path_match, path_unmatch 这几种。
mapping 就是指匹配到的字段应该使用怎样的 mapping。下面我们介绍几种 match conditions
match_mapping_type
我们先来看一个简单的例子
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"integers": {
"match_mapping_type": "long",
"mapping": {
"type": "integer"
}
}
},
{
"strings": {
"match_mapping_type": "string",
"mapping": {
"type": "text",
"fields": {
"raw": {
"type": "keyword",
"ignore_above": 256
}
}
}
}
}
]
}
}
这里我们有两个模版,其一是使用 integer 类型来代替 long 类型,其二是将字符串类型映射为 keyword。
match 和 unmatch
这两个比较简单,match 是指匹配到模式的字段, unmatch 是表示不匹配的字段。
PUT my-index-000001
{
"mappings": {
"dynamic_templates": [
{
"longs_as_strings": {
"match_mapping_type": "string",
"match": "long_*",
"unmatch": "*_text",
"mapping": {
"type": "long"
}
}
}
]
}
}
在这个例子中,我们需要的是 long_ 开头的字符串,不需要 _text结尾的字符串字段。
除了以上三种之外,其他的就是 match_pattern 用来进行正则匹配,path_match 和 path_unmatch 则是表示字段所在路径的是否匹配。
另外 dynamic template 还支持两种变量替换,分别是 {name} 和 {dynamic_type}。其实 name 就是字段名,dynamic_type 就是检测出的字段类型。
总结
关于 Elasticsearch 的 mapping 我们就先聊这些,我认为 mapping 的配置是一个需要经验的事情,当你处理的 case 越来越多之后,就能比较轻松的知道如何更好的配置 mapping 了。此外,mapping 的许多字段和参数文中都没有涉及,对于我而言,大部分都是用到了现查文档,不过也还是建议大家看一看文档,起码遇到问题时能知道大概查找文档的一个方向。这样就会比身边人强不少。
Elasticsearch从入门到放弃:瞎说Mapping的更多相关文章
- Elasticsearch从入门到放弃:分词器初印象
Elasticsearch 系列回来了,先给因为这个系列关注我的同学说声抱歉,拖了这么久才回来,这个系列虽然叫「Elasticsearch 从入门到放弃」,但只有三篇就放弃还是有点过分的,所以还是回来 ...
- Elasticsearch从入门到放弃:索引基本使用方法
前文我们提到,Elasticsearch的数据都存储在索引中,也就是说,索引相当于是MySQL中的数据库.是最基础的概念.今天分享的也是关于索引的一些常用的操作. 创建索引 curl -X PUT & ...
- Elasticsearch从入门到放弃:文档CRUD要牢记
在Elasticsearch中,文档(document)是所有可搜索数据的最小单位.它被序列化成JSON存储在Elasticsearch中.每个文档都会有一个唯一ID,这个ID你可以自己指定或者交给E ...
- Elasticsearch从入门到放弃:再聊搜索
在前文中我们曾经聊过搜索文档的方法,Elasticsearch 一般适用于读多写少的场景,因此我们需要更多的关注读操作. Elasticsearch 提供的 Search API 可以分为 URI S ...
- Elasticsearch从入门到放弃:浅谈算分
今天来聊一个 Elasticsearch 的另一个关键概念--相关性算分.在查询 API 的结果中,我们经常会看到 _score 这个字段,它就是用来表示相关性算分的字段,而相关性就是描述一个文档和查 ...
- elasticsearch入门到放弃之elasticsearch-head
elasticsearch-head可理解为跟DBeaver一样是一个数据可视化工具,但是这个工具并没有理想中那么好用坑也是很多,我已经在我的github上fork了一份修改后的版本:https:// ...
- Go从入门到放弃
Go语言介绍 为什么你应该学习Go语言? 开发环境准备 从零开始搭建Go语言开发环境 VS Code配置Go语言开发环境 Go语言基础 Go语言基础之变量和常量 Go语言基础之基本数据类型 Go语言基 ...
- CYQ.Data 从入门到放弃ORM系列:开篇:自动化框架编程思维
前言: 随着CYQ.Data 开始回归免费使用之后,发现用户的情绪越来越激动,为了保持这持续的激动性,让我有了开源的念头. 同时,由于框架经过这5-6年来的不断演进,以前发的早期教程已经太落后了,包括 ...
- [精品书单] C#/.NET 学习之路——从入门到放弃
C#/.NET 学习之路--从入门到放弃 此系列只包含 C#/CLR 学习,不包含应用框架(ASP.NET , WPF , WCF 等)及架构设计学习书籍和资料. C# 入门 <C# 本质论&g ...
随机推荐
- 利用docker部署oxidized网络设备备份系统
随着网络设备的增多,通过人手备份网络设备倍感压力,而且效率低.有编程基础的人可能会通过Python的parimiko 或者netmiko 连接到设备操作 把文件通过ftp 上传到FTP服务器, 在通过 ...
- XSS与CSRF定义
一. CSRF 1. CSRF的基本概念 跨站请求伪造(英语:Cross-site request forgery),也被称为 one-click attack 或者 session riding,通 ...
- error rabbitMQ:Error: unable to perform an operation on node 'rabbit@xxxx'.
C:\Program Files\RabbitMQ Server\rabbitmq_server-3.7.4\sbin>rabbitmqctl list_queues Error: unable ...
- SQLAlchemy01 /SQLAlchemy去连接数据库、ORM介绍、将ORM模型映射到数据库中
SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到数据库中 目录 SQLAlchemy01 /SQLAlchemy去连接数据库.ORM介绍.将ORM模型映射到 ...
- Python函数03/函数名的第一类对象及使用/f 格式化/迭代器/递归
Python函数03/函数名的第一类对象及使用/f 格式化/迭代器/递归 目录 Python函数03/函数名的第一类对象及使用/f 格式化/迭代器/递归 内容纲要 1.函数名的第一类对象及使用 2.f ...
- 使用Typora写博客,图片即时上传,无需第三方图床-EasyBlogImageForTypora
背景 习惯使用markdown的人应该都知道Typora这个神器,它非常简洁高效.虽然博客园的在线markdown编辑器也不错,但毕竟是网页版,每次写东西需要登录系统-进后台-找到文章-编辑-保存草稿 ...
- 微信小程序wx.switchTab跳转到tab页面后onLoad里面的方法不执行
相信大家在做小程序的时候启动页跳转到tab首页会用到switchTab 但是在跳转后发现页面模块不全,后面console.log()后发现是onLoad里面的方法不执行 解决这种问题的方法页有很多中, ...
- CCNA - Part7:网络层 - ICMP 应该是你最熟悉的协议了
ICMP 协议 在之前网络层的介绍中,我们知道 IP 提供一种无连接的.尽力而为的服务.这就意味着无法进行流量控制与差错控制.因此在 IP 数据报的传输过程中,出现各种的错误是在所难免的,为了通知源主 ...
- Oracle数据泵详解
一.EXPDP和IMPDP使用说明 Oracle Database 10g引入了最新的数据泵(Data Dump)技术,数据泵导出导入(EXPDP和IMPDP)的作用 1)实现逻辑备份和逻辑恢复. 2 ...
- 通过PHP工具箱-站点域名管理(创建本地虚拟主机)
工具:php程序员工具箱(网上很多请自己搜索下载) 1.点击其它选项菜单 -> 选择站点域名管理.如下图 2.进入站点域名管理.如下图(初始的时候,站点为空) 3.设置站点管理.如下图 网站域名 ...