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字段值的最小值
}
}
}
}