springboot + elasticsearch 實現(xiàn)聚合查詢的詳細(xì)代碼
需求背景:
終端上報表讀數(shù) 記錄在elasticsearch
統(tǒng)計每天 最大值最小值
springboot版本:2.2.6
默認(rèn)的elasticsearch
<groupId>org.springframework.data</groupId> <artifactId>spring-data-elasticsearch</artifactId> <version>3.2.6.RELEASE</version>
版本 elasticsearch
{ "name" : "node1", "cluster_name" : "docker-cluster", "cluster_uuid" : "Lg0bD-E-Thuaw4cDN5uQrQ", "version" : { "number" : "7.4.2", "build_flavor" : "default", "build_type" : "tar", "build_hash" : "2f90bbf7b93631e52bafb59b3b049cb44ec25e96", "build_date" : "2019-10-28T20:40:44.881551Z", "build_snapshot" : false, "lucene_version" : "8.2.0", "minimum_wire_compatibility_version" : "6.8.0", "minimum_index_compatibility_version" : "6.0.0-beta1" }, "tagline" : "You Know, for Search" }
根據(jù)springdata官網(wǎng)
Spring Data Elasticsearch - Reference Documentation
版本符合
這里為了方便 采用的是 api創(chuàng)建索引
切記這里沒有采用spring-data 去創(chuàng)建索引 而是采用的是 api 接口創(chuàng)建 原因后面再提
@PutMapping("/createIndex") @ApiOperation(value = "創(chuàng)建索引") public R<Object> createIndex() { boolean index = elasticsearchRestTemplate.createIndex(DataUploadInfo.class); elasticsearchRestTemplate.putMapping(DataUploadInfo.class); return R.success(); }
import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.data.annotation.Id; import org.springframework.data.annotation.TypeAlias; import org.springframework.data.elasticsearch.annotations.DateFormat; import org.springframework.data.elasticsearch.annotations.Document; import org.springframework.data.elasticsearch.annotations.Field; import org.springframework.data.elasticsearch.annotations.FieldType; /** * { * "busId": "1000010814", * "createTime": 1649408879000, * "deviceNum": "AE0007A1GMBC00047P", * "gunNo": "1", * "rdChargeCurrent": 5.617, * "rdChargingPower": 1220.0, * "rdChargingVoltage": 225.11, * "totalElectricalPower": 270305.0 * } * * * * @Field(type=FieldType.Text, analyzer=“ik_max_word”) 表示該字段是一個文本,并作最大程度拆分,默認(rèn)建立索引 * @Field(type=FieldType.Text,index=false) 表示該字段是一個文本,不建立索引 * @Field(type=FieldType.Date) 表示該字段是一個文本,日期類型,默認(rèn)不建立索引 * @Field(type=FieldType.Long) 表示該字段是一個長整型,默認(rèn)建立索引 * @Field(type=FieldType.Keyword) 表示該字段內(nèi)容是一個文本并作為一個整體不可分,默認(rèn)建立索引 * @Field(type=FieldType.Float) 表示該字段內(nèi)容是一個浮點類型并作為一個整體不可分,默認(rèn)建立索引 * <p> * date 、float、long都是不能夠被拆分的 */ @Data @Document(indexName = "charging-monitor-data", indexStoreType = "_doc", useServerConfiguration = true, createIndex = false) @TypeAlias("_doc") public class DataUploadInfo { /** * 主鍵 */ @Id @ApiModelProperty(value = "主鍵", example = "11", hidden = true) private String id; @ApiModelProperty(value = "槍號", example = "1") @Field(type = FieldType.Keyword ) private String gunNo; @ApiModelProperty(value = "樁號", example = "DG1120B1CN1C000125") @Field(type = FieldType.Keyword) private String deviceNum; @ApiModelProperty(value = "流水ID", example = "AU22188888888888") @Field(type = FieldType.Keyword ) private String busId; @ApiModelProperty(value = "充電電流(毫安)", example = "21.21") @Field(type = FieldType.Double, index = false) private Double rdChargeCurrent; @ApiModelProperty(value = "充電電壓(毫伏)", example = "212.21") @Field(type = FieldType.Double, index = false) private Double rdChargingVoltage; @ApiModelProperty(value = "充電電能(瓦)", example = "212.21") @Field(type = FieldType.Double, index = false) private Double rdChargingPower; @ApiModelProperty(value = "剩余時間(分鐘)", example = "21") @Field(type = FieldType.Integer, index = false) private Integer rdTimeLeft; @ApiModelProperty(value = "電量百分比(soc)", example = "29") @Field(type = FieldType.Integer, index = false) private Integer rdCurrentSoc; @ApiModelProperty(value = "電表讀數(shù) 單位kwh 保留三位小數(shù),啟動成功時才有", example = "2.292") @Field(type = FieldType.Double, index = false) private Double totalElectricalPower; @ApiModelProperty(value = "正極溫度", example = "22") @Field(type = FieldType.Integer, index = false) private Integer gunPositiveTemperature; @ApiModelProperty(value = "負(fù)極溫度", example = "83") @Field(type = FieldType.Integer, index = false) private Integer gunNegativeTemperature; @ApiModelProperty(value = "電量上報時間", example = "1648646486000") @Field(type = FieldType.Date, format = DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis") private Long createTime; }
這里是創(chuàng)建 映射的Java文件 注意配置 createIndex = false
這里不自動創(chuàng)建索引
我們調(diào)用上面的rest 接口創(chuàng)建 索引
查看_mapping 會發(fā)現(xiàn)
{ -"charging-monitor-data": { -"mappings": { -"properties": { -"busId": { "type": "keyword" }, -"createTime": { "format": "yyyy-MM-dd HH:mm:ss||yyyy-MM-dd||epoch_millis", "type": "date" }, -"deviceNum": { "type": "keyword" }, -"gunNegativeTemperature": { "index": false, "type": "integer" }, -"gunNo": { "type": "keyword" }, -"gunPositiveTemperature": { "index": false, "type": "integer" }, -"id": { -"fields": { -"keyword": { "ignore_above": 256, "type": "keyword" } }, "type": "text" }, -"rdChargeCurrent": { "index": false, "type": "double" }, -"rdChargingPower": { "index": false, "type": "double" }, -"rdChargingVoltage": { "index": false, "type": "double" }, -"rdCurrentSoc": { "index": false, "type": "integer" }, -"rdTimeLeft": { "index": false, "type": "integer" }, -"totalElectricalPower": { "index": false, "type": "double" } } } } }
keyword類型會增加keyword屬性 而不是直接增加到我定義gunNegativeTemperature的屬性下面
"pojo里面定義的屬性": { -"fields": { -"keyword": { "ignore_above": 256, "type": "keyword" } }, "type": "text" }
下面按照樁槍做每日電表的最大最小值
上代碼
import com.haoran.cloud.app.monitor.entity.DataUploadInfo; import com.haoran.cloud.app.monitor.ocpp.OcppResult; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.log4j.Log4j2; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.aggregations.Aggregation; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.Aggregations; import org.elasticsearch.search.aggregations.bucket.terms.ParsedStringTerms; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.max.MaxAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.max.ParsedMax; import org.elasticsearch.search.aggregations.metrics.min.MinAggregationBuilder; import org.elasticsearch.search.aggregations.metrics.min.ParsedMin; import org.joda.time.DateTime; import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate; import org.springframework.data.elasticsearch.core.query.NativeSearchQuery; import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; import javax.annotation.Resource; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Date; import java.util.List; import java.util.Map; /** * @author wenhaoran * @version 1.0 */ @RestController @RequestMapping("/test") @Api(value = "test", tags = "test") @Log4j2 @Validated public class PileMonitorController1 { /** * @return */ @GetMapping("/dailySummaryEnergy") @ApiOperation(value = "每日電力匯總") public OcppResult<Object> dailySummaryEnergy() throws ParseException { BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery(); DateTime now = DateTime.now(); DateTime plus = now.plusDays(1); String fromDateStr = df.format(now.toDate()); Date fromDate = df.parse(fromDateStr); String toDateStr = df.format(plus.toDate()); Date toDate = df.parse(toDateStr); queryBuilder.must(QueryBuilders.rangeQuery("createTime").gte(fromDate.getTime()).lt(toDate.getTime())); NativeSearchQueryBuilder nativeSearchQueryBuilder = new NativeSearchQueryBuilder().withQuery(queryBuilder); TermsAggregationBuilder pile = AggregationBuilders.terms("group_deviceNum").field("deviceNum"); TermsAggregationBuilder gun = AggregationBuilders.terms("group_gunNo").field("gunNo"); MinAggregationBuilder minNumber = AggregationBuilders.min("minNumber").field("totalElectricalPower"); MaxAggregationBuilder maxNumber = AggregationBuilders.max("maxNumber").field("totalElectricalPower"); gun.subAggregation(minNumber).subAggregation(maxNumber); pile.subAggregation(gun); nativeSearchQueryBuilder.addAggregation(pile); NativeSearchQuery nativeSearchQuery = nativeSearchQueryBuilder.build(); Aggregations query = elasticsearchRestTemplate.query(nativeSearchQuery, searchResponse -> searchResponse.getAggregations()); Map<String, Aggregation> stringAggregationMap = query.asMap(); ParsedStringTerms stringTerms = (ParsedStringTerms) stringAggregationMap.get("group_deviceNum"); List<? extends Terms.Bucket> buckets = stringTerms.getBuckets(); for (Terms.Bucket bucket : buckets) { Map<String, Aggregation> pileMap = bucket.getAggregations().asMap(); ParsedStringTerms gunAgg = (ParsedStringTerms) pileMap.get("group_gunNo"); List<? extends Terms.Bucket> gunBucketList = gunAgg.getBuckets(); for (Terms.Bucket gunBucket : gunBucketList) { Aggregations aggregations = gunBucket.getAggregations(); Map<String, Aggregation> asMap = aggregations.getAsMap(); if (asMap.containsKey("minNumber")) { ParsedMin aggregation = (ParsedMin) asMap.get("minNumber"); System.out.println("minNumber=" + aggregation.getValue()); } if (asMap.containsKey("maxNumber")) { ParsedMax aggregation = (ParsedMax) asMap.get("maxNumber"); System.out.println("maxNumber=" + aggregation.getValue()); } } } return OcppResult.success("success"); } @DeleteMapping("/deleteIndex") @ApiOperation(value = "刪除索引") public OcppResult<Object> deleteIndex() { elasticsearchRestTemplate.deleteIndex(DataUploadInfo.class); return OcppResult.success(); } @PutMapping("/createIndex") @ApiOperation(value = "創(chuàng)建索引") public OcppResult<Object> createIndex() { boolean index = elasticsearchRestTemplate.createIndex(DataUploadInfo.class); elasticsearchRestTemplate.putMapping(DataUploadInfo.class); return OcppResult.success(); } final DateFormat df = new SimpleDateFormat("yyyy-MM-dd"); @Resource private ElasticsearchRestTemplate elasticsearchRestTemplate; }
到此這篇關(guān)于springboot + elasticsearch 實現(xiàn)聚合查詢的文章就介紹到這了,更多相關(guān)springboot elasticsearch聚合查詢內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
SpringBoot、Java 使用 Jsoup 解析 HTML 頁面
這篇文章主要介紹了SpringBoot、Java 使用 Jsoup 解析 HTML 頁面的詳細(xì)步驟,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-08-08使用SpringBoot注解方式處理事務(wù)回滾實現(xiàn)
這篇文章主要介紹了使用SpringBoot注解方式處理事務(wù)回滾實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08java如何獲取用戶登錄ip、瀏覽器信息、SessionId
這篇文章主要介紹了java如何獲取用戶登錄ip、瀏覽器信息、SessionId,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11Struts2實現(xiàn)CRUD(增 刪 改 查)功能實例代碼
CRUD是Create(創(chuàng)建)、Read(讀?。pdate(更新)和Delete(刪除)的縮寫,它是普通應(yīng)用程序的縮影。接下來通過本文給大家介紹Struts2實現(xiàn)CRUD(增 刪 改 查)功能實例代碼,感興趣的朋友一起看看吧2016-06-06Java AOP實現(xiàn)自定義滑動窗口限流器方法詳解
這篇文章主要介紹了Java AOP實現(xiàn)自定義滑動窗口限流器方法,其中滑動窗口算法彌補了計數(shù)器算法的不足,滑動窗口算法把間隔時間劃分成更小的粒度,當(dāng)更小粒度的時間間隔過去后,把過去的間隔請求數(shù)減掉,再補充一個空的時間間隔,需要的朋友可以參考下2022-07-07java序列化對象根據(jù)不同配置動態(tài)改變屬性名的方法
本文主要介紹了java序列化對象根據(jù)不同配置動態(tài)改變屬性名的方法,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-05-05詳解Elasticsearch如何實現(xiàn)簡單的腳本排序
Elasticsearch?是位于?Elastic?Stack?核心的分布式搜索和分析引擎,可以為所有類型的數(shù)據(jù)提供近乎實時的搜索和分析。本文主要介紹了Elasticsearch如何實現(xiàn)簡單的腳本排序,感興趣的可以了解一下2023-01-01