首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

Elasticsearch学习笔记——自动映射

Elasticsearch学习笔记——自动映射

映射

es中的mapping,中文翻译为映射。或者是认为映射这个词不够贴合mapping本身的真实意图,所以,骄傲的程序员一般直接称之为mapping。(谁还不会个英文杂的?)

但是,当mapping前面加上某些前缀时,可能就会说中文多一些,比如说动态映射。(最讨厌那种中英文夹杂的了。自动mapping多难听?你说对吗?mapping?)

es通常用来作搜索,但其本质也是一个数据存储容器。那么,我们不妨把es和常用的关系型数据库,如MySQL作一个比较。

用两句话来整理一下,帮助记忆:

一个MySQL服务器里通常包含几个库,每个库里有几张表,每个表的结构不同。表里有若干行,每行有若干列。

一个ES服务器里通常包含几个索引,每个索引中都有几个类型,每个类型的映射不同。类型有若干文档,每个文档有若干字段。

映射在ES中的作用,就等同于MySQL的表结构定义,它规定了ES某个索引的某个Type的字段处理规则:如索引如何建立,索引类型,是否保存原始索引JSON文档,是否压缩原始JSON文档,是否需要分词处理及如何进行分词处理等。

动态映射

es通过RestFul风格的封装,屏蔽了不同语言的复杂性。任何语言,都通过RestFul接口来对es进行相关的操作。比如,我们在Spring Boot中使用es时,通常会使用spring-boot-starter-data-elasticsearch。(网上有部分论点称该包仅支持es 2.X。经试验,在6.X下也可以正常使用)我们会使用@Document注解建立一个和ES中type相应对的实现,会建立一个Repository来继承ElasticsearchRepository。看过源码就会发现,ElasticsearchRepository中其实就是RestFul接口的访问进行了二次封装。就好像我们在使用MyBatis时,定义的Mapper实现也是对访问数据库的封装。

在使用时,我们一般会先创建索引,再在索引下创建Type,定义mapping。有时候,我们发现,即使不创建索引,不创建Type,不定义mapping,也可以直接向es中增加文档。这是因为es帮我们做了动态映射。

动态映射:索引文档前不需要创建索引、类型等信息,在索引的同时会自动完成索引、类型、映射的创建。

自动检测

映射的重要重要之一就是定义字段及字段的类型,那么,动态映射是如何确定某个字段的类型的?这就是自动检测。

自动检测会根据你提供的JSON格式的文档来猜测其中的字段及字段类型。

当某个字段每一次出现时,es会根据下表来做猜测:

|JSON数据|ES中的数据类型|

|null|不会添加字段|

|true 或 false |boolean|

|含小数点的数字|double|

|整数|long|

|对象|object|

|数组|根据数组中首个非null元素来确定|

|字符串|日期、数字或者text + keyword|

从上表中,我们可以看到,es在做自动映射时,采用的是一种比较“贪婪”的做法。比如说,对于数字,如果是小数,就定义为double,如果是整数,就定义为long,事实上,我们在做时,不一定会选择double或long,我们可能会根据字段的基本范围,来使用float、int等,这样可以在满足业务需求的同时,尽量减小索引的大小。但是,es显然无法根据你在JSON的描述来猜测出数据的范围,所以,es选择了它能提供的能容纳最大范围的类型,以减少溢出的可能。

再比如说字符串,es会先尝试解析成日期,如果不成,再尝试解析成数字(自动数字检测需要手动开启),如果还是不行,就解析成text + keyword。之所以解析成text和keyword,是因为不确定你是否需要分词,是否需要聚合,那就索性都给了。

是否需要动态映射

了解了动态映射中核心的自动检测,我们发现,动态映射事实上可能只适用于初学者的快速入手,并不是很适合放在真正的产品中,即使可以去动态映射的规则做一些定制(事实上es确实支持)。因为动态映射可能会遇到以下一些问题:

空间的浪费。无论是对数字对double或long,还是对字符串同时进行text和keyword索引,都是一种空间的浪费。

错误的类型。事实上,一个字符串长得像日期或数字,它就一定是日期或数字吗?比如说文章的发表日期,可能是某个像是日期的表述,如2020/1/28,也有可能是三天前,两个小时前,或者是刚刚。这对于我们来说容易理解,但是对于es,可能就会有些迷茫。(你刚才给的明明是个日期,现在怎么说“刚刚”呢?小刚是谁?)

综上,es的动态映射可能并不太适合我们,映射还是有必要自己去琢磨定义一番的,尤其是对追求精致(代码和女朋友都要精致)的程序员们,不是吗?

在调用建立索引接口时,通过mappings的dynamic属性可以定义动态映射的行为。true(默认值)为动态添加新字段,false为忽略新字段,strict为碰到陌生字段即抛出异常。个人认为,strict更合适。就是要严格的知道程序中发生的每一件事情。如果设为false,可能有天会疑惑,为什么在doc中明明包含某个字段,索引中却没有呢?

  • 发表于:
  • 原文链接https://kuaibao.qq.com/s/20200324A0EMLF00?refer=cp_1026
  • 腾讯「腾讯云开发者社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 cloudcommunity@tencent.com 删除。

扫码

添加站长 进交流群

领取专属 10元无门槛券

私享最新 技术干货

扫码加入开发者社群
领券