当前位置:   article > 正文

springboot + elasticsearch 实现聚合查询_springboot elasticsearch 聚合查询

springboot elasticsearch 聚合查询

需求背景:

终端上报表读数 记录在elasticsearch

统计每天 最大值最小值

springboot版本:2.2.6   默认的elasticsearch

  1. <groupId>org.springframework.data</groupId>
  2. <artifactId>spring-data-elasticsearch</artifactId>
  3. <version>3.2.6.RELEASE</version>

版本 elasticsearch

  1. {
  2. "name" : "node1",
  3. "cluster_name" : "docker-cluster",
  4. "cluster_uuid" : "Lg0bD-E-Thuaw4cDN5uQrQ",
  5. "version" : {
  6. "number" : "7.4.2",
  7. "build_flavor" : "default",
  8. "build_type" : "tar",
  9. "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96",
  10. "build_date" : "2019-10-28T20:40:44.881551Z",
  11. "build_snapshot" : false,
  12. "lucene_version" : "8.2.0",
  13. "minimum_wire_compatibility_version" : "6.8.0",
  14. "minimum_index_compatibility_version" : "6.0.0-beta1"
  15. },
  16. "tagline" : "You Know, for Search"
  17. }

根据springdata官网

Spring Data Elasticsearch - Reference Documentation

 版本符合

这里为了方便 采用的是 api创建索引

切记这里没有采用spring-data 去创建索引 而是采用的是 api 接口创建 原因后面再提

  1. @PutMapping("/createIndex")
  2. @ApiOperation(value = "创建索引")
  3. public R<Object> createIndex() {
  4. boolean index = elasticsearchRestTemplate.createIndex(DataUploadInfo.class);
  5. elasticsearchRestTemplate.putMapping(DataUploadInfo.class);
  6. return R.success();
  7. }
  1. import io.swagger.annotations.ApiModelProperty;
  2. import lombok.Data;
  3. import org.springframework.data.annotation.Id;
  4. import org.springframework.data.annotation.TypeAlias;
  5. import org.springframework.data.elasticsearch.annotations.DateFormat;
  6. import org.springframework.data.elasticsearch.annotations.Document;
  7. import org.springframework.data.elasticsearch.annotations.Field;
  8. import org.springframework.data.elasticsearch.annotations.FieldType;
  9. /**
  10. * {
  11. * "busId": "1000010814",
  12. * "createTime": 1649408879000,
  13. * "deviceNum": "AE0007A1GMBC00047P",
  14. * "gunNo": "1",
  15. * "rdChargeCurrent": 5.617,
  16. * "rdChargingPower": 1220.0,
  17. * "rdChargingVoltage": 225.11,
  18. * "totalElectricalPower": 270305.0
  19. * }
  20. *
  21. *
  22. *
  23. * @Field(type=FieldType.Text, analyzer=“ik_max_word”) 表示该字段是一个文本,并作最大程度拆分,默认建立索引
  24. * @Field(type=FieldType.Text,index=false) 表示该字段是一个文本,不建立索引
  25. * @Field(type=FieldType.Date) 表示该字段是一个文本,日期类型,默认不建立索引
  26. * @Field(type=FieldType.Long) 表示该字段是一个长整型,默认建立索引
  27. * @Field(type=FieldType.Keyword) 表示该字段内容是一个文本并作为一个整体不可分,默认建立索引
  28. * @Field(type=FieldType.Float) 表示该字段内容是一个浮点类型并作为一个整体不可分,默认建立索引
  29. * <p>
  30. * date 、float、long都是不能够被拆分的
  31. */
  32. @Data
  33. @Document(indexName = "charging-monitor-data", indexStoreType = "_doc", useServerConfiguration = true, createIndex = false)
  34. @TypeAlias("_doc")
  35. public class DataUploadInfo {
  36. /**
  37. * 主键
  38. */
  39. @Id
  40. @ApiModelProperty(value = "主键", example = "11", hidden = true)
  41. private String id;
  42. @ApiModelProperty(value = "枪号", example = "1")
  43. @Field(type = FieldType.Keyword )
  44. private String gunNo;
  45. @ApiModelProperty(value = "桩号", example = "DG1120B1CN1C000125")
  46. @Field(type = FieldType.Keyword)
  47. private String deviceNum;
  48. @ApiModelProperty(value = "流水ID", example = "AU22188888888888")
  49. @Field(type = FieldType.Keyword )
  50. private String busId;
  51. @ApiModelProperty(value = "充电电流(毫安)", example = "21.21")
  52. @Field(type = FieldType.Double, index = false)
  53. private Double rdChargeCurrent;
  54. @ApiModelProperty(value = "充电电压(毫伏)", example = "212.21")
  55. @Field(type = FieldType.Double, index = false)
  56. private Double rdChargingVoltage;
  57. @ApiModelProperty(value = "充电电能(瓦)", example = "212.21")
  58. @Field(type = FieldType.Double, index = false)
  59. private Double rdChargingPower;
  60. @ApiModelProperty(value = "剩余时间(分钟)", example = "21")
  61. @Field(type = FieldType.Integer, index = false)
  62. private Integer rdTimeLeft;
  63. @ApiModelProperty(value = "电量百分比(soc)", example = "29")
  64. @Field(type = FieldType.Integer, index = false)
  65. private Integer rdCurrentSoc;
  66. @ApiModelProperty(value = "电表读数 单位kwh 保留三位小数,启动成功时才有", example = "2.292")
  67. @Field(type = FieldType.Double, index = false)
  68. private Double totalElectricalPower;
  69. @ApiModelProperty(value = "正极温度", example = "22")
  70. @Field(type = FieldType.Integer, index = false)
  71. private Integer gunPositiveTemperature;
  72. @ApiModelProperty(value = "负极温度", example = "83")
  73. @Field(type = FieldType.Integer, index = false)
  74. private Integer gunNegativeTemperature;
  75. @ApiModelProperty(value = "电量上报时间", example = "1648646486000")
  76. @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis")
  77. private Long createTime;
  78. }

