Elasticsearch在很多情况下被当作一个文本型的NOSQL数据库,也有增删查改操作

数据写入

Elasticsearch的一大特点是,全是RESTful接口处理JSON请求

1
2
3
4
5
# curl -XPOST http://localhost:9200/logstash-2017.10.29/testlog -d '{
"date": "1509271325780"
"user": "jack"
"mesg": "first message into Elasticsearch"
}'

数据获取

在数据写入时,会返回该数据的_id,这是后续用来获取数据的关键:

1
2
3
4
5
6
7
# curl -XGET http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo
{"_index": "logstash-2017.10.29","_type": "testlog", "_id": "AV9nlDQhv96dGKcHC2zo", "_version": 1, "found": true, "_source": {
"date": "1509271325780",
"user": "jack",
"mesg": "first message into Elasticsearch"
}
}

也可以使用下面语法来获取源数据部分

1
curl -XGET http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo/_source

或者使用下面语法来指明获取字段

1
curl -XGET http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo?fields=user,mesg

数据删除

1
2
3
4
5
#删除单条数据
# curl -XDELETE http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo
#删除整个type或者整个索引
# curl -XGET http://localhost:9200/logstash-2017.10.2*

数据更新

分为两种情况:

  1. 全量提交
  2. 指明_id再发送一次写入请求
    1
    2
    3
    4
    5
    6
    #全部提交
    # curl -XPOST http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo -d '{
    "date": "1509271325780",
    "user": "jack",
    "mesg": "first message into Elasticsearch but version 2"
    }'
1
2
3
4
5
6
#局部提交
# curl -XPOST http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo -d '{
"doc": {
"user": "jack wang"
}
}'

或者

1
2
3
# curl -XPOST http://localhost:9200/logstash-2017.10.29/testlog/AV9nlDQhv96dGKcHC2zo/_update -d '{
"scripts": "ctx._source.user = \"someone\""
}'

全文搜索

1
2
3
# curl -XGET http://localhost:9200/logstash-2017.10.29/testlog/_search?pretty=true?q='first'
# curl -XGET http://localhost:9200/logstash-2017.10.29/testlog/_search?pretty=true?q=user:"jack"
querystring 语法

上例中?q=后面的就是querystring语法,会在kibana中经常使用

  • 全文检索:直接写搜索的单词。如:?q=aaaa
  • 单字段的全文检索:在搜索单词之前加上字段名和冒号。如:?q=user:jack
  • 单字段的精确检索:在搜索单词前加上双引号。如:?q=user:"jack"
  • 多个检索条件的组合:可以使用NOTANDOR来组合检索,必须是大写的。如:?q=user:("jack" OR "bob") AND NOT mesg:aaaa
  • 字段是否存在_exists_:user表示要求user字段存在,_missing_:user表示user字段不存在。如:?q=_exists_:beat.name
  • 通配符:用?表示单字母,*表示任意个字母。如:?q=DevE?N?q=DevE?N*
  • 正则:比通配符更复杂一点点。如:?q=/dub{2}o/
    注:Elasticsearch正则性能不好,尽量不要使用太复杂或不使用。参考Elasticsearch正则表达式语法
  • 近似搜索:用~表示搜索单词可能有一字母写的不对。如:?q=dubao~
  • 范围搜索:对数值和时间。如:?q=@timestamp:>150928968615?q=@timestamp:["now-1m" TO "now"]
DSL语法

Elasticsearch也支持其他查询语法,具体见:Elasticsearch其他查询语法

  • term query
    1
    2
    3
    4
    5
    6
    7
    8
    # curl -XGET http://localhost:9200/_search -d '
    {
    "query": {
    "term": {
    "_id": "AV9orWWLv96dGKcHDVyi"
    }
    }
    }'
聚合请求

在检索范围确定后,Elasticsearch还执行对结果集做聚合查询,返回更直接的聚合统计结果。
aggression分为bucketmetric,分别用作词元划分和数值计算。而bucket aggression还支持在自身结果集的基础上叠加新的aggression。
实现一个时序的百分比统计

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# curl -XPOST 'http://localhost:9200/logstash-2017.10.29/_search?size=0&pretty' -d '{
"aggs": {
"percentile_over_time": {
"date_histogram": {
"field": "@timestamp",
"interval": "1m"
},
"aggs": {
"percentile_one_time": {
"percentiles": {
"field": "requesttime"
}
}
}
}
}
}'

pipeline聚合

Elasticsearch 2.x 新增pipeline aggression类型,再已有aggression返回的数组数据之后,再对这组数值做一次运算。在Kibana 5.0的timelion中有用到
常见的pipeline聚合场景,就是对时序数据求移动平均值
示例:
对响应时间设置如下:周期为7,移动窗口为30,alpa、beta、gamma参数均为0.5,holt-winters季节性预测2个未来值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
"aggs": {
"my_date_histo": {
"date_histogram": {
"field": "@timestamp",
"interval": "1h"
},
"aggs": {
"avgtime": {
"avg": { "field": "requesttime" }
},
"the_movavg": {
"moving_avg": {
"buckets_path": "avgtime",
"window": 30,
"model": "holt_winters",
"predict": 2,
"settings": {
"type": "mult",
"alpha": 0.5,
"beat": 0.5,
"gamma": 0.5,
"period": 7,
"pad": true
}
}
}
}
}
}
}

buckets_path语法

aggression是有堆叠层级关系的,所以pipeline aggression在引用 metric aggression时会涉及到层级的问题。在上例中,the_movavg和avgtime是同一级,所以buckets_path直接就写avgtime即可。但如果把the_movavg上提一层,跟my_date_histo同级

1
"buckets_path": "my_date_histo > avgtime"

如果用的是返回的数值有多个值的聚合,比如?percentiles或者?extended_stats

1
"buckets_path": "percentile_over_time > percentile_one_time.95"

目前Elasticsearch支持的聚合请求列表,参考:https://www.elastic.co/guide/en/elasticsearch/reference/5.6/search-aggregations.html
参考阅读:Holt Winters预测算法,见:https://en.wikipedia.org/wiki/Holt-Winters

搜索请求参数

搜索请求参数如下:

  • from: 从索引的第几条数据开始返回,默认是0
  • size: 返回多少条数据,默认是10
    Elasticsearch集群实际是需要给 coordinate node 返回 shards number x (from + size)条数据,然后在单机上进行排序,最后给客户端返回大小为 size的数据。所以请慎用 from和size参数
    此外,Elasticsearch 2.x 还增加了一个索引级别的动态控制配置项:index.max_result_window,默认为10000,即from + size大于10000,Elasticsearch会直接拒绝这次请求不进行具体搜索,以保护节点
    Elasticsearch 2.x 还优化了,当设置 “size”:0 时,自动改变 search_type为 count。跳过过程的 fetch 阶段
  • timeout:coordinate node 等待超时时间。当达到阀值后,coordinate node 会直接把当前收到的数据返回个客户端,不再等待 data node后续的返回结果了。
    注:这个参数只是为了配合客户端程序,并不能取消data node上搜索任务还在运行和占用资源
  • terminate_after:各data node上,扫描单个分片时找到多少记录后,就认为足够了。这个参数可以切实保护 data node 上搜索任务不会长期运行和占用资源。也就是意味着搜索范围没有覆盖全部索引,是一个抽样数据。准确率不好判断。
  • request_cache:各data node上,在分片级别对请求的响应(仅限于hits.total数值、 aggression 和 suggestion的结果集)做的缓存。注意,这个缓存的键值要求很严格,请求的JSON必须一字不易,缓存才能命中
    另外,request_cache 参数不能写在请求的JSON里,只能以URL参数的形式存在,示例如下:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # curl -XPOST http://localhost:9200/_search?request_cache=true -d '
    {
    "size": 0,
    "timeout": "120s",
    "terminate_after": 1000000,
    "query": { "match_all": {} },
    "aggs": {"terms": { "terms" : { "field" : "keyname" } } }
    }
    '

本文出自”Jack Wang Blog”:http://www.yfshare.vip/2017/10/30/Elasticsearch查询语法/