Elasticsearch 依据我们提供的数据,根据自己的估计,并自动生成相应的 mapping。这在很多的时候是非常有用的。 它可以帮我们自动省很多的手动操作,而且在大多数的情况下,Elasticsearch 帮我们自动生成的 mapping 也是有效的。一般来讲,如果我们想自己定义自己的 mapping 的话,如下的步骤将是可取的,也是推荐的方法:
- 把自己的一个数据输入到 Elasticsearch 中
- 得到上面输入数据的 mapping,并在此基础上进行调整,从而得出适合自己数据的 mapping
在下面我们以几个例子来展示几个我们需要调整的地方。
调整数据类型
我们首先在我们的 Kibana 中输入如下的一个命令:
PUT myindex/_doc/1
{
"status_code": 404
}
上面创建一个叫做 myindex 的索引,它里面含有一个我们通常见到的 HTTP 请求的 status_code。在这里我们的文档的值为 404。我们通过如下的命令来显示这个 myindex 的mapping。请记住这个 mapping 是在第一次数据输入时,根据我们输入的数据猜出来的:
GET myindex/_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
}
}
从上面我们可以看出来,尽管我们修改了我们的数据类型,但是我们返回的数据还是对的。