一、动态映射

刚开始学ES时感觉它与MySQL相比,有个明显不同:ES不需要先定义表结构就可以插入数据了。
我们不用先创建index和mapping,直接put数据后,ES会自动帮我们创建index和mapping。
这个功能虽然看着比较方便,但是有时也会给我们带来困扰,因为ES自动创建的mapping中的字段类型不一定是我们期望的。所以掌握好ES的Mapping的知识是在工作中使用ES的基础。

ES的mappings设置选项中,有个dynamic,它是控制是否接收以及如何处理新的字段,它有四个值可选:

PUT pigg_map_test
{
  "mappings": {
    "dynamic": runtime
  }
}

dynamic值

说明

true

添加新字段到mapping中,这个是默认值

runtime

新字段将作为runtime fields添加到mapping,这些字段不会被索引,查询时会从_source中加载出来

false

新添加的字段会被忽略,这些新字段不会被索引,所以也不支持检索

strict

严格模式,当有新字段时,会报错

这个dynamic参数一般也就采用默认值true。它有2个优点:

  • 容错率高,即使没有为新字段设置mapping,也会存储,哪怕类型不对,后期可以同步到类型对的字段上,这样保证了客户的数据没有丢失。在企业开发中,丢了重要的数据可能就得提桶跑路了。
  • 别的同事来处理这个功能也比较熟悉,如果你设置成别的选项,别人再接手时可能感觉掉进一个坑里,因为他可能对这些配置并不是那么熟悉。

注意:下面讲的动态字段映射,还是以dynamictrue的基础上继续讨论。

二、动态字段映射

当ES接收到新的字段,它会自动为新字段创建类型,我们要熟悉ES自动创建类型的规律。
下面给出插入文档中JSON数据类型到ES数据类型的一个映射表。

JSON数据类型

ES数据类型

null

不添加字段

true / false

boolean

double

float

long

long

object

object

array

根据数组中第一个非null值的类型

通过日期检测的string

date

通过数字检测的string

float 或 long

没有通过上面2个检测的string

.keyword子字段的text类型

下面我们来对上表格中每一项都依次验证下。

1 null

插入一个文档,name的值为null,然后再验证mapping

PUT pigg_map_test/_doc/1
{
  "name": null
}

GET pigg_map_test/_mapping返回如下,看出null值是不会添加字段的

{
  "pigg_map_test" : {
    "mappings" : { }
  }
}

2 true / false

插入一个文档,state的值为true,然后再验证mapping

PUT pigg_map_test/_doc/1
{
  "state": true
}

GET pigg_map_test/_mapping返回如下,看出布尔值会设置为boolean类型

{
  "pigg_map_test" : {
    "mappings" : {
      "properties" : {
        "state" : {
          "type" : "boolean"
        }
      }
    }
  }
}

3 double & long 数字

PUT pigg_map_test/_doc/1
{
  "price": 1.0000,
  "count": 10000
}

GET pigg_map_test/_mapping返回如下:

{
  "pigg_map_test" : {
    "mappings" : {
      "properties" : {
        "count" : {
          "type" : "long"
        },
        "price" : {
          "type" : "float"
        }
      }
    }
  }
}

4 object

给文档添加1个objcet

PUT pigg_map_test/_doc/1
{
  "user": {
    "name": "江苏最菜亚瑟",
    "salary": 33000.00
  }
}

mapping如下,dynamictrue有这样的好处,如果设置dynamicruntime,则不会为object添加字段

{
  "pigg_map_test" : {
    "mappings" : {
      "properties" : {
        "user" : {
          "properties" : {
            "name" : {
              "type" : "text",
              "fields" : {
                "keyword" : {
                  "type" : "keyword",
                  "ignore_above" : 256
                }
              }
            },
            "salary" : {
              "type" : "float"
            }
          }
        }
      }
    }
  }
}

5 array

插入一个数组,mapping的字段类型以第一个非null值的类型

PUT pigg_map_test/_doc/1
{
  "hero": [ null, 1, 2]
}

mapping如下:

{
  "pigg_map_test" : {
    "mappings" : {
      "properties" : {
        "hero" : {
          "type" : "long"
        }
      }
    }
  }
}

数组中数据类型得一致,下面数组同时包含1和2.2,这样文档会保存失败的

PUT pigg_map_test/_doc/1
{
  "hero": [ null, 1, 2.2]
}

6 时间格式的string

关于ES的日期格式,可以参考我之前的博客详解mapping之date date_nanos 注意第三个日期类型是yyyy-MM-ddTHH:mm:ss

PUT pigg_map_test/_doc/1
{
  "date1": "2022-08-25",
  "date2": "2022/08/25",
  "date3": "2022-08-25T13:25:01"
}

mapping如下,上面3个确实都转成date类型了

{
  "pigg_map_test" : {
    "mappings" : {
      "properties" : {
        "date1" : {
          "type" : "date"
        },
        "date2" : {
          "type" : "date",
          "format" : "yyyy/MM/dd HH:mm:ss||yyyy/MM/dd||epoch_millis"
        },
        "date3" : {
          "type" : "date"
        }
      }
    }
  }
}

6.1 定制日期格式

我们还可以定制自己想要的日期格式,在mappings中设置dynamic_date_formats,ES会把符合格式的字符串设置为date类型。

PUT pigg_map_test
{
  "mappings": {
    "dynamic_date_formats": ["yyyy-MM-dd", "yyyy/MM/dd", "yyyy-MM-dd HH:mm:ss"]
  }
}

创建文档中3个字段分别对应上面设置的3个日期格式

PUT pigg_map_test/_doc/1
{
  "date1": "2022-08-25",
  "date2": "2022/08/25",
  "date3": "2022-08-25 13:25:01"
}

mapping如下:

{
  "pigg_map_test" : {
    "mappings" : {
      "dynamic_date_formats" : [
        "yyyy-MM-dd",
        "yyyy/MM/dd",
        "yyyy-MM-dd HH:mm:ss"
      ],
      "properties" : {
        "date1" : {
          "type" : "date",
          "format" : "yyyy-MM-dd"
        },
        "date2" : {
          "type" : "date",
          "format" : "yyyy/MM/dd"
        },
        "date3" : {
          "type" : "date",
          "format" : "yyyy-MM-dd HH:mm:ss"
        }
      }
    }
  }
}

7 数字格式的string

ES默认会把数字格式的string也设置为text类型,比如下面例子

PUT pigg_map_test/_doc/1
{
  "age": "30",
  "salary": "35000.00"
}

mapping中age和salary都会是text类型,如果要数字格式的字符串也按照数字格式保存,需要设置如下

PUT pigg_map_test
{
  "mappings": {
    "numeric_detection": true
  }
}

再插入上面文档,会发现字段类型会是数字类型:

{
  "pigg_map_test" : {
    "mappings" : {
      "numeric_detection" : true,
      "properties" : {
        "age" : {
          "type" : "long"
        },
        "salary" : {
          "type" : "float"
        }
      }
    }
  }
}

三、结语

在实际企业开发中,都会提前设置好mapping的,不会完全让ES自动设置字段类型的。但是掌握好动态字段映射还是很重要的,是学习mapping的前提条件。

  • 在字段类型比较确定时,可以先设置好mapping,再插入数据,有新字段时,先给mapping添加新的字段设置
  • 在字段的个数和类型都不确定时,可以使用mapping的动态模板,按照已经指定的规则设置它的类型。比如某个字段名为int_age,就让类型为integer,字段名为float_price就设为float

好好学习,天天向上,下一篇博客会写mapping的动态模板的内容。