这里是创建 映射的Java文件 注意配置   createIndex = false

这里不自动创建索引

我们调用上面的rest 接口创建 索引

查看_mapping 会发现

  1. {
  2. -"charging-monitor-data": {
  3. -"mappings": {
  4. -"properties": {
  5. -"busId": {
  6. "type": "keyword"
  7. },
  8. -"createTime": {
  9. "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis",
  10. "type": "date"
  11. },
  12. -"deviceNum": {
  13. "type": "keyword"
  14. },
  15. -"gunNegativeTemperature": {
  16. "index": false,
  17. "type": "integer"
  18. },
  19. -"gunNo": {
  20. "type": "keyword"
  21. },
  22. -"gunPositiveTemperature": {
  23. "index": false,
  24. "type": "integer"
  25. },
  26. -"id": {
  27. -"fields": {
  28. -"keyword": {
  29. "ignore_above": 256,
  30. "type": "keyword"
  31. }
  32. },
  33. "type": "text"
  34. },
  35. -"rdChargeCurrent": {
  36. "index": false,
  37. "type": "double"
  38. },
  39. -"rdChargingPower": {
  40. "index": false,
  41. "type": "double"
  42. },
  43. -"rdChargingVoltage": {
  44. "index": false,
  45. "type": "double"
  46. },
  47. -"rdCurrentSoc": {
  48. "index": false,
  49. "type": "integer"
  50. },
  51. -"rdTimeLeft": {
  52. "index": false,
  53. "type": "integer"
  54. },
  55. -"totalElectricalPower": {
  56. "index": false,
  57. "type": "double"
  58. }
  59. }
  60. }
  61. }
  62. }

keyword类型会增加keyword属性 而不是直接增加到我定义gunNegativeTemperature的属性下面

  1. "pojo里面定义的属性": {
  2. -"fields": {
  3. -"keyword": {
  4. "ignore_above": 256,
  5. "type": "keyword"
  6. }
  7. },
  8. "type": "text"
  9. }

下面按照桩枪做每日电表的最大最小值

