侧边栏壁纸
博主头像
孔子说JAVA博主等级

成功只是一只沦落在鸡窝里的鹰,成功永远属于自信且有毅力的人!

  • 累计撰写 352 篇文章
  • 累计创建 135 个标签
  • 累计收到 10 条评论

目 录CONTENT

文章目录

ES教程7-聚合查询语法及示例

孔子说JAVA
2022-10-12 / 0 评论 / 0 点赞 / 189 阅读 / 16,240 字 / 正在检测是否收录...
广告 广告

聚合查询可以将数据汇总为度量、统计或其他分析,为用户提供了进行分组和数理统计的能力,可以把聚合理解成SQL中的GROUP BY和分组函数。ES提供了强大的聚合分析功能,按照操作上细化,可以主要分为类: Bucket桶聚合、Metric指标聚合、Pipeline管道聚合。

1、数据准备

1.1 创建索引

创建地址如下,其中 employee 表示索引名称,请求方式选择PUT。

http://172.19.82.206:9200/employee/

然后在请求体(Body)中,mapping的定义如下:

{
  "mappings": {
    "properties": {
      "id": {
        "type": "integer"
      },
      "name": {
        "type": "keyword"
      },
      "job": {
        "type": "keyword"
      },
      "age": {
        "type": "integer"
      },
      "gender": {
        "type": "keyword"
      }
    }
  }
}

数据说明:name是员工的姓名,job是员工的工种,age为员工的年龄,sal为员工的薪水,gender为员工的性别

image-1665362800771

1.2 添加文档

es数据的批量插入方式如下:

PUT /employee/_bulk

其中的 employee 是索引名;_bulk表示批量插入,需要使用POST添加。BODY如下:

{"index": {"_id": 1}}
{"id": 1, "name": "Bob", "job": "java", "age": 21, "sal": 8000, "gender": "male"}
{"index": {"_id": 2}}
{"id": 2, "name": "Rod", "job": "html", "age": 31, "sal": 18000, "gender": "female"}
{"index": {"_id": 3}}
{"id": 3, "name": "Gaving", "job": "java", "age": 24, "sal": 12000, "gender": "male"}
{"index": {"_id": 4}}
{"id": 4, "name": "King", "job": "dba", "age": 26, "sal": 15000, "gender": "female"}
{"index": {"_id": 5}}
{"id": 5, "name": "Jonhson", "job": "dba", "age": 29, "sal": 16000, "gender": "male"}
{"index": {"_id": 6}}
{"id": 6, "name": "Douge", "job": "java", "age": 41, "sal": 20000, "gender": "female"}
{"index": {"_id": 7}}
{"id": 7, "name": "cutting", "job": "dba", "age": 27, "sal": 7000, "gender": "male"}
{"index": {"_id": 8}}
{"id": 8, "name": "Bona", "job": "html", "age": 22, "sal": 14000, "gender": "female"}
{"index": {"_id": 9}}
{"id": 9, "name": "Shyon", "job": "dba", "age": 20, "sal": 19000, "gender": "female"}
{"index": {"_id": 10}}
{"id": 10, "name": "James", "job": "html", "age": 18, "sal": 22000, "gender": "male"}
{"index": {"_id": 11}}
{"id": 11, "name": "Golsling", "job": "java", "age": 32, "sal": 23000, "gender": "female"}
{"index": {"_id": 12}}
{"id": 12, "name": "Lily", "job": "java", "age": 24, "sal": 2000, "gender": "male"}
{"index": {"_id": 13}}
{"id": 13, "name": "Jack", "job": "html", "age": 23, "sal": 3000, "gender": "female"}
{"index": {"_id": 14}}
{"id": 14, "name": "Rose", "job": "java", "age": 36, "sal": 6000, "gender": "female"}
{"index": {"_id": 15}}
{"id": 15, "name": "Will", "job": "dba", "age": 38, "sal": 4500, "gender": "male"}
{"index": {"_id": 16}}
{"id": 16, "name": "smith", "job": "java", "age": 32, "sal": 23000, "gender": "male"}

使用postman执行,Headers设置:

image-1665364783559

使用postman执行,Body设置及执行:

image-1665364964594

查询插入结果:

image-1665365190712

2、查询数据分类

