@[toc]
ElasticSearch 系列教程咱们前面已经连着发了三篇了,今天第四篇,咱们来聊一聊 Es 中的动态映射、静态映射以及四种不一样的字段类型。java
本文是松哥所录视频教程的一个笔记,笔记简明扼要,完整内容小伙伴们能够参考视频,视频下载连接:https://pan.baidu.com/s/1oKiV... 提取码: p3sxgit
映射就是 Mapping,它用来定义一个文档以及文档所包含的字段该如何被存储和索引。因此,它其实有点相似于关系型数据库中表的定义。github
动态映射数据库
顾名思义,就是自动建立出来的映射。es 根据存入的文档,自动分析出来文档中字段的类型以及存储方式,这种就是动态映射。数组
举一个简单例子,新建一个索引,而后查看索引信息:app
在建立好的索引信息中,能够看到,mappings 为空,这个 mappings 中保存的就是映射信息。性能
如今咱们向索引中添加一个文档,以下:编码
PUT blog/_doc/1 { "title":"1111", "date":"2020-11-11" }
文档添加成功后,就会自动生成 Mappings:es5
能够看到,date 字段的类型为 date,title 的类型有两个,text 和 keyword。spa
默认状况下,文档中若是新增了字段,mappings 中也会自动新增进来。
有的时候,若是但愿新增字段时,可以抛出异常来提醒开发者,这个能够经过 mappings 中 dynamic 属性来配置。
dynamic 属性有三种取值:
具体配置方式以下,建立索引时指定 mappings(这其实就是静态映射):
PUT blog { "mappings": { "dynamic":"strict", "properties": { "title":{ "type": "text" }, "age":{ "type":"long" } } } }
而后向 blog 中索引中添加数据:
PUT blog/_doc/2 { "title":"1111", "date":"2020-11-11", "age":99 }
在添加的文档中,多出了一个 date 字段,而该字段没有预约义,因此这个添加操做就回报错:
{ "error" : { "root_cause" : [ { "type" : "strict_dynamic_mapping_exception", "reason" : "mapping set to strict, dynamic introduction of [date] within [_doc] is not allowed" } ], "type" : "strict_dynamic_mapping_exception", "reason" : "mapping set to strict, dynamic introduction of [date] within [_doc] is not allowed" }, "status" : 400 }
动态映射还有一个日期检测的问题。
例如新建一个索引,而后添加一个含有日期的文档,以下:
PUT blog/_doc/1 { "remark":"2020-11-11" }
添加成功后,remark 字段会被推断是一个日期类型。
此时,remark 字段就没法存储其余类型了。
PUT blog/_doc/1 { "remark":"javaboy" }
此时报错以下:
{ "error" : { "root_cause" : [ { "type" : "mapper_parsing_exception", "reason" : "failed to parse field [remark] of type [date] in document with id '1'. Preview of field's value: 'javaboy'" } ], "type" : "mapper_parsing_exception", "reason" : "failed to parse field [remark] of type [date] in document with id '1'. Preview of field's value: 'javaboy'", "caused_by" : { "type" : "illegal_argument_exception", "reason" : "failed to parse date field [javaboy] with format [strict_date_optional_time||epoch_millis]", "caused_by" : { "type" : "date_time_parse_exception", "reason" : "Failed to parse with all enclosed parsers" } } }, "status" : 400 }
要解决这个问题,可使用静态映射,即在索引定义时,将 remark 指定为 text 类型。也能够关闭日期检测。
PUT blog { "mappings": { "date_detection": false } }
此时日期类型就回当成文原本处理。
静态映射
略。
es 中动态映射类型推断方式以下:
JSON 中的数据 | 自动推断出来的数据类型 |
---|---|
null | 没有字段被添加 |
true/false | boolean |
浮点数字 | float |
数字 | long |
JSON 对象 | object |
数组 | 数组中的第一个非空值来决定 |
string | text/keyword/date/double/long 都有可能 |
类型 | 取值范围 |
---|---|
long | -2^63到2^63-1 |
integer | -2^31到2^31-1 |
short | -2^15到2^15-1 |
byte | -2^7到2^7-1 |
double | 64 位的双精度 IEEE754 浮点类型 |
float | 32 位的双精度 IEEE754 浮点类型 |
half_float | 16 位的双精度 IEEE754 浮点类型 |
scaled_float | 缩放类型的浮点类型 |
scaled_float 举例:
PUT product { "mappings": { "properties": { "name":{ "type": "text" }, "price":{ "type": "scaled_float", "scaling_factor": 100 } } } }
因为 JSON 中没有日期类型,因此 es 中的日期类型形式就比较多样:
es 内部将时间转为 UTC,而后将时间按照 millseconds-since-the-epoch 的长整型来存储。
自定义日期类型:
PUT product { "mappings": { "properties": { "date":{ "type": "date" } } } }
这个可以解析出来的时间格式比较多。
PUT product/_doc/1 { "date":"2020-11-11" } PUT product/_doc/2 { "date":"2020-11-11T11:11:11Z" } PUT product/_doc/3 { "date":"1604672099958" }
上面三个文档中的日期均可以被解析,内部存储的是毫秒计时的长整型数。
JSON 中的 “true”、“false”、true、false 均可以。
二进制接受的是 base64 编码的字符串,默认不存储,也不可搜索。
定义的时候,指定范围类型便可:
PUT product { "mappings": { "properties": { "date":{ "type": "date" }, "price":{ "type":"float_range" } } } }
插入文档的时候,须要指定范围的界限:
PUT product { "mappings": { "properties": { "date":{ "type": "date" }, "price":{ "type":"float_range" } } } }
指定范围的时,可使用 gt、gte、lt、lte。
es 中没有专门的数组类型。默认状况下,任何字段均可以有一个或者多个值。须要注意的是,数组中的元素必须是同一种类型。
添加数组是,数组中的第一个元素决定了整个数组的类型。
因为 JSON 自己具备层级关系,因此文档包含内部对象。内部对象中,还能够再包含内部对象。
PUT product/_doc/2 { "date":"2020-11-11T11:11:11Z", "ext_info":{ "address":"China" } }
nested 是 object 中的一个特例。
若是使用 object 类型,假若有以下一个文档:
{ "user":[ { "first":"Zhang", "last":"san" }, { "first":"Li", "last":"si" } ] }
因为 Lucene 没有内部对象的概念,因此 es 会将对象层次扁平化,将一个对象转为字段名和值构成的简单列表。即上面的文档,最终存储形式以下:
{ "user.first":["Zhang","Li"], "user.last":["san","si"] }
扁平化以后,用户名之间的关系没了。这样会致使若是搜索 Zhang si 这我的,会搜索到。
此时能够 nested 类型来解决问题,nested 对象类型能够保持数组中每一个对象的独立性。nested 类型将数组中的每一饿对象做为独立隐藏文档来索引,这样每个嵌套对象均可以独立被索引。
{ { "user.first":"Zhang", "user.last":"san" },{ "user.first":"Li", "user.last":"si" } }
优势
文档存储在一块儿,读取性能高。
缺点
更新父或者子文档时须要更新更个文档。
使用场景:
geo_point 就是一个坐标点,定义方式以下:
PUT people { "mappings": { "properties": { "location":{ "type": "geo_point" } } } }
建立时指定字段类型,存储的时候,有四种方式:
PUT people/_doc/1 { "location":{ "lat": 34.27, "lon": 108.94 } } PUT people/_doc/2 { "location":"34.27,108.94" } PUT people/_doc/3 { "location":"uzbrgzfxuzup" } PUT people/_doc/4 { "location":[108.94,34.27] }
注意,使用数组描述,先经度后纬度。
地址位置转 geo_hash:http://www.csxgame.top/#/
GeoJSON | ElasticSearch | 备注 |
---|---|---|
Point | point | 一个由经纬度描述的点 |
LineString | linestring | 一个任意的线条,由两个以上的点组成 |
Polygon | polygon | 一个封闭多边形 |
MultiPoint | multipoint | 一组不连续的点 |
MultiLineString | multilinestring | 多条不关联的线 |
MultiPolygon | multipolygon | 多个多边形 |
GeometryCollection | geometrycollection | 几何对象的集合 |
circle | 一个圆形 | |
envelope | 经过左上角和右下角两个点肯定的矩形 |
指定 geo_shape 类型:
PUT people { "mappings": { "properties": { "location":{ "type": "geo_shape" } } } }
添加文档时须要指定具体的类型:
PUT people/_doc/1 { "location":{ "type":"point", "coordinates": [108.94,34.27] } }
若是是 linestring,以下:
PUT people/_doc/2 { "location":{ "type":"linestring", "coordinates": [[108.94,34.27],[100,33]] } }
存储 IP 地址,类型是 ip:
PUT blog { "mappings": { "properties": { "address":{ "type": "ip" } } } }
添加文档:
PUT blog/_doc/1 { "address":"192.168.91.1" }
搜索文档:
GET blog/_search { "query": { "term": { "address": "192.168.0.0/16" } } }
用于统计字符串分词后的词项个数。
PUT blog { "mappings": { "properties": { "title":{ "type": "text", "fields": { "length":{ "type":"token_count", "analyzer":"standard" } } } } } }
至关于新增了 title.length 字段用来统计分词后词项的个数。
添加文档:
PUT blog/_doc/1 { "title":"zhang san" }
能够经过 token_count 去查询:
GET blog/_search { "query": { "term": { "title.length": 2 } } }
最后,松哥还搜集了 50+ 个项目需求文档,想作个项目练练手的小伙伴不妨看看哦~