ES查询语法一文掌握

474 阅读8分钟

ES查询

查询的基本语法结构

GET /{索引名}/_search
{
 "from" : 0,  // 搜索结果的开始位置
   "size" : 10, // 分页大小,也就是一次返回多少数据
   "_source" :[ ...需要返回的字段数组... ],
 "query" : { ...query子句... },
 "aggs" : { ..aggs子句..  },
 "sort" : { ..sort子句..  }
}

先看一下URI部分,{索引名}是我们要搜索的索引,可以放置多个索引,使用逗号进行分隔,比如:

GET /_order_demo1,_order_demo2/_search
GET /_order*/_search # 按前缀匹配索引名

查询结果:

{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "order",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : 10000,
          "status" : 0,
          "total_price" : 10000,
          "create_time" : "2020-09-06 17:30:22",
          "user" : {
            "id" : 10000,
            "username" : "asong2020",
            "phone" : "888888888",
            "address" : "深圳人才区"
          }
        }
      }
    ]
  }
}
  • ES查询分页:通过from和size参数设置,相当于MYSQL的limit和offset结构
  • query:主要编写类似SQL的Where语句,支持布尔查询(and/or)、IN、全文搜索、模糊匹配、范围查询(大于小于)
  • aggs:主要用来编写统计分析语句,类似SQL的group by语句
  • sort:用来设置排序条件,类似SQL的order by语句
  • source:用于设置查询结果返回什么字段,相当于select语句后面指定字段

单字段查询

匹配单个字段

GET /{索引名}/_search
{
  "query": {
    "match": {
      "{FIELD}": "{TEXT}"
    }
  }
}

{FIELD} 就是我们需要匹配的字段名

{TEXT} 就是我们需要匹配的内容

精确匹配单个字段

当我们需要根据手机号、用户名来搜索一个用户信息时,这就需要使用精确匹配了。可以使用term实现精确匹配语法:

GET /{索引名}/_search
{
  "query": {
    "term": {
      "{FIELD}": "{VALUE}"
    }
  }
}

{FIELD} - 就是我们需要匹配的字段名

{VALUE} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。

多值匹配

多值匹配,也就是想mysql中的in语句一样,一个字段包含给定数组中的任意一个值匹配。上文使用term实现单值精确匹配,同理terms就可以实现多值匹配。

GET /{索引名}/_search
{
  "query": {
    "terms": {
      "{FIELD}": [
        "{VALUE1}",
        "{VALUE2}"
      ]
    }
  }
}

{FIELD} - 就是我们需要匹配的字段名

{VALUE1}, {VALUE2} .... {VALUE N} - 就是我们需要匹配的内容,除了TEXT类型字段以外的任意类型。

范围查询

我们想通过范围来确实查询数据,这时应该怎么做呢?不要慌,当然有办法了,使用range就可以实现范围查询,相当于SQL语句的>,>=,<,<=表达式

GET /{索引名}/_search
{
  "query": {
    "range": {
      "{FIELD}": {
        "gte": 100, 
        "lte": 200
      }
    }
  }
}
  • {FIELD} - 字段名
  • gte范围参数 - 等价于>=
  • lte范围参数 - 等价于 <=
  • 范围参数可以只写一个,例如:仅保留 "gte": 100, 则代表 FIELD字段 >= 100

范围参数有如下:

gt - 大于 ( > ) gte - 大于且等于 ( >= ) lt - 小于 ( < ) lte - 小于且等于 ( <= )

bool组合查询

前面的查询都是设置单个字段的查询条件,实际项目中这么应用是很少的,基本都是多个字段的查询条件,所以接下来我们就来一起学习一下组合多个字段的查询条件。 bool查询是一个复合查询,用于组合多个子查询,支持逻辑操作符AND、OR和NOT以及过滤器。它是构建复杂查询的基础之一

我们先来看一下bool查询的基本语法结构:

GET /{索引名}/_search
{
  "query": {
    "bool": {
      "must":    [ { "match": { "field1": "value1" }} ],
      "must_not":[ { "match": { "field2": "value2" }} ],
      "should":  [ { "match": { "field3": "value3" }} ],
      "filter":  [ { "range": { "date_field": { "gte": "2022-01-01" }}} ]
    }
  }
}

must: 这是一个必须匹配的子查询,相当于AND操作符。文档必须满足所有must子查询条件。 must_not: 这是一个必须不匹配的子查询,相当于NOT操作符。文档不能满足任何must_not子查询条件。 should: 这是一个可选匹配的子查询,相当于OR操作符。文档可以满足任何should子查询条件,但不是必须的。 filter: 这是一个过滤器子查询,用于对文档进行过滤,不影响相关性评分。

在bool查询中,这些子查询可以根据实际需求组合和嵌套,以构建复杂的查询逻辑。

排序

假设我们现在要查询订单列表,那么返回符合条件的列表肯定不会是无序的,一般都是按照时间进行排序的,所以我们就要使用到了排序语句。ES的默认排序是根据相关性分数排序,如果我们想根据查询结果中的指定字段排序,需要使用sort Processors处理

GET /{索引名}/_search
{
  "query": {
    ...查询条件....
  },
  "sort": [
    {
      "{Field1}": { // 排序字段1
        "order": "desc" // 排序方向,asc或者desc, 升序和降序
      }
    },
    {
      "{Field2}": { // 排序字段2
        "order": "desc" // 排序方向,asc或者desc, 升序和降序
      }
    }
    ....多个排序字段.....
  ]
}