查询 请求方式 url格式 示例
查询某个索引信息 GET 请求 ip:port/<索引名> localhost:9200/product
指定id查询单条数据 GET 请求 ip:port/<索引名>/<类型名称>/<文档id> localhost:9200/product/_doc/1
指定索引查询数据 GET 请求 ip:port/<索引名>/_search localhost:9200/product/_search
全es查询数据 GET 请求 ip:port/_search localhost:9200/_search

ES的数据查询主要分为:

  • query查询:这种语句在执行时既要计算文档是否匹配,还要计算文档相对于其他文档的匹配度有多高。会在查询结果的每条数据中,计算一个_score 值来表示匹配度,查询结果并按_score倒序排列;

  • filter查询:在查询过程中,只判断该文档是否满足条件,不会进行匹配度计算;

所有查询操作都可以分为基础查询聚合查询符合查询

3、聚合查询示例

下述示例中,如无特殊说明,均为POST请求方式,请求地址为:http://172.19.82.206:9200/employee/_search/,employee 是索引名。

如何运行一个聚合查询

GET /my-index-000001/_search
{
  "aggs": {
    "my-agg-name": {
      "terms": {
        "field": "my-field"
      }
    }
  }
}

在哪个查询结果的基础上聚合,则在其平级下写 aggs

说明:

  • aggs 说明采用的是聚合查询
  • my-agg-name 是聚合查询的名称,为自定义变量名
  • terms 声明查询条件,说明采用的是Terms aggregation多值聚合:一个基于多桶值源的聚合,其中桶是动态构建的——每个唯一值一个桶。统计每个唯一值的个数。
  • field 指定需要统计的字段(聚合字段),即结果按 my-field 字段进行统计。

3.1 Bucket 桶聚合

分桶就是将具有某一类共同特征的数据归为一类,然后求其总数,例如: 男女、公司同一工作岗位的员工、商品高中低档等。在对数据分桶后还可以进一步分桶,例如:020岁男性、2150岁男性、50岁以上男性;同一工作岗位男性、女性;高档商品好评、中评、差评的商品。

image-1665365997277

3.1.1 terms 聚合

terms根据字段值项分组聚合,field按什么字段分组,size指定返回多少个分组,shard_size指定每个分片上返回多少个分组,order排序方式,可以指定include和exclude正则筛选表达式的值,指定missing设置缺省值。

  • (结构化数据查询,比如数字、日期等)不会对查询目标进行分词处理,完全匹配。
  • 默认情况下,包含聚合的查询会同时返回搜索命中的结果和聚合结果。若要只返回聚合结果,请将大小size设置为0

按工种job属性分组查询每个工种下的人员数量。

未指定size查询会同时返回搜索命中的结果和聚合结果

POST employee/_search
{
  "aggs": {
    "job_category_count": {
      "terms": {
        "field": "job"
      }
    }
  }
}

image-1665368695947

将size设置为0时只返回聚合结果

POST employee/_search
{
  "size": 0, 
  "aggs": {
    "job_category_count": {
      "terms": {
        "field": "job"
      }
    }
  }
}

image-1665366674891

指定返回结果数量

{
    "size": 0, 
    "aggs": {
      "terms":{
        "terms": {
          "field": "job",
          "size": 2
        }
      }
    }
}

指定返回结果数量同时按统计数量排序

{
    "size": 0, 
    "aggs": {
      "terms":{
        "terms": {
          "field": "job",
          "size": 5,
          "order": {
            "_count": "asc"
          }
        }
      }
    }
}

3.1.2 多个聚合条件

指定多个聚合条件。

{
  "size": 0,
  "aggs": {
    "job_category_count": {
      "terms": {
        "field": "job"
      }
    },
    "gender_category_count": {
      "terms": {
        "field": "gender"
      }
    }
  }
}

image-1665371939030

3.1.3 cardinality 去重

查询有多少工种,即按照job去重后的数量。

{
  "size": 0,
  "aggs": {
    "job_category_num": {
      "cardinality": {
        "field": "job"
      }
    }
  }
}

image-1665367559654

3.1.4 二次聚合(子聚合)

统计索引中 job 字段的每个唯一值的记录数按升序排列,并计算每组记录中 sal 字段的最大值。典型的场景:先分组,再计算

{
    "size": 0, 
    "aggs": {
      "agg_terms": {
        "terms": {
          "field": "job",
          "order": {
            "_count": "asc"
          }
        },
        "aggs": {
          "max_balance": {
            "max": {
              "field": "sal"
            }
          }
        }
      }
    }
}