上代码

  1. import com.haoran.cloud.app.monitor.entity.DataUploadInfo;
  2. import com.haoran.cloud.app.monitor.ocpp.OcppResult;
  3. import io.swagger.annotations.Api;
  4. import io.swagger.annotations.ApiOperation;
  5. import lombok.extern.log4j.Log4j2;
  6. import org.elasticsearch.index.query.BoolQueryBuilder;
  7. import org.elasticsearch.index.query.QueryBuilders;
  8. import org.elasticsearch.search.aggregations.Aggregation;
  9. import org.elasticsearch.search.aggregations.AggregationBuilders;
  10. import org.elasticsearch.search.aggregations.Aggregations;
  11. import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms;
  12. import org.elasticsearch.search.aggregations.bucket.terms.Terms;
  13. import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
  14. import org.elasticsearch.search.aggregations.metrics.max.MaxAggregationBuilder;
  15. import org.elasticsearch.search.aggregations.metrics.max.ParsedMax;
  16. import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder;
  17. import org.elasticsearch.search.aggregations.metrics.min.ParsedMin;
  18. import org.joda.time.DateTime;
  19. import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
  20. import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
  21. import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
  22. import org.springframework.validation.annotation.Validated;
  23. import org.springframework.web.bind.annotation.*;
  24. import javax.annotation.Resource;
  25. import java.text.DateFormat;
  26. import java.text.ParseException;
  27. import java.text.SimpleDateFormat;
  28. import java.util.Date;
  29. import java.util.List;
  30. import java.util.Map;
  31. /**
  32. * @author wenhaoran
  33. * @version 1.0
  34. */
  35. @RestController
  36. @RequestMapping("/test")
  37. @Api(value = "test", tags = "test")
  38. @Log4j2
  39. @Validated
  40. public class PileMonitorController1 {
  41. /**
  42. * @return
  43. */
  44. @GetMapping("/dailySummaryEnergy")
  45. @ApiOperation(value = "每日电力汇总")
  46. public OcppResult<Object> dailySummaryEnergy() throws ParseException {
  47. BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
  48. DateTime now = DateTime.now();
  49. DateTime plus = now.plusDays(1);
  50. String fromDateStr = df.format(now.toDate());
  51. Date fromDate = df.parse(fromDateStr);
  52. String toDateStr = df.format(plus.toDate());
  53. Date toDate = df.parse(toDateStr);
  54. queryBuilder.must(QueryBuilders.rangeQuery("createTime").gte(fromDate.getTime()).lt(toDate.getTime()));
  55. NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(queryBuilder);
  56. TermsAggregationBuilder pile = AggregationBuilders.terms("group_deviceNum").field("deviceNum");
  57. TermsAggregationBuilder gun = AggregationBuilders.terms("group_gunNo").field("gunNo");
  58. MinAggregationBuilder minNumber = AggregationBuilders.min("minNumber").field("totalElectricalPower");
  59. MaxAggregationBuilder maxNumber = AggregationBuilders.max("maxNumber").field("totalElectricalPower");
  60. gun.subAggregation(minNumber).subAggregation(maxNumber);
  61. pile.subAggregation(gun);
  62. nativeSearchQueryBuilder.addAggregation(pile);
  63. NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build();
  64. Aggregations query = elasticsearchRestTemplate.query(nativeSearchQuery, searchResponse -> searchResponse.getAggregations());
  65. Map<String, Aggregation> stringAggregationMap = query.asMap();
  66. ParsedStringTerms stringTerms = (ParsedStringTerms) stringAggregationMap.get("group_deviceNum");
  67. List<? extends Terms.Bucket> buckets = stringTerms.getBuckets();
  68. for (Terms.Bucket bucket : buckets) {
  69. Map<String, Aggregation> pileMap = bucket.getAggregations().asMap();
  70. ParsedStringTerms gunAgg = (ParsedStringTerms) pileMap.get("group_gunNo");
  71. List<? extends Terms.Bucket> gunBucketList = gunAgg.getBuckets();
  72. for (Terms.Bucket gunBucket : gunBucketList) {
  73. Aggregations aggregations = gunBucket.getAggregations();
  74. Map<String, Aggregation> asMap = aggregations.getAsMap();
  75. if (asMap.containsKey("minNumber")) {
  76. ParsedMin aggregation = (ParsedMin) asMap.get("minNumber");
  77. System.out.println("minNumber=" + aggregation.getValue());
  78. }
  79. if (asMap.containsKey("maxNumber")) {
  80. ParsedMax aggregation = (ParsedMax) asMap.get("maxNumber");
  81. System.out.println("maxNumber=" + aggregation.getValue());
  82. }
  83. }
  84. }
  85. return OcppResult.success("success");
  86. }
  87. @DeleteMapping("/deleteIndex")
  88. @ApiOperation(value = "删除索引")
  89. public OcppResult<Object> deleteIndex() {
  90. elasticsearchRestTemplate.deleteIndex(DataUploadInfo.class);
  91. return OcppResult.success();
  92. }
  93. @PutMapping("/createIndex")
  94. @ApiOperation(value = "创建索引")
  95. public OcppResult<Object> createIndex() {
  96. boolean index = elasticsearchRestTemplate.createIndex(DataUploadInfo.class);
  97. elasticsearchRestTemplate.putMapping(DataUploadInfo.class);
  98. return OcppResult.success();
  99. }
  100. final DateFormat df = new SimpleDateFormat("yyyy-MM-dd");
  101. @Resource
  102. private ElasticsearchRestTemplate elasticsearchRestTemplate;
  103. }

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/一键难忘520/article/detail/785753
推荐阅读
相关标签
  

闽ICP备14008679号