sort子句支持多个字段排序,类似SQL的order by。

聚合查询

ES中的聚合查询,类似SQL的SUM/AVG/COUNT/GROUP BY分组查询,主要用于统计分析场景。

我们先来看一看什么是聚合查询:

ES聚合查询类似SQL的GROUP by,一般统计分析主要分为两个步骤:

  • 分组
  • 组内聚合

对查询的数据首先进行一轮分组,可以设置分组条件,例如:新生入学,把所有的学生按专业分班,这个分班的过程就是对学生进行了分组。

组内聚合,就是对组内的数据进行统计,例如:计算总数、求平均值等等,接上面的例子,学生都按专业分班了,那么就可以统计每个班的学生总数, 这个统计每个班学生总数的计算,就是组内聚合计算。

知道了什么是聚合,下面我们就来看其中几个重要关键字:

  • 桶:桶的就是一组数据的集合,对数据分组后,得到一组组的数据,就是一个个的桶。ES中桶聚合,指的就是先对数据进行分组。

  • 指标:指标指的是对文档进行统计计算方式,又叫指标聚合。桶内聚合,说的就是先对数据进行分组(分桶),然后对每一个桶内的数据进行指标聚合。说白了就是,前面将数据经过一轮桶聚合,把数据分成一个个的桶之后,我们根据上面计算指标对桶内的数据进行统计。常用的指标有:SUM、COUNT、MAX等统计函数。

了解了真正的概念,我们就可以学习聚合查询的语法了:

{
  "aggregations" : {
    "<aggregation_name>" : {
        "<aggregation_type>" : {
            <aggregation_body>
        }
        [,"aggregations" : { [<sub_aggregation>]+ } ]? // 嵌套聚合查询,支持多层嵌套
    }
    [,"<aggregation_name_2>" : { ... } ]* // 多个聚合查询,每个聚合查询取不同的名字
  }
}
  • aggregations - 代表聚合查询语句,可以简写为aggs
  • <aggregation_name> - 代表一个聚合计算的名字,可以随意命名,因为ES支持一次进行多次统计分析查询,后面需要通过这个名字在查询结果中找到我们想要的计算结果。
  • <aggregation_type> - 聚合类型,代表我们想要怎么统计数据,主要有两大类聚合类型,桶聚合和指标聚合,这两类聚合又包括多种聚合类型,例如:指标聚合:sum、avg, 桶聚合:terms、Date histogram等等。
  • <aggregation_body> - 聚合类型的参数,选择不同的聚合类型,有不同的参数。
  • aggregation_name_2 - 代表其他聚合计算的名字,意思就是可以一次进行多种类型的统计。

假设现在order索引中,存储了每一笔外卖订单,里面包含了店铺名字这个字段,那我们想要统计每个店铺的订单数量,就需要用到聚合查询。

GET /order/_search
{
    "size" : 0, // 设置size=0的意思就是,仅返回聚合查询结果,不返回普通query查询结果。
    "aggs" : { // 简写
        "count_store" : { // 聚合查询名字
            "terms" : { // 聚合类型为,terms,terms是桶聚合的一种,类似SQL的group by的作用,根据字段分组,相同字段值的文档分为一组。
              "field" : "store_name" // terms聚合类型的参数,这里需要设置分组的字段为store_name,根据store_name分组
            }
        }
    }
}

这里我们没有明确指定指标聚合函数,默认使用的是Value Count聚合指标统计文档总数。

接下来我们就来介绍一下各个指标聚合函数:

Value Count:值聚合,主要用于统计文档总数,类似SQL的count函数。

GET /sales/_search?size=0
{
  "aggs": {
    "types_count": { // 聚合查询的名字,随便取个名字
      "value_count": { // 聚合类型为:value_count
        "field": "type" // 计算type这个字段值的总数
      }
    }
  }
}

cardinality

基数聚合,也是用于统计文档的总数,跟Value Count的区别是,基数聚合会去重,不会统计重复的值,类似SQL的count(DISTINCT 字段)用法。

POST /sales/_search?size=0
{
    "aggs" : {
        "type_count" : { // 聚合查询的名字,随便取一个
            "cardinality" : { // 聚合查询类型为:cardinality
                "field" : "type" // 根据type这个字段统计文档总数
            }
        }
    }
}

avg

求平均值

POST /exams/_search?size=0
{
  "aggs": {
    "avg_grade": { // 聚合查询名字,随便取一个名字
      "avg": { // 聚合查询类型为: avg
        "field": "grade" // 统计grade字段值的平均值
      }
    }
  }
}

Sum 求和计算

POST /sales/_search?size=0
{
  "aggs": {
    "hat_prices": { // 聚合查询名字,随便取一个名字
      "sum": { // 聚合类型为:sum
        "field": "price" // 计算price字段值的总和
      }
    }
  }
}

max 求最大值

POST /sales/_search?size=0
{
  "aggs": {
    "max_price": { // 聚合查询名字,随便取一个名字
      "max": { // 聚合类型为:max
        "field": "price" // 求price字段的最大值
      }
    }
  }
}

min 求最小值

POST /sales/_search?size=0
{
  "aggs": {
    "min_price": { // 聚合查询名字,随便取一个
      "min": { // 聚合类型为: min
        "field": "price" // 求price字段值的最小值
      }
    }
  }
}