3.1.5 正则筛选表达式的值

{
    "size": 0, 
    "aggs": {
      "agg_terms": {
        "terms": {
          "field": "job",
          "include": ".*",
          "exclude": ".*"
        }
      }
    }
}

3.1.6 terms多个值匹配

{
    "query": {
        "terms": {
            "price": [
                9.9,
                19.9
            ]
        }
    }
}

3.2 Metric 指标聚合(计算/矩阵)

计算具有一类特征的数据的统计值,例如平均值、最大值、最小值、求和等。矩阵就是同时可以支持多值的输出,例如对分桶的数据同时求平均、最大、最小值。将过滤出来的数据集按条件分成多个小数据集,然后Metrics会分别作用在这些小数据集上。

3.2.1 单值输出

常用有:min 、max、sum、avg、cardinality(去重求和)

{
  "size": 0,
  "aggs": {
    "avg_sal": {
      "avg": {
        "field": "sal"
      }
    },
    "max_val": {
      "max": {
        "field": "sal"
      }
    },
    "min_val": {
      "min": {
        "field": "sal"
      }
    },
    "sum_val": {
      "sum": {
        "field": "sal"
      }
    },
    "cardibality_count": {
      "cardinality": {
        "field": "job"
      }
    }
  }
}

image-1665369475696

3.2.2 多值输出 stats

stats: 根据查询的字段求查询的数量、最大值、最小值、平均值、总和。

{
  "size": 0,
  "aggs": {
    "stats_info": {
      "stats": {
        "field": "sal"
      }
    }
  }
}

image-1665369596328

3.2.3 terms查询嵌套

查询不同岗位下人数,同时嵌套查询不同岗位下不同性别的人数

{
  "size": 0, 
  "aggs": {
    "job_count": {
      "terms": {
        "field": "job"  //查询不同岗位下的人数
      },
      "aggs": {
        "gender_count": {
          "terms": {
            "field": "gender" //查询不同岗位下不同性别的人数
          }
        }
      }
    }
  }
}

image-1665369867776

查询不同岗位下工资的详情(总数、最大值、最小值、平均值、和)

{
  "size": 0,
  "aggs": {
    "job_count": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "stats_count": {
          "stats": {
            "field": "sal"
          }
        }
      }
    }
  }
}

image-1665369730842

aggs 还可以套3层,4层…

3.2.4 top_hits查询

查询年龄最大的两名员工信息

{
  "size": 0,
  "aggs": {
    "top_age_infot": {
      "top_hits": {
        "size": 2,
        "sort": [
          {
            "age": {
              "order": "desc"
            }
          }
        ]
      }
    }
  }
}

image-1665370058822

查询不同工种的员工的数量,并查询每个工种最大年龄的员工信息。

{
  "size": 0,
  "aggs": {
    "job_analysis": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "age_top_1": {
          "top_hits": {
            "size": 1,
            "sort": [
              {
                "age": {
                  "order": "desc"
                }
              }
            ]
          }
        }
      }
    }
  }
}

image-1665368333626

3.2.5 range范围统计查询

指定工资范围内的员工数量: 查询工资范围在 0~5000, 5001~8000, 8001~12000, 12001~18000, 18001+ 员工的人数

{
  "size": 0,
  "aggs": {
    "sal_range_info": {
      "range": {
        "field": "sal",
        "ranges": [
          {
            "to": 5000
          },
          {
            "from": 5001,
            "to": 8000
          },
          {
            "from": 8001,
            "to": 12000
          },
          {
            "from": 12001,
            "to": 18000
          },
          {
            "from": 18001
          }
        ]
      }
    }
  }
}

image-1665367796078

{
  "size": 0,
  "aggs": {
    "range_infot": {
      "range": {
        "field": "sal",
        "ranges": [
          {
            "key": "0-5000",
            "from": 0,
            "to": 5000
          },
          {
            "key": "5000-10000",
            "from": 5000,
            "to": 10000
          },
          {
            "key": "10000<",
            "from": 10000
          }
        ]
      }
    }
  }
}

image-1665370196104

使用gte/lte关键字

{
    "query": {
        "range": {  -- 声明查询动作
            "price": { -- 声明查询字段
                "gte": 6.7,  --  大于等于6.7, 只要大于是  gt(e是equals缩写)
                "lte": 40.2  -- 小于等于40.2, 只要小于是  lt
            }
        }
    }
}

