我们今天要讨论的话题会让很多新手感到困惑,因为这个问题本身就比较难懂。但是如果你对ES比较熟悉的话,今天的内容也可以检验一下你对ES数据类型的了解是否扎实。1.默认的Numeric类型首先,我们创建一个索引:PUTorders/_doc/1{"order_id":1}如上例,使用DynamicMapping,系统会自动为orders索引创建一个Mapping,所以通过默认情况下,order_id字段将被推断为什么类型?以下是orders索引的Mapping:#GetMappingGETorders/_mapping#Results:{"orders":{"mappings":{"properties":{"order_id":{"type":"long"}}}}}如上例所示,很明显DynamicMapping推断出的order_id是long类型。那么如果我们向这个order_id字段写入一些非整数会发生什么?在Kibana中执行以下命令插入文档:PUTorders/_doc/2{"order_id":2}PUTorders/_doc/3{"order_id":"3"}PUTorders/_doc/4{"order_id":4.5}PUTorders/_doc/5{"order_id":"5.5"}PUTorders/_doc/6{"order_id":"6"}文档2和文档1类似,肯定可以插入。但是,当我们试图将字符串、浮点数,甚至是字符串形式的浮点值存储到long类型字段中时,会发生什么呢?可以肯定的是,除了文件6,其他都可以成功存储,但是为什么呢?2.Coerce处理数据默认情况下,ES会使用coerce来处理不符合规则的数据。Coercion会尝试转换与字段类型不匹配的数据,例如:字符串将被转换为数字。Float将被截断并转换为整数。ok,强制一下,我们通过搜索接口得到的order_id会不会是1,2,3,4,5呢?其实不是:#获取数据GET订单/_search{"query":{"match_all":{}}}#Result{"_shards":{.....},"hits":{..."hits":[{“_id”:“1”,“_source”:{“order_id”:1}},{“_id”:“2”,“_source”:{“order_id”:2}},{“_id”:“3","_source":{"order_id":"3"}},{"_id":"4","_source":{"order_id":4.5}},{"_id":"5","_source":{"order_id":"5.5"}}]}}看到上面的结果,是不是一头雾水?你不是说你可以转换数据吗?这时候再看Mapping,会发现order_id确实是long类型。3.不会改变的_source上面的问题其实很好回答,因为ES不会改变_source的内容。简单的说,_source的数据其实是存放在一个地方,而order_id字段的索引数据存放在另外一个地方,他们并没有混合(共享)。简单的说,写数据的时候,会把_source中的order_id取出来,强制处理,然后对处理后的结果进行索引。可以通过对order_id字段做聚合操作来验证这个思路:#aggregationoperationGETorders/_search{"size":0,"aggs":{"the_sum":{"sum":{"field":"order_id"}}}}#Result{......"aggregations":{"the_sum":{"value":15.0}}}聚合order_id,最终得到正确的结果,可以证明数据类型长。4.总结最后要注意的是,以后可能会删掉coerce!!!关于这部分的信息,可以参考这个issue。怎么说呢,默认更改用户输入的数据其实也不是一个很好的选择,让它崩溃不是很好吗?另外,从这个例子中,我们可以加深对Mapping和Indexing的理解。Mapping其实就是描述了索引的设置和各个字段的属性,但是并没有过多限制用户输入的_source是否严格匹配字段类型(默认)。最后,如果你对ES感兴趣,欢迎订阅我的《Elasticsearch 从入门到实践》小册子。
