Elasticsearch最佳生产实践整理,推荐收藏

前言

Elasticsearch是一个底层基于Lucene的全文搜索和分析引擎,支持近乎实时地存储、搜索和分析大量数据的能力,最常用于网站搜索、日志搜索、数据分析等场景。

本文主要针对日常工作中Elasticsearch使用的一些基础概念、使用规范、注意事项、常见优化以及工具使用进行总结,如有不当的地方,欢迎指正。

一、Elasticsearch建索引规范

索引建立时需搞清楚每个字段存在的用途(这里用途不仅仅是业务上的定义,还需关心该字段是会做索引,还是会聚合计算,还是会有排序,或者仅仅只是文档),在建立mapping时应当根据字段的不同用途,不同数据类型来匹配合适的Elasticsearch中的数据类型。

搞清楚中Elasticsearch中的数据类型

1. string类型

KeywordText都属于string类的基本数据类型,但使用场景完全不同。

KeywordText差异对比

Keyword(不分词):如果文本上有精确搜索、排序、聚合查询的需求时,可以使用,大文本用不要用keyword类型。

Text(分词):按分词器进行分词,用于全文检索,不能排序,也禁止用来聚合。

以下测试案例,具体说明了两种类型分别在matchterm查询时反映出来的差异性。

# 建立名为emp的索引
PUT /emp/
{
   
  "mappings": {
   
    "_doc": {
   
      "properties": {
   
        "nickname": {
   
          "type": "text"
        },
        "name": {
   
          "type": "keyword"
        },
        "age": {
   
          "type": "integer"
        }
      }
    }
  }
}

# 插入测试数据
POST /emp/_doc/_bulk
{
   "index":{
   "_id":"1"}}
{
   "nickname":"zhang san","name":"zhang san","age":"28"}
{
   "index":{
   "_id":"2"}}
{
   "nickname":"zhang san feng","name":"zhang san feng","age":"88"}
{
   "index":{
   "_id":"3"}}
{
   "nickname":"zhang san bu feng","name":"zhang san bu feng","age":"8"}

# 3条全部能够查到
GET /emp/_search
{
   "query":{
   "match":{
   "nickname":"zhang san"}}}
# 3条全都查不到
GET /emp/_search
{
   "query":{
   "term":{
   "nickname":"zhang san"}}}

# 换成查name,match和term都只能查到id为1的这条数据
GET /emp/_search
{
   "query":{
   "match":{
   "name":"zhang san"}}}
GET /emp/_search
{
   "query":{
   "term":{
   "name":"zhang san"}}}

# match和term都是3条全部能够查到
GET /emp/_search
{
   "query":{
   "match":{
   "nickname":"zhang"}}}
GET /emp/_search
{
   "query":{
   "term":{
   "nickname":"zhang"}}}

# match和term都是一条也查不到
GET /emp/_search
{
   "query":{
   "match":{
   "name":"zhang"}}}
GET /emp/_search
{
   "query":{
   "term":{
   "name":"zhang"}}}

# 可以排序
GET /emp/_search
{
   "sort":[{
   "name":{
   "order":"desc"}}]}

# 报错
GET /emp/_search
{
   "sort":[{
   "nickname":{
   "order":"desc"}}]}

2. 数值类型

数组类型包括:long, integer, short, byte, double, float, half_float, scaled_float

请按实际需求选择,因为这不仅仅是能够节省空间,同时索引和搜索都将变的更有效率,不过Elasticsearch会根据存储的实际情况进行优化。

以下案例具体说明了,当实际存储类型与数据类型精度不一致时,所导致的“怪异”现象,主要原因就是因为Elasticsearch会根据存储的实际情况进行优化。

# 注意age字段指定的是integer类型
PUT /emp/
{
   
  "mappings": {
   
    "_doc": {
   
      "properties": {
   
        "nickname": {
   
          "type": "text"
        },
        "name": {
   
          "type": "keyword"
        },
        "age": {
   
          "type": "integer"
        }
      }
    }
  }
}

# 插入的测试数据,age字段实际上保存的都是字符串,但完全不影响插入
POST /emp/_doc/_bulk
{
   "index":{
   "_id":"1"}}
{
   "nickname":"zhang san","name":"zhang san","age":"28"}
{
   "index":{
   "_id":"2"}}
{
   "nickname":"zhang san feng","name":"zhang san feng","age":"88"}
{
   "index":{
   "_id":"3"}}
{
   "nickname":"zhang san bu feng","name":"zhang san bu feng","age":"8"}

# 同样,保存小数也没问题
POST /emp/_doc/_bulk
{
   "index":{
   "_id":"6"}}
{
   "nickname":"li gang","name":"li gang","age":16.9}

不过问题会出在查询时,直接查16.9是查不到的。

# 查不出结果
GET /emp/_search
{
   "query":{
   "match":{
   "age":16.9}}}

而查16却可以查到结果。

# 能查出结果
GET /emp/_search
{
   "query":{
   "match":{
   "age":16}}}

当然如果改为使用double类型存储小数后,则可正常查询,以下是测试案例:

# 新建一个double类型的字段
PUT /emp_double/
{
   "mappings":{
   "_doc":{
   "properties":{
   "salary":{
   "type":"double"}}}}}

# 构建数据
POST /emp_double/_doc/_bulk
{
   "index":{
   "_id":"1"}}
{
   "salary":1000.5}
{
   "index":{
   "_id":"2"}}
{
   "salary":2000.25}
{
   "index":{
   "_id":"3"}}
{
   "salary":3000}
{
   "index":{
   "_id":"4"}}
{
   "salary":4000.1234}

# 4条数据查1000.52000.2530004000.1234都没问题
GET /emp_double/_search
{
   "query":{
   "match":{
   "salary":4000.1234}}}

所以,实际生产环境不要存储比字段类型精度更高的数据。

当然数值类型也是支持聚合和排序的。同样,注意字段类型与实际存储类型产生的差异即可。

并没有按照实际存储的数值进行排序,因为实际精度并没有保留到小数。

这里还需要注意的是,在Elasticsearch中存储时并不是所有数值数据都一定要被映射为数值类型的,通常情况是当数值需要进行范围查询时,则建议使用数值类型,而术语级别的查询,则使用keyword更合适。

例如像ID、编号等这样的数据通常不会被用来做范围查询,而是经常用来做术语查询,因此应当建立为keyword类型,尽管它本身是一串数字。

3. 日期类型

Elasticsearch中日期类型既可以是格式化后的字符串,也可以是时间戳,Elasticsearch内部统一会将其转换为UTC,并按照long number类型进行存储。

多种时间格式的测试案例:

POST /my_date/_doc/_bulk
{
   "index":{
   "_id":"1"}}
{
   "date":"2015-01-01"}
{
   "index":{
   "_id":"2"}}
{
   "date":"2015-01-01T12:10:30Z"}
{
   "index":{
   "_id":"3"}}
{
   "date":1420070400001}

GET my_date/_search
{
   "sort":{
   "date":"desc"}}

也支持指定的日期格式:

PUT my_date
{
   
  "mappings": {
   
    "_doc": {
   
      "properties": {
   
        "date": {
   
          "type": "date",
          "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd"
        }
      }
    }
  }
}

# 此时插入第3条时间戳的格式将会报错
POST /my_date/_doc/_bulk
{
   "index":{
   "_id":"1"}}
{
   "date":"2015-01-01"}
{
   "index"
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码拉松

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值