备注:针对日期查询,es还支持指定到当前日期,关键字为now。 比如 “lte”: “now”, 表示小于等于当前日期

3.2.6 histogram直方图区间统计

以每5000为一个区间,查询工资在对应范围内的员工的数量

{
  "size": 0,
  "aggs": {
    "sal_histogram": {
      "histogram": {
        "field": "sal",
        "interval": 5000,
        "extended_bounds": {
          "min": 0,
          "max": 25000
        }
      }
    }
  }
}

image-1665367880936

{
  "size": 0,
  "aggs": {
    "sal_histogram": {
      "histogram": {
        "field": "sal",
        "interval": 5000
      }
    }
  }
}

image-1665370335496

3.2.7 多结果的矩阵

查询每个工种的数量,以及不同工种的工资统计信息

{
  "size": 0,
  "aggs": {
    "job_and_salary_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "sal_info": {
          "stats": {
            "field": "sal"
          }
        }
      }
    }
  }
}

image-1665368160504

3.2.8 聚合嵌套查询

不同工种下男女员工的数量,以及男女员工的薪资信息

{
  "size": 0, 
  "aggs": {
    "job_gender_sal_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "gender_info": {
          "terms": {
            "field": "gender"
          },
          "aggs": {
            "sal_info": {
              "stats": {
                "field": "sal"
              }
            }
          }
        }
      }
    }
  }
}

image-1665368222119

3.2.9 符合条件人的平均工资

查询年龄大于30岁的员工平均工资

{
  "size": 0,
  "query": {
    "range": {
      "age": {
        "gte": 30
      }
    }
  },
  "aggs": {
    "sal_info": {
      "avg": {
        "field": "sal"
      }
    }
  }
}

image-1665371154138

查询java员工的平均工资

{
  "size": 0,
  "query": {
    "constant_score": {
      "filter": {
        "term": {
          "job": "java"
        }
      }
    }
  },
  "aggs": {
    "java_avg_sal_info": {
      "avg": {
        "field": "sal"
      }
    }
  }
}

constant_score不会计算分数,用于聚合查询时可以提高效率

image-1665371344560

3.2.10 局部过滤

查询所有员工平均工资和年龄大于30岁员工平均工资

{
  "size": 0,
  "aggs": {
    "sal_avg": {
      "avg": {
        "field": "sal"
      }
    },
    "gt_30_avg_info": {
      "filter": {//局部过滤
        "range": {
          "age": {
            "gt": 30
          }
        }
      },
      "aggs": {
        "gt_30_avg_sal": {
          "avg": {
            "field": "sal"
          }
        }
      }
    }
  }
}

image-1665371448734

3.2.11 percentiles百分比

percentiles对指定字段(脚本)的值按从小到大累计每个值对应的文档数的占比(占所有命中文档数的百分比),返回指定占比比例对应的值。默认返回[ 1, 5, 25, 50, 75, 95, 99 ]分位上的值

{
  "size": 0,
  "aggs": {
    "age_percents": {
      "percentiles": {
        "field": "age",
        "percents": [
          1,
          5,
          25,
          50,
          75,
          95,
          99
        ]
      }
    }
  }
}

image-1665376037047

{
  "size": 0,
  "aggs": {
    "states": {
      "terms": {
        "field": "gender"
      },
      "aggs": {
        "banlances": {
          "percentile_ranks": {
            "field": "sal",
            "values": [
              20000,
              40000
            ]
          }
        }
      }
    }
  }
}

image-1665376183117

3.2.12 指定值的文档比

统计小于等于指定值的文档比

{
  "size": 0,
  "aggs": {
    "tests": {
      "percentile_ranks": {
        "field": "age",
        "values": [
          15,
          35
        ]
      }
    }
  }
}

image-1665376267333

3.2.13 聚合结果分页

{
  "size": 0,
  "aggs": {
    "group_account": {
      "terms": {
        "size": 3,
        "field": "name",
        "order": {
          "sum_gmv": "desc"
        }
      },
      "aggs": {
        "sum_gmv": {
          "sum": {
            "field": "age"
          }
        }
      }
    }
  }
}

image-1665376818591

3.2.14 聚合查询中使用scripts脚本

采用script脚本提取运行时字段,并对运行时字段message.length进行聚合。

