Elasticsearch之映射
映射基础
索引创建之后,等于有了关系型数据库中的database,es7.x取消了索引type类型的设置,不允许指定类型,默认为_doc,但字段仍然是有的,我们需要设置字段的约束信息,叫做字段映射(mapping)
字段的约束包括但不限于:
- 字段的数据类型
- 是否要存储
- 是否要索引
- 分词器
我们一起来看下创建的语法。
5.1 创建映射字段
1.创建映射字段
PUT /索引库名/_mapping
{
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器"
} } }
https://www.elastic.co/guide/en/elasticsearch/reference/7.3/mapping-params.html
字段名:任意填写,下面指定许多属性,例如:
type:类型,可以是text、long、short、date、integer、object等
index:是否索引,默认为true
store:是否存储,默认为false
analyzer:指定分词器
5.2 映射属性详解
5.2.1 type(数据类型)
ES中支持的数据类型非常丰富:
https://www.elastic.co/guide/en/elasticsearch/reference/7.3/mapping-types.html
其中几个关键的类型
- String类型,又分为两种:
* text: 可分词,不可参与聚合
* keyword: 不可分词,数据会作为完整的字段进行比配,可以参与聚合
- Numerical: 数值类型,分两类
* 基本数据类型: long,interger,short, double, float, half_float
* 浮点数的高精度类型: scaled_float
需要指定一个精度因子,比如10或者100,ES会把真实值乘以这银因子后存储,取出时再返原
- Date: 日期类型
ES可以对日期格式化为字符串存储,但是建议我们存储为毫秒值,存储为long,节省空间
- Array:数组类型
进行匹配时,任意一个元素满足,都认为满足
排序时,如果升序则用数组中的最小值来排序,如果降序则用数组中的最大值来排序
- Object:对象
如果存储到索引库的是对象类型,例如上面的girl,会把girl变成两个字段:girl.name和girl.age
5.2.2 index(索引)
index影响字段的索引情况。
true:字段会被索引,则可以用来进行搜索。默认值就是true
false:字段不会被索引,不能用来搜索
index的默认值就是true,也就是说你不进行任何配置,所有字段都会被索引。
但是有些字段是我们不希望被索引的,比如企业的logo图片地址,就需要手动设置index为false。
5.2.3 store(是否独立存储)
是否将数据进行独立存储。
原始的文本会存储在 _source 里面,默认情况下其他提取出来的字段都不是独立存储的,是从
_source 里面提取出来的。当然你也可以独立的存储某个字段,只要设置store:true即可,获取独立存
储的字段要比从_source中解析快得多,但是也会占用更多的空间,所以要根据实际业务需求来设置,
默认为false。
5.2.4 analyzer(分词器)
4)analyzer:指定分词器
一般我们处理中文会选择ik分词器 ik_max_word, ik_smart_word
5.3 查看映射关系
5.3.1 查看单个索引映射关系
语法: GET /索引名称/_mapping
5.3.2 查看所有索引映射关系
方式一
GET _mapping
方式二
GET _all/_mapping
5.3.3 修改索引映射关系
注意:修改映射增加字段 做其它更改只能删除索引 重新建立映射
PUT /索引库名/_mapping {
"properties": {
"字段名": {
"type": "类型",
"index": true,
"store": true,
"analyzer": "分词器" } } }
4.一次性创建索引和映射
刚才 的案例中我们是把创建索引库和映射分开来做,其实也可以在创建索引库的同时,直接制定索引库中的索引,基本语法:
put /索引库名称
{
"settings":{
"索引库属性名":"索引库属性值"
},
"mappings":{
"properties":{
"字段名":{
"映射属性名":"映射属性值" } } } }
案例:
PUT /lagou-employee-index
{
"settings": {},
"mappings": {
"properties": {
"name": {
"type": "text",
"analyzer": "ik_max_word" } } } }
映射深入
1.1 地理坐标点数据类型
1.1.1 地理坐标点
地理坐标点是指地球表面可以用经纬度描述的一个点。 地理坐标点可以用来计算两个坐标间的距离,还可以判断一个坐标是否在一个区域中。地理坐标点需要显式声明对应字段类型为 geo_point :
1.1.2 经纬度坐标格式
如上例, location 字段被声明为 geo_point 后,我们就可以索引包含了经纬度信息的文档了。 经纬度信息的形式可以是字符串、数组或者对象
# 增加地址坐标点
GET /company-locations/_mapping //查看映射关系
增加经纬度
# 字符串形式
PUT /company-locations/_doc/1
{ "name":"NetEase",
"location":"40.715,74.011" }
# 对象形式
PUT /company-locations/_doc/2
{ "name":"Sina",
"location":{
"lat":40.722,
"lon":73.989 }}
# 数组形式
PUT /company-locations/_doc/3
{ "name":"Baidu",
"location":[73.983,40.719] }
注意
字符串形式以半角逗号分割,如 "lat,lon"
对象形式显式命名为 lat 和 lon
数组形式表示为 [lon,lat]
通过地理坐标点过滤 有四种地理坐标点相关的过滤器 可以用来选中或者排除文档
过滤器 |
作用 |
geo_bounding_box |
找出落在指定矩形框中的点 |
geo_distance |
找出与指定位置在给定距离内的点 |
geo_distance_range |
找出与指定点距离在给定最小距离和最大距离之间的点 |
geo_polygon |
找出落在多边形中的点。 这个过滤器使用代价很大 。当你觉得自己需要使用它,最好先看看 geo-shapes |
1.1.3 geo_bounding_box查询
这是目前为止最有效的地理坐标过滤器了,因为它计算起来非常简单。 你指定一个矩形的顶部 ,底部 , 左边界和右边界,然后过滤器只需判断坐标的经度是否在左右边界之间,纬度是否在上下边界之间
location这些坐标也可以用 bottom_left 和 top_right 来表示
1.1.4 geo_distance
过滤仅包含与地理位置相距特定距离内的匹配的文档。假设以下映射和索引文档然后可以使用 geo_distance 过滤器执行以下查询
GET /company-locations/_search
{ "query": {
"bool": {
"must": {
"match_all": {} },
"filter": {
"geo_distance": {
"distance": "200km",
"location": {
"lat": 40,
"lon": 70
} } } } } }
1.2 动态映射
Elasticsearch在遇到文档中以前未遇到的字段,可以使用dynamic mapping(动态映射机制)来确定字段的数据类型并自动把新的字段添加到类型映射。
Elastic的动态映射机制可以进行开关控制,通过设置mappings的dynamic属性,dynamic有如下设置项
true:遇到陌生字段就执行dynamic mapping处理机制
false:遇到陌生字段就忽略
strict:遇到陌生字段就报错
PUT /user
{ "settings": {
"number_of_shards": 3, "number_of_replicas": 0 },
"mappings": { "dynamic": "strict", "properties": {
"name": { "type": "text" },
"address": { "type": "object", "dynamic": true } } } }
# 插入以下文档,将会报错
# user索引层设置dynamic是strict,在user层内设置age将报错
# 在address层设置dynamic是ture,将动态映射生成字段
PUT /user/_doc/1
{ "name": "lisi", "age": "20", "address": {
"province": "beijing",
"city": "beijing" } }
PUT /user
{ "settings": {
"number_of_shards": 3, "number_of_replicas": 0 },
"mappings": { "dynamic": true,
"properties": {
"name": {
"type": "text" },
"address": {
"type": "object",
"dynamic": true } } } }
1.3 自定义动态映射
如果你想在运动时增加新的字段,你可能会启用动态映射,然而有时候动态映射规则可能不太智能,幸运的是,我们可以通过设置去自定义这些规则,以便更好的适用于你的数据
当 Elasticsearch 遇到一个新的字符串字段时,它会检测这个字段是否包含一个可识别的日期,比如 2014-01-01 如果它像日期,这个字段就会被作为 date 类型添加。否则,它会被作为 string 类型添加。 有些时候这个行为可能导致一些问题。想象下,你有如下这样的一个文档:
{ "note": "2014-01-01" }
假设这是第一次识别 note 字段,它会被添加为 date 字段。但是如果下一个文档像这样:
{ "note": "Logged out" }
这显然不是一个日期,但为时已晚。这个字段已经是一个日期类型,这个 不合法的日期 将会造成一个 异常。
日期检测可以通过在根对象上设置 date_detection 为 false 来关闭
PUT /my_index/_doc/1
{ "note": "2014-01-01" }
PUT /my_index/_doc/1
{ "note": "Logged out" }
PUT /my_index
{ "mappings": {
"date_detection": false } }
使用这个映射,字符串将始终作为 string 类型。如果需要一个 date 字段,必须手动添加。
Elasticsearch 判断字符串为日期的规则可以通过 dynamic_date_formats setting 来设置。
1.3.1 dynamic_templates(控制新生成字段的映射)
使用 dynamic_templates 可以完全控制新生成字段的映射,甚至可以通过字段名称或数据类型来应用不同的映射。每个模板都有一个名称,你可以用来描述这个模板的用途,一个 mapping 来指定映射应该怎样使用,以及至少一个参数 (如 match) 来定义这个模板适用于哪个字段。
模板按照顺序来检测;第一个匹配的模板会被启用。例如,我们给 string 类型字段定义两个模板:
es :以 _es 结尾的字段名需要使用 spanish 分词器。
en :所有其他字段使用 english 分词器。
我们将 es 模板放在第一位,因为它比匹配所有字符串字段的 en 模板更特殊:
PUT / my_index2
{ "mappings": {
"dynamic_templates": [{
"es": {
"match": "*_es",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"analyzer": "spanish"
} } }, {
"en": {
"match": "*",
"match_mapping_type": "string",
"mapping": {
"type": "text",
"analyzer": "english"
} } } ] } }
PUT /my_index2/_doc/1
{ "name_es":"testes",
"name":"es" }
1)匹配字段名以 _es 结尾的字段
2)匹配其他所有字符串类型字段
match_mapping_type:允许你应用模板到特定类型的字段上,就像有标准动态映射规则检测的一样(例如string或 long)
match参数只匹配字段名称,path_match 参数匹配字段在对象上的完整路径,所以 address.*.name将匹配这样的字段