Elasticsearch:mapping定制

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是在第一次数据输入时,根据我们输入的数据猜出来的:

GET myindex/_mapping

上面的命令显示的结果是:

{
  "myindex" : {
    "mappings" : {
      "properties" : {
        "status_code" : {
          "type" : "long"
        }
      }
    }
  }
}

从上面的结果中,我们可以看出来type为long,意味着这将是一个64bit的数据长度。我们知道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_factore来配置它的精度:

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
  }
}

从上面我们可以看出来,尽管我们修改了我们的数据类型,但是我们返回的数据还是对的。

发布了512 篇原创文章 · 获赞 124 · 访问量 90万+

猜你喜欢

转载自blog.csdn.net/UbuntuTouch/article/details/104816322