GET /my-index-000001/_search?size=0
{
  "runtime_mappings": {
    "message.length": {
      "type": "long",
      "script": "emit(doc['message.keyword'].value.length())"
    }
  },
  "aggs": {
    "message_length": {
      "histogram": {
        "interval": 10,
        "field": "message.length"
      }
    }
  }
}

3.3 Pipeline 管道聚合

pipeline与Linux操作系统中的管道操作(将上一步操作的结果作为下一步操作的数据源)类似。即将上一次聚合操作的结果作为下一次聚合操作的数据源。

3.3.1 管道操作

查询平均工资最低的部门的平均工资,以及最低工资。

{
  "size": 0, 
  "aggs": {
    "jobs": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "sal_info": {
          "avg": {
            "field": "sal"
          }
        }
      }
    },
    "min_avg_sal": {
      "max_bucket": {
        "buckets_path": "jobs>sal_info"
      }
    }
  }
}

管道操作(jobs>sal_info中的>不是大于的意思,描述的为路径),指查询条件中第一级aggs下的jobs和第二级aggs下的sal_info。

image-1665368252819

3.3.2 查询每个桶的最大最小值

max_bucket查询每个桶的最大值,min_bucket查询每个桶的最小值。

查询平均工资最高部门及最低部门的平均工资。

{
  "size": 0,
  "aggs": {
    "job_info": {
      "terms": {
        "field": "job"
      },
      "aggs": {
        "job_avg_info": {
          "avg": {
            "field": "sal"
          }
        }
      }
    },
    "max_avg_sal_job": {
      "max_bucket": {
        "buckets_path": "job_info>job_avg_info"
      }
    },
    "min_avg_sal_job": {
      "min_bucket": {
        "buckets_path": "job_info>job_avg_info"
      }
    }
  }
}

管道操作(job_info>job_avg_info 中的>不是大于的意思,描述的为路径),指查询条件中第一级aggs下的job_info和第二级aggs下的job_avg_info。

image-1665370721550

4、其他聚合查询

4.1 filter聚合

filter对满足过滤查询的文档进行聚合计算,在查询命中的文档中选取过滤条件的文档进行聚合,先过滤在聚合。

{
    "size": 0, 
    "aggs": {
      "agg_filter":{
        "filter": {
          "match":{"gender":"F"}
        },
        "aggs": {
          "avgs": {
            "avg": {
              "field": "age"
            }
          }
        }
      }
    }
}

4.2 filtters聚合

多个过滤组聚合计算。

{
    "size": 0, 
    "aggs": {
      "message": {
        "filters": {
          
          "filters": {
            "errors": {
              "exists": {
                "field": "__type"
              }
            },
            "warring":{
              "term": {
                "__type": "info"
              }
            }
          }
        }
      }
    }
}

4.3 range聚合

{
    "aggs": {
      "agg_range": {
        "range": {
          "field": "cost",
          "ranges": [
            {
              "from": 50,
              "to": 70
            },
            {
              "from": 100
            }
          ]
        },
        "aggs": {
          "bmax": {
            "max": {
              "field": "cost"
            }
          }
        }
      }
    }
}

4.4 date_range聚合

{
     "aggs": {
       "date_aggrs": {
         "date_range": {
           "field": "accepted_time",
           "format": "MM-yyy", 
           "ranges": [
             {
               "from": "now-10d/d",
               "to": "now"
             }
           ]
         }
       }
     }
}

4.5 date_histogram聚合

时间直方图聚合,就是按天、月、年等进行聚合统计。可按 year (1y), quarter (1q), month (1M), week (1w), day (1d), hour (1h), minute (1m), second (1s) 间隔聚合或指定的时间间隔聚合

{ 
  "aggs": {
    "sales_over_time": {
      "date_histogram": {
        "field": "accepted_time",
        "interval": "quarter",
        "min_doc_count" : 0, //可以返回没有数据的月份
        "extended_bounds" : { //强制返回数据的范围
           "min" : "2014-01-01",
           "max" : "2014-12-31"
        }
      }
    }
  }
}

4.6 missing聚合

{ 
  
  "aggs": {
    "account_missing": {
      "missing": {
        "field": "__type"
      }
    }
  }
}

5、聚合查询缓存说明

  • 为了获得更快的响应,Elasticsearch 将频繁运行的聚合结果缓存到切分请求缓存中。
  • 若要获取缓存结果,请对每次搜索使用相同的首选项字符串。
  • 如果您不需要搜索命中、只返回聚合结果,请将大小设置为0,以避免填充缓存。
0

评论区