作者:刘晓国
Elasticsearch 依据我们提供的数据,根据自己的估计,并自动生成相应的 mapping。这在很多的时候是非常有用的。 它可以帮我们自动省很多的手动操作,而且在大多数的情况下,Elasticsearch 帮我们自动生成的 mapping 也是有效的。一般来讲,如果我们想自己定义自己的 mapping 的话,如下的步骤将是可取的,也是推荐的方法:
1.把自己的一个数据输入到 Elasticsearch 中
2.得到上面输入数据的 mapping,并在此基础上进行调整,从而得出适合自己数据的 mapping
在下面我们以几个例子来展示几个我们需要调整的地方。
调整数据类型
我们首先在我们的 Kibana 中输入如下的一个命令:
PUT myindex/_doc/1 { "status_code": 404 }
上面创建一个叫做 myindex 的索引,它里面含有一个我们通常见到的 HTTP 请求的 status_code。在这里我们的文档的值为 404。我们通过如下的命令来显示这个 myindex 的mapping。请记住这个 mapping 是在第一次数据输入时,根据我们输入的数据猜出来的:
{ "myindex" : { "mappings" : { "properties" : { "status_code" : { "type" : "long" } } } } }
从上面的结果中,我们可以看出来 type 为 long,意味着这将是一个 64 bit 的数据长度。我们知道 HTTP 的 status_code,通常就是小于 1000 的数据。这样一个 64 bit 的数据显然浪费存储空间。如果我们的数据是很少,这个可能并不算是什么,但是如果我们有海量的数据,那么这个存储空间的浪费将是很大的。为此,我们可以把这个数据类型修改为 short类型的, 也就是 16 bit:
PUT myindex1 { "mappings": { "properties": { "status_code": { "type": "short" } } } }
在上面,我们创建的 myindex1 的 mapping 里定义 status_code 为 short 类型。
如果你之前看过我的另外一篇文章 “开始使用Elasticsearch (2)”,我们在那里也调整一个 geo_point 的数据类型。比如:
PUT twitter/_doc/1 { "user": "zhangsan", "location": { "lat": "39.970718", "lon": "116.325747" } }
我们看看 Elasticsearch 帮我们生产的数据类型:
GET twitter/_mapping
{ "twitter" : { "mappings" : { "properties" : { "location" : { "properties" : { "lat" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } }, "lon" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } }, "user" : { "type" : "text", "fields" : { "keyword" : { "type" : "keyword", "ignore_above" : 256 } } } } } } }
显然,在上面我们可以看到 lat 及 lon 都被估算为 text 类型,而且是一个 multi-field 的数据类型,这显然不是我们所需要的。另外,我们的 user 类型,我们并不想它是一个 text 类型的。那么我们可以作如下的调整:
PUT twitter1 { "mappings": { "properties": { "location": { "type": "geo_point" }, "user": { "type": "keyword" } } } }
在上面的 twitter1 中,我们可以看出来调整后的 location 类型为 geo_point 的数据类型,而 user 也变成了我们所希望的 keyword 类型。
动态的 mapping 并不总是优化的
针对一个浮点数来说:
PUT my_index/_doc/1 { "price": 1.99 }
我们可以得到它的 mapping:
GET my_index/_mapping
{ "my_index" : { "mappings" : { "properties" : { "price" : { "type" : "float" } } } } }
从上面我们可以看出来,price 的数据类型是一个 float 类型。对于大多数的情况来说,这个应该没有问题。但是在实际的应用中,我们可以把这个 float 数据类型转换为 scaled float 数据类型。Scaled float 由 long 数据类型来支持。long 数据类型在 Lucene 里可以被更加有效地压缩,从而节省存储的空间。在使用 scaled float 数据类型时,你必须使用scaling_factor 来配置它的精度:
PUT my_index1/_doc/1 { "mappings": { "properties": { "price": { "type": "scaled_float", "scaling_factor": 100 } } } }
在上面我们定义 price 类型为 scaled_float 数据类型,并定义 scaling_factor 为 100。这样我们的数据,比如 1.99 刚好可以在乘以 100 变为 199,从而成为一个整型数。
经过这样的改造后,我们可以试试重新在 my_index1 里输入一个文档:
PUT my_index1/_doc/1 { "price": 1.99 }
我们通过如下的方法来查询这个数据:
GET my_index1/_doc/1
返回的结果是:
{ "_index" : "my_index1", "_type" : "_doc", "_id" : "1", "_version" : 2, "_seq_no" : 1, "_primary_term" : 1, "found" : true, "_source" : { "price" : 1.99 } }
从上面我们可以看出来,尽管我们修改了我们的数据类型,但是我们返回的数据还是对的。