ElasticSearch| mapping
Type可以理解为关系型数据库的Table,那每个字段的数据类型是如何定义的呢?
实际上每个Type中的字段是什么数据类型,由mapping定义,如果我们在创建Index的时候,没有设定mapping,系统会自动根据一条数据的格式来推断出该数据对应的字段类型,
mapping除了自动定义,还可以手动定义,但是只能对新加的、没有数据的字段进行定义,一旦有了数据就无法再做修改了。
实际上每个type中的字段是什么数据类型,由mapping定义。
但是如果没有设定mapping系统会自动,根据一条数据的格式来推断出应该的数据格式。
作用:
定义数据库中的表的结构的定义,通过mapping来控制索引存储数据的设置
- 定义Index下的字段名(Field Name)
- 定义字段的类型,比如数值型、字符串型、布尔型等
- 定义倒排索引相关的配置,比如documentId、记录position、打分等
获取索引mapping; 不进行配置时,自动创建的mapping
请求: GET /movie_index/_mapping
响应: key-word是分词类型
1. Dynamic Mapping与常见字段
Mapping类似数据库中的schema的定义,作用如下:
- 定义索引中字段的名称;
- 定义字段的数据类型,例如字符串,数字,布尔...
- 字段,倒排索引的相关配置,(Analyzed or Not Analyzed, Analyzer)
Mapping会把JSON文档映射成Lucene所需要的扁平格式;
一个Mapping属于一个索引的Type
- 每个文档都属于一个Type
- 一个Type有一个Mapping定义
- 7.0开始,不需要在Mappiing定义中指定type信息
字段的数据类型
① 简单类型
- Text / Keyword
- Date
- Integer / Floating
- Boolean
- IPv4 & IPv6
② 复杂类型 - 对象和嵌套对象
对象类型 / 嵌套类型
③ 特殊类型
geo_point & geo_shape / percolator
Dynamic Mapping
- 在写入文档时候,如果索引不存在,会自动创建索引;
- Dynamic Mapping的机制,使得我们无需手动定义Mappings,Elaticsearch会自动根据文档信息,推算出字段的类型;
- 但是有时候会推算的不对,例如地理位置信息;
- 当类型如果设置不对时,会导致一些功能无法正常运行,例如Range查询。
类型的自动识别
具体推断类型如下:
- true/false → boolean
- 1020 → long
- 20.1 → float
- “2018-02-01” → date
- “hello world” → text +keyword
默认只有text会进行分词,keyword是不会分词的字符串。
ES 依靠json文档字段类型来实现自动识别字段类型,支持的类型
mapping中的字段类型一旦设定后,禁止修改
原因:Lucene实现的倒排索引生成后不允许修改(提高效率)
如果要修改字段的类型,需要从新建立索引,然后做reindex操作
dynamic设置
- true:允许自动新增字段(默认的配置)
- False:不允许自动新增字段,但是文档可以正常写入,无法对字段进行查询操作
- strict:文档不能写入(如果写入会报错)
Index属性,控制当前字段是否索引,默认为true,即记录索引,false不记录,即不可以搜索,比如:手机号、身份证号等敏感信息,不希望被检索
例1:
#写入文档,查看 Mapping
PUT mapping_test/_doc/1
{
"firstName":"Chan",
"lastName": "Jackie",
"loginDate":"2018-07-24T10:29:48.103Z"
}
#查看 Mapping文件, 将firstName字符串推断为了text,并加了一个keyword;把loginDate字符串推断为了一个Date
GET mapping_test/_mapping
#Delete index
DELETE mapping_test
例2:
#dynamic mapping,推断字段的类型
PUT mapping_test/_doc/1
{
"uid" : "123",
"isVip" : false,
"isAdmin": "true",
"age":19,
"heigh":180
}
#查看 Dynamic,将uid,isAdmin等字符推断为了text并加了一个keyword,将isVip布尔推断为了boolean,将age、height推断为了long类型
GET mapping_test/_mapping
当插入一个文档时,如果索引不存在,ES会自动根据文档的类型生成一个mapping文件;
能否更改Mapping的字段类型
两种情况:
① 新增加字段
-
-
- Dynamic设为true,一旦有新增字段的文档写入,Mapping也同时被更新;
- Dynamic设为false,Mapping不会被更新,意味着新增字段的数据无法被索引,但是信息会出现在_source中。
- Dynamic设为Strict,文档写入失败
-
② 对已有字段,一旦已经有数据写入,就不再支持修改字段定义
-
-
- Lucene实现的倒排索引,一旦生成后,就不允许修改。
-
如果希望改变字段类型,必须Reindex API,重建索引。
原因:
如果修改了字段的数据类型,会导致已被索引的属于无法被搜索;
但是如果是增加新的字段,就不会有这样的影响。
控制Dynamic Mappings| true flase strict
出现一个新的文档(包含新的字段),设为true时,文档可以被索引进ES,字段可以被索引搜索到,Mapping也会被更新;其他情况见上面表格。
当Dynamic设为false时候,存在新增字段的数据写入,该数据可以被索引,但是新增字段被丢弃;
当Dynamic设为Strict模式时候,数据写入直接出错。
#----------------------默认Mapping支持dynamic,写入的文档中加入新的字段----------------------
PUT dynamic_mapping_test/_doc/1
{
"newField":"someValue"
}
#该字段可以被搜索,数据也在_source中出现
POST dynamic_mapping_test/_search
{
"query":{
"match":{
"newField":"someValue"
}
}
}
#------------------------------------修改为dynamic false-------------------------
PUT dynamic_mapping_test/_doc/_mapping
{
"dynamic": false
}
#新增 anotherField
PUT dynamic_mapping_test/_doc/10
{
"anotherField":"someValue"
}
#该字段不可以被搜索,因为dynamic已经被设置为false
POST dynamic_mapping_test/_search
{
"query":{
"match":{
"anotherField":"someValue"
}
}
}
#查看索引的Mapping文件, 并没有刚刚新新增的字段anotherField
GET dynamic_mapping_test/_mapping
#查看新增的字段出现在_source中
GET dynamic_mapping_test/_doc/10
#----------------------------------修改为strict------------------------------------
PUT dynamic_mapping_test/_doc/_mapping
{
"dynamic": "strict"
}
#写入数据出错,HTTP Code 400
PUT dynamic_mapping_test/_doc/12
{
"lastField":"value"
}
DELETE dynamic_mapping_test
2. 显示Mapping设置与常见参数
自定义Mapping的建议
① 可以参考API手册,纯手写;
② 为了减少输入的工作量,减少出错概率,可以依照以下步骤:
- 创建一个临时的index,写入一些样本数据
- 通过访问Mapping API获得该临时文件的动态Mapping定义
- 修改后佣,使用该配置创建你的索引
- 删除临时索引
控制当前字段是否被索引
例如用户的手机号就可以设置为false,节省磁盘的开销
常见参数
Index Options
DELETE users
#将mobile的 index 值设置为false
PUT users
{
"mappings" : {
"doc":{
"properties" : {
"firstName" : {
"type" : "text"
},
"lastName" : {
"type" : "text"
},
"mobile" : {
"type" : "text",
"index": false
}
}
}
}
}
PUT users/doc/1
{
"firstName":"Ruan",
"lastName": "Yiming",
"mobile": "12345678"
}
#查询报错 "reason": "Cannot search on field [mobile] since it is not indexed."
POST /users/doc/_search
{
"query": {
"match": {
"mobile":"12345678"
}
}
}
null_value
#设定Null_value
DELETE users
PUT users
{
"mappings" : {
"doc":{
"properties" : {
"firstName" : {
"type" : "text"
},
"lastName" : {
"type" : "text"
},
"mobile" : {
"type" : "keyword",
"null_value": "NULL"
}
}
}
}
}
PUT users/doc/1
{
"firstName":"Ruan",
"lastName": "Yiming",
"mobile": null
}
#在_source中搜索到mobie的值为null
GET users/_search
{
"query": {
"match": {
"mobile":"NULL"
}
}
}
copy_to设置
#设置 Copy to
DELETE users
PUT users
{
"mappings": {
"doc": {
"properties": {
"firstName":{
"type": "text",
"copy_to": "fullName"
},
"lastName":{
"type": "text",
"copy_to": "fullName"
}
}
}
}
}
PUT users/doc/1
{
"firstName":"Ruan",
"lastName": "Yiming"
}
# 查询,但是并没有fullName这个字段,使用了copy_to;但是 _source中并不存在fullName,它只在查询中可以指定
GET users/_search?q=fullName:(Ruan Yiming)
POST users/_search
{
"query": {
"match": {
"fullName":{
"query": "Ruan Yiming",
"operator": "and"
}
}
}
}
数组类型
#数组类型
PUT users/doc/1
{
"name":"onebird",
"interests":"reading"
}
#更新文档
PUT users/doc/1
{
"name":"twobirds",
"interests":["reading","music","sleeping"]
}
##"interests" : [
# "reading",
# "music",
# "sleeping"
# ]
POST users/_search
{
"query": {
"match_all": {}
}
}
#查看mapping看到interests的类型 "type" : "text" 还是text
GET users/_mapping
多字段类型
为索引设置mapping文件时,可以增加一个子字段,比如text类型的,都会默认添加一个keyword的字段;
多字段属性,可以为特定字段如用英文的方式进行分词,增加子字段指定用拼音的方式进行分词。
Index Template
集群上的索引会越来越多,例如,为日志每天创建一个索引;
使用多个索引可以更好的管理数据,提高性能;
- logs-2019-05-01
- logs-2019-05-02
- log-2019-05-03
Index Templates - 帮助你设定Mappings和Settings,并按照一定的规则,自动匹配到新创建的索引之上。
- 模板仅在一个索引被创建时,才会产生作用。修改模板不会影响已创建的索引;
- 可以设定多个索引模板,这些设置会被“merge” 在一起;
- 可以指定“order” 的数值,控制“merging” 的过程。
两个Index Templates
左边的索引模是为数据各设置一个分片一个副本;
右边的索引模板是只要以 test开头的索引主分片数1个,二个副本,(如果字符串符合日期格式的就转换为date类型,在这个模板中把这个功能关闭,同时如果数字的探索设为true)
Index Template的工作方式
当一个索引被新创建时
- 应用Elasticsearch默认的settings和mappings
- 应用order数值低的Index Template中的设定
- 应用order高的Index Template中的设定,之前的设定会被覆盖
- 应用创建索引时,用户指定的Settings和Mappings,并覆盖之前模板中的设定。
#数字字符串被映射成text,日期字符串被映射成日期
PUT ttemplate/_doc/1
{
"someNumber":"1",
"someDate":"2019/01/01"
}
# # someNumber字符类型,推断为text, 外加一个keyword; someDate 字符日期类型会推断为date类型
GET ttemplate/_mapping
{ "ttemplate" : { "mappings" : { "_doc" : { "properties" : { "someDate" : { "type" : "date", "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis" }, "someNumber" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } } }
#Create a default template
PUT _template/template_default
{
"index_patterns": ["*"],
"order" : 0,
"version": 1,
"settings": {
"number_of_shards": 1,
"number_of_replicas":1
}
}
PUT /_template/template_test
{
"index_patterns" : ["test*"],
"order" : 1,
"settings" : {
"number_of_shards": 1,
"number_of_replicas" : 2
},
"mappings" : {
"_doc": {
"date_detection": false,
"numeric_detection": true
}
}
}
#查看template信息
GET /_template/template_default
#通过通配符查看所有的template
GET /_template/temp*
#写入新的数据,index以test开头
PUT testtemplate/_doc/1
{
"someNumber":"1",
"someDate":"2019/01/01"
}
#可以看到日期字符型的类型变成了 text;someNumber "1"字符型数字 变成long
GET testtemplate/_mapping
GET testtemplate/_settings
#创建一个索引, 查看是否匹配到索引模板了
PUT testmy
{
"settings":{
"number_of_replicas":5
}
}
##往索引中插入一个文档 ,看number_of_replicas是几个
PUT testmy/_doc/1
{
"key":"value"
}
# 发现匹配到了template_test, "number_of_replicas" : "5" overwrite了
GET testmy/_settings
Dynamic Template
前边index template应用于所有的index上面,dynamic template应用于具体的索引上面。
根据Elasticsearch识别的数据类型,结合字段名称,来动态设定字段类型
- 所有的字符串类型都设定成keyword,或者关闭keyword字段
- is开头的字段都设置成boolean
- long_开头的都设置成long类型
Dynamic Template
匹配规则参数
#Dynaminc Mapping 根据类型和字段名
DELETE my_index
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}
##自动推断firstName为text keyword, isVIP为 text keyword
GET my_index/_mapping
DELETE my_index
PUT my_index
{
"mappings": {
"_doc": {
"dynamic_templates": [
{
"strings_as_boolean": {
"match_mapping_type": "string",
"match":"is*",
"mapping": {
"type": "boolean"
}
}
},
{
"strings_as_keywords": {
"match_mapping_type": "string",
"mapping": {
"type": "keyword"
}
}
}
]
}
}
}
PUT my_index/_doc/1
{
"firstName":"Ruan",
"isVIP":"true"
}
##匹配模板, firstName为keyword, isVIP为 boolean
GET my_index/_mapping
DELETE my_index
#结合路径, 设置一个新的template, 把name底下除了middle 都会把值copy到full_name上去,text类型的
PUT my_index
{
"mappings": {
"_doc": {
"dynamic_templates": [
{
"full_name": {
"path_match": "name.*",
"path_unmatch": "*.middle",
"mapping": {
"type": "text",
"copy_to": "full_name"
}
}
}
]
}
}
}
PUT my_index/_doc/1
{
"name": {
"first": "John",
"middle": "Winston",
"last": "Lennon"
}
}
#检索文档 ,在full_name上查询就可以查询到相应的结果了
GET my_index/_search?q=full_name:John