ElasticSearch学习04

常用DSL

官方文档

DSL介绍

Domain Specific Language:领域特定语言

Elasticsearch基于JSON提供完整的查询DSL来定义查询。

一个查询可由两部分字句构成:

  • Leaf query clauses 叶子查询字句:Leaf query clauses 在指定的字段上查询指定的值,如:match、term or range queries. 叶子字句可以单独使用。
  • Compound query clauses 复合查询字句:以逻辑方式组合多个叶子、复合查询为一个查询。

一个查询字句的行为取决于它是用在query context 还是 filter context 中:

  • Query context 查询上下文:用在查询上下文中的字句回答“这个文档有多匹配这个查询?”。除了决定文档是否匹配,字句匹配的文档还会计算一个字句评分,来评定文档有多匹配,会参与相关性评分。查询上下文由 query 元素表示。
  • Filter context 过滤上下文:过滤上下文由 filter 元素或 bool 中的 must not 表示。用在过滤上下文中的字句回答“这个文档是否匹配这个查询?”,不参与相关性评分。被频繁使用的过滤器将被ES自动缓存,来提高查询性能。

Query DSL语法格式

1
2
3
4
5
6
{
QUERY_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
1
2
3
4
5
6
7
8
{
QUERY_NAME: {
FIELD_NAME: {
ARGUMENT: VALUE,
ARGUMENT: VALUE,...
}
}
}

简单查询

1
2
3
4
5
6
GET /_search
{
"query":{
"match_all": {}
}
}

/_search 查找整个ES中所有索引的内容

query 为查询关键字,类似的还有aggs为聚合关键字

match_all 匹配所有的文档,也可以写match_none不匹配任何文档

image-20220610151353333

took: 表示我们执行整个搜索请求消耗了多少毫秒

timed_out: 表示本次查询是否超时

这里需要注意当timed_out为True时也会返回结果,这个结果是在请求超时时ES已经获取到的数据,所以返回的这个数据可能不完整。

且当你收到timed_out为True之后,虽然这个连接已经关闭,但在后台这个查询并没有结束,而是会继续执行

_shards: 显示查询中参与的分片信息,成功多少分片失败多少分片等

hits: 匹配到的文档的信息,其中total表示匹配到的文档总数,max_score为文档中所有_score的最大值

hits中的hits数组为查询到的文档结果,默认包含查询结果的前十个文档,每个文档都包含文档的_index_type_id_score_source数据

结果文档默认情况下是按照相关度(_score)进行降序排列,也就是说最先返回的是相关度最高的文档,文档相关度意思是文档内容与查询条件的匹配程度,上边的查询与过滤中有介绍

指定索引

上边的查询会搜索ES中的所有索引,但我们通常情况下,只需要去固定一个或几个索引中搜索就可以了,搜索全部无疑会造成资源的浪费,在ES中可以通过以下几种方法来指定索引

  1. 指定一个固定的索引,xxxxx为索引名字
1
2
GET /xxxxx/_search

以上表示在xxxxx索引下查找数据

  1. 指定多个固定索引,多个索引名字用逗号分割
1
2
GET /xxxxx,yyyyy/_search

  1. 用*号匹配,在匹配到的所有索引下查找数据
1
2
GET /zzzzzz-*/_search

当然这里也可以用逗号分割多个匹配索引

分页查询

上边有说到查询结果hits默认只展示10个文档,那我们如何查询10个以后的文档呢?ES中给了sizefrom两个参数

size: 设置一次返回的结果数量,也就是hits中的文档数量,默认为10

from: 设置从第几个结果开始往后查询,默认值为0

1
2
3
4
5
6
7
8
9
GET /xxxxx/_search
{
"size": 5,
"from": 10,
"query":{
"match_all": {}
}
}

以上查询就表示查询xxxxx索引下的所有数据,并会在hits中显示第11到第15个文档的数据

全文查询

上边有用到一个match_all的全文查询关键字,match_all为查询所有记录,常用的查询关键字在ES中还有以下几个

match

最简单的查询,下边的例子就表示查找hostaaaaa.cn的所有记录

1
2
3
4
5
6
7
8
GET /xxxxxx/_search
{
"query":{
"match": {
"host":"aaaaa.cn"
}
}
}

multi_match

在多个字段上执行相同的match查询,下边的例子就表示查询hosthttp_referer字段中包含aaaaa.cn的记录

1
2
3
4
5
6
7
8
9
10
GET /aaaaa-2019.05.15/_search
{
"query":{
"multi_match": {
"query":"aaaaa.cn",
"fields":["host","http_referer"]
}
}
}

query_string

可以在查询里边使用AND或者OR来完成复杂的查询,例如:

1
2
3
4
5
6
7
8
9
10
GET /xxxxx/_search
{
"query":{
"query_string": {
"query":"(a.aaaaa.cn) OR (b.aaaaa.cn)",
"fields":["host"]
}
}
}

以上表示查找host为a.aaaaa.cn或者b.aaaaa.cn的所有记录

也可以用下边这种方式组合更多的条件完成更复杂的查询请求

1
2
3
4
5
6
7
8
9
GET /xxxxx/_search
{
"query":{
"query_string": {
"query":"host:a.aaaaa.cn OR (host:b.aaaaa.cn AND status:403)"
}
}
}

以上表示查询(host为a.aaaaa.cn)或者是(host为b.aaaaa.cn且status为403)的所有记录

与其像类似的还有个simple_query_string的关键字,可以将query_string中的AND或OR用+|这样的符号替换掉

term

term可以用来精确匹配,精确匹配的值可以是数字、时间、布尔值或者是设置了not_analyzed不分词的字符串

1
2
3
4
5
6
7
8
9
10
GET /efun_alias-*/_search
{
"query": {
"term": {
"sys": {
"value": "su"
}
}
}
}

term对输入的文本不进行分析,直接精确匹配输出结果,如果要同时匹配多个值可以使用terms

1
2
3
4
5
6
7
8
9
GET /efun_alias-*/_search
{
"query": {
"terms": {
"sys": ["su","systemd"]

}
}
}

range

range用来查询落在指定区间内的数字或者时间

1
2
3
4
5
6
7
8
9
10
11
12
GET /xxxxx/_search
{
"query": {
"range":{
"status":{
"gte": 400,
"lte": 599
}
}
}
}

以上表示搜索所有状态为400到599之间的数据,这里的操作符主要有四个gt大于,gte大于等于,lt小于,lte小于等于

当使用日期作为范围查询时,我们需要注意下日期的格式,官方支持的日期格式主要有两种

时间戳,注意是毫秒粒度

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /xxxxx/_search
{
"query": {
"range": {
"@timestamp": {
"gte": 1557676800000,
"lte": 1557680400000,
"format":"epoch_millis"
}
}
}
}

日期字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
GET /xxxxx/_search
{
"query": {
"range":{
"@timestamp":{
"gte": "2019-05-13 18:30:00",
"lte": "2019-05-14",
"format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd",
"time_zone": "+08:00"
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
GET /efun_alias-*/_search
{
"query": {
"range": {
"@timestamp_02": {
"gte": "now-12h",
"lte": "now"
}
}
}
}

通常更推荐用这种日期字符串的方式,看起来比较清晰,日期格式可以按照自己的习惯输入,只需要format字段指定匹配的格式,如果格式有多个就用||分开,像例子中那样,不过我更推荐用同样的日期格式

如果日期中缺少年月日这些内容,那么缺少的部分会用unix的开始时间(即1970年1月1日)填充,当你将"format":"dd"指定为格式时,那么"gte":10将被转换成1970-01-10T00:00:00.000Z

elasticsearch中默认使用的是UTC时间,所以我们在使用时要通过time_zone来设置好时区,以免出错

bool

  • 布尔查询的子句类型有四种: must、filter、should、must_not
  1. must
    算分
    返回的文档必须满足 must 子句的条件
    多个查询条件的完全匹配,相当于 AND

  2. filter
    不算分的 must

  3. should
    算分
    在一个 bool 查询中,如果没有 must 或者 filter,
    有一个或者多个should子句,那么只要满足一个就可以返回。
    minimum_should_match 参数定义了至少满足几个子句
    至少有一个查询条件匹配,相当于 OR

  4. must_not
    不算分
    返回的文档必须不满足 must_not 定义的条件
    多个查询条件的相反匹配,相当于 NOT

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
POST _search
{
"query": {
"bool" : {
"must" : {
"term" : { "user" : "kimchy" }
},
"filter": {
"term" : { "tag" : "tech" }
},
"must_not" : {
"range" : {
"age" : { "gte" : 10, "lte" : 20 }
}
},
"should" : [
{ "term" : { "tag" : "wow" } },
{ "term" : { "tag" : "elasticsearch" } }
],
"minimum_should_match" : 1,
"boost" : 1.0
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
GET /efun_alias-*/_search
{
"query": {
"bool": {
"filter": {
"range": {
"@timestamp_02": {
"gte": "now-24h",
"lte": "now"
}
}
},
"must_not": {
"term": {
"sys": {
"value": "su"
}
}
}
}
}
}