一文搞懂ElasticSearch之Ma

这篇文章主要介绍Mapping、DynamicMapping以及ElasticSearch是如何自动判断字段的类型,同时介绍Mapping的相关参数设置。首先来看下什么是Mapping什么是Mapping?在一篇文章带你搞定ElasticSearch术语中,我们讲到了Mapping类似于数据库中的表结构定义schema,它有以下几个作用:定义索引中的字段的名称定义字段的数据类型,比如字符串、数字、布尔字段,倒排索引的相关配置,比如设置某个字段为不被索引、记录position等在ES早期版本,一个索引下是可以有多个Type,从7.0开始,一个索引只有一个Type,也可以说一个Type有一个Mapping定义。在了解了什么是Mapping之后,接下来对Mapping的设置做下介绍:Mapping设置在创建一个索引的时候,可以对dynamic进行设置,可以设成false、true或者strict。比如一个新的文档,这个文档包含一个字段,当Dynamic设置为true时,这个文档可以被索引进ES,这个字段也可以被索引,也就是这个字段可以被搜索,Mapping也同时被更新;当dynamic被设置为false时候,存在新增字段的数据写入,该数据可以被索引,但是新增字段被丢弃;当设置成strict模式时候,数据写入直接出错。另外还有index参数,用来控制当前字段是否被索引,默认为true,如果设为false,则该字段不可被搜索。参数index_options用于控制倒排索引记录的内容,有如下4种配置:doc:只记录docidfreqs:记录docid和termfrequenciespositions:记录docid、termfrequencies和termpositionoffsets:记录docid、termfrequencies、termposition和characteroffects另外,text类型默认配置为positions,其他类型默认为doc,记录内容越多,占用存储空间越大。null_value主要是当字段遇到null值时的处理策略,默认为NULL,即空值,此时ES会默认忽略该值,可以通过设定该值设定字段的默认值,另外只有KeyWord类型支持设定null_value。copy_to作用是将该字段的值复制到目标字段,实现类似_all的作用,它不会出现在_source中,只用来搜索。除了上述介绍的参数,还有许多参数,大家感兴趣的可以在官方文档中进行查看。在学习了Mapping的设置之后,让我们来看下字段的数据类型有哪些吧!字段数据类型ES字段类型类似于MySQL中的字段类型,ES字段类型主要有:核心类型、复杂类型、地理类型以及特殊类型,具体的数据类型如下图所示:核心类型从图中可以看出核心类型可以划分为字符串类型、数字类型、日期类型、布尔类型、基于BASE64的二进制类型、范围类型。字符串类型其中,在ES7.x有两种字符串类型:text和keyword,在ES5.x之后string类型已经不再支持了。text类型适用于需要被全文检索的字段,例如新闻正文、邮件内容等比较长的文字,text类型会被Lucene分词器(Analyzer)处理为一个个词项,并使用Lucene倒排索引存储,text字段不能被用于排序,如果需要使用该类型的字段只需要在定义映射时指定JSON中对应字段的type为text。keyword适合简短、结构化字符串,例如主机名、姓名、商品名称等,可以用于过滤、排序、聚合检索,也可以用于精确查询。数字类型数字类型分为long、integer、short、byte、double、float、half_float、scaled_float。数字类型的字段在满足需求的前提下应当尽量选择范围较小的数据类型,字段长度越短,搜索效率越高,对于浮点数,可以优先考虑使用scaled_float类型,该类型可以通过缩放因子来精确浮点数,例如12.34可以转换为来存储。日期类型在ES中日期可以为以下形式:格式化的日期字符串,例如-03-:00、/03/17时间戳(和-01-:00:00UTC的差值),单位毫秒或者秒即使是格式化的日期字符串,ES底层依然采用的是时间戳的形式存储。布尔类型JSON文档中同样存在布尔类型,不过JSON字符串类型也可以被ES转换为布尔类型存储,前提是字符串的取值为true或者false,布尔类型常用于检索中的过滤条件。二进制类型二进制类型binary接受BASE64编码的字符串,默认store属性为false,并且不可以被搜索。范围类型范围类型可以用来表达一个数据的区间,可以分为5种:integer_range、float_range、long_range、double_range以及date_range。复杂类型复合类型主要有对象类型(object)和嵌套类型(nested):对象类型JSON字符串允许嵌套对象,一个文档可以嵌套多个、多层对象。可以通过对象类型来存储二级文档,不过由于Lucene并没有内部对象的概念,ES会将原JSON文档扁平化,例如文档:实际上ES会将其转换为以下格式,并通过Lucene存储,即使name是object类型:嵌套类型嵌套类型可以看成是一个特殊的对象类型,可以让对象数组独立检索,例如文档:username字段是一个JSON数组,并且每个数组对象都是一个JSON对象。如果将username设置为对象类型,那么ES会将其转换为:可以看出转换后的JSON文档中first和last的关联丢失了,如果尝试搜索first为wu,last为xy的文档,那么成功会检索出上述文档,但是wu和xy在原JSON文档中并不属于同一个JSON对象,应当是不匹配的,即检索不出任何结果。嵌套类型就是为了解决这种问题的,嵌套类型将数组中的每个JSON对象作为独立的隐藏文档来存储,每个嵌套的对象都能够独立地被搜索,所以上述案例中虽然表面上只有1个文档,但实际上是存储了4个文档。地理类型地理类型字段分为两种:经纬度类型和地理区域类型:经纬度类型经纬度类型字段(geo_point)可以存储经纬度相关信息,通过地理类型的字段,可以用来实现诸如查找在指定地理区域内相关的文档、根据距离排序、根据地理位置修改评分规则等需求。地理区域类型经纬度类型可以表达一个点,而geo_shape类型可以表达一块地理区域,区域的形状可以是任意多边形,也可以是点、线、面、多点、多线、多面等几何类型。特殊类型特殊类型包括IP类型、过滤器类型、Join类型、别名类型等,在这里简单介绍下IP类型和Join类型,其他特殊类型可以查看官方文档。IP类型IP类型的字段可以用来存储IPv4或者IPv6地址,如果需要存储IP类型的字段,需要手动定义映射:Join类型Join类型是ES6.x引入的类型,以取代淘汰的_parent元字段,用来实现文档的一对一、一对多的关系,主要用来做父子查询。Join类型的Mapping如下:其中,my_join_field为Join类型字段的名称;relations指定关系:question是answer的父类。例如定义一个ID为1的父文档:接下来定义一个子文档,该文档指定了父文档ID为1:再了解完字段数据类型后,再让我们看下什么是DynamicMapping?什么是DynamicMapping?DynamicMapping机制使我们不需要手动定义Mapping,ES会自动根据文档信息来判断字段合适的类型,但是有时候也会推算的不对,比如地理位置信息有可能会判断为Text,当类型如果设置不对时,会导致一些功能无法正常工作,比如Range查询。类型自动识别ES类型的自动识别是基于JSON的格式,如果输入的是JSON是字符串且格式为日期格式,ES会自动设置成Date类型;当输入的字符串是数字的时候,ES默认会当成字符串来处理,可以通过设置来转换成合适的类型;如果输入的是Text字段的时候,ES会自动增加keyword子字段,还有一些自动识别如下图所示:下面我们通过一个例子是看看是怎么类型自动识别的,输入如下请求,创建索引:然后使用GET/mapping_test/_mapping查看,结果如下图所示:可以从结果中看出,ES会根据文档信息自动推算出合适的类型。哦豁,万一我想修改Mapping的字段类型,能否更改呢?让我们分以下两种情况来探究下:修改Mapping字段类型?如果是新增加的字段,根据Dynamic的设置分为以下三种状况:当Dynamic设置为true时,一旦有新增字段的文档写入,Mapping也同时被更新。当Dynamic设置为false时,索引的Mapping是不会被更新的,新增字段的数据无法被索引,也就是无法被搜索,但是信息会出现在_source中。当Dynamic设置为strict时,文档写入会失败。另外一种是字段已经存在,这种情况下,ES是不允许修改字段的类型的,因为ES是根据Lucene实现的倒排索引,一旦生成后就不允许修改,如果希望改变字段类型,必须使用ReindexAPI重建索引。不能修改的原因是如果修改了字段的数据类型,会导致已被索引的无法被搜索,但是如果是增加新的字段,就不会有这样的影响。总结本文主要介绍了Mapping和DynamicMapping,同时对字段类型做了详细介绍,也介绍了在ES中是如何对字段类型做推算的,了解了Mapping的相关参数设置。


转载请注明:http://www.aierlanlan.com/cyrz/8385.html