本周接到一个任务:定时统计订单表中的数据,将异常订单挑出来,放入ES中供统计页面从总数点击跳转过去进行列表展示。
一、配置ES
配置maven,注入template
@Resource
private ElasticsearchTemplate elasticsearchTemplate;
二、构建实体
其实就是实体类,一般是将业务实体中的部分字段写入ES。
构建IndexQuery(),设置ES的实体类,数据 类型 _doc、索引名
package org.springblade.chargingpile.es.data; import 
com.fasterxml.jackson.annotation.JsonFormat; import 
io.swagger.annotations.ApiModelProperty; import lombok.Data; 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; import 
java.io.Serializable; import java.util.Date; /** * 异常订单明细信息 * * @date 2022/11/9 
*/ @Data @Document(indexName = "charging_order_exception", type = "_doc") 
public class OrderExceptionES implements Serializable { 
@ApiModelProperty("订单编号") @Field(type = FieldType.Text) private Long id; 
@ApiModelProperty("充电桩编码") @Field(type = FieldType.Text) private String pileSn; 
@ApiModelProperty("充电枪id") @Field(type = FieldType.Text) private Long gunId; 
@ApiModelProperty("枪口") @Field(type = FieldType.Text) private Integer gunPort; 
@ApiModelProperty("结束时间") @Field(type = FieldType.Date, format = 
DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(shape = 
JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 
private Date endDate; @ApiModelProperty("城市代码") @Field(type = FieldType.Text) 
private Long cityCode; @ApiModelProperty("场站的id") @Field(type = FieldType.Text) 
private Long stationId; @ApiModelProperty("启动失败次数") @Field(type = 
FieldType.Text) private Integer isBootFailure; @ApiModelProperty("异常跳枪次数") 
@Field(type = FieldType.Text) private Integer isGunFailure; 
@ApiModelProperty("结束原因编码") @Field(type = FieldType.Text) private String 
endReason; @ApiModelProperty("开始时间") @Field(type = FieldType.Date, format = 
DateFormat.custom, pattern = "yyyy-MM-dd HH:mm:ss") @JsonFormat(shape = 
JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 
private Date startDate; } 
三、向ES写入数据
其实这里是两个步骤,ES可以用MySQL来类比,先创建索引(MySQL中的表)再写入数据。
如下方法可以将单个实体类数据写入ES
 @Resource private ElasticsearchTemplate elasticsearchTemplate; @Override 
public String saveChargingWarnDetailES(ChargingWarnDetailES 
chargingWarnDetailES) { //构建插入数据 IndexQuery indexQuery = new IndexQuery(); 
//插入的实体类 indexQuery.setObject(chargingWarnDetailES); //索引 
indexQuery.setIndexName(WarnConstants.WARN_ES_INDEX); //类型 
indexQuery.setType("_doc"); String index = StringUtils.EMPTY; try { // 保存数据 
index = elasticsearchTemplate.index(indexQuery); } catch (Exception e) { 
e.printStackTrace(); } return index; } 
四、从ES查询数据
这个步骤问题是比较多的,记录一下。
通过ES查询的字段有:充电场站ID、充电枪ID、时间范围、是否异常订单
同时需要根据时间,也就是ID倒序排列,因为ID是根据时间递增的。
1、构建QueryBuilder,这里用到的是BoolQueryBuilder
        
这个BoolQueryBuilder适用于这个场景,是最基本的查询类似于mysql的where条件,条件执行的时候只有true和false这两种结果。must 
就类似于 查询条件拼接的 and 字段。
        这里用到的ES时间范围查询,统计从开始到结束时间的订单。用到了rangeQuery("要查询的字段").from("开始时间").to("结束时间”),需要注意的是,这里的要查询的字段要加后缀.keyword,不然查询不出来,时间范围格式和存入时对应,可以用string,因为实体类日期字段标注了格式的
2、构建SearchSourceBuilder
       这里用到的场景是分页、排序。
        
ES的查询分页网上主要有三种方法,主要有from..size的浅分页,滑动分页Scroll等。我这里用到的是最简单的浅分页。from参数传入查询数据截取的开始范围,传入前端传过来的(页号-1)*页大小。from 
+ 
size数值不能超过10000,且是ES查询全部数据再截取得到的效率差了一点点,浅分页就是有这些缺陷。分页要设置searchSourceBuilder.trackTotalHits(true);这样在searchResponse可以通过getTotalHits()得到总的数据量条数。
3、构建SearchRequest 
使用ActionFuture包装的SearchResponse接收返回结果,遍历里面的hit中的对象放入结果集
这里的包装,可以用actionGet()获取到与ES的查询请求结果,为成功再进行下一步。
最终代码如下:
 //构建BoolQueryBuilder 布尔条件查询 BoolQueryBuilder boolQueryBuilder = 
QueryBuilders.boolQuery(); if 
(!ObjectUtils.isEmpty(exceptionVO.getIsBootFailure())) { 
boolQueryBuilder.must(QueryBuilders.termsQuery("isBootFailure", new int[]{1})); 
} if (!ObjectUtils.isEmpty(exceptionVO.getIsGunFailure())) { 
boolQueryBuilder.must(QueryBuilders.termsQuery("isGunFailure", new int[]{1})); 
} if (!ObjectUtils.isEmpty(exceptionVO.getGunId())) { 
boolQueryBuilder.must(QueryBuilders.termsQuery("gunId", new 
Object[]{exceptionVO.getGunId()})); } if 
(!ObjectUtils.isEmpty(exceptionVO.getStart()) && 
!ObjectUtils.isEmpty(exceptionVO.getEnd())) { 
boolQueryBuilder.must(QueryBuilders.rangeQuery("endDate.keyword").from(exceptionVO.getStart() 
+ " 00:00:00").to(exceptionVO.getEnd() + " 23:59:59")); } 
//构建SearchSourceBuilder SearchSourceBuilder searchSourceBuilder = new 
SearchSourceBuilder(); searchSourceBuilder.trackTotalHits(true); if 
(!ObjectUtils.isEmpty(exceptionVO.getCurrent()) && 
!ObjectUtils.isEmpty(exceptionVO.getSize())) { 
searchSourceBuilder.from((exceptionVO.getCurrent() - 1) * 
exceptionVO.getSize()); searchSourceBuilder.size(exceptionVO.getSize()); } else 
{ searchSourceBuilder.from(0); searchSourceBuilder.size(9999); } 
searchSourceBuilder.sort("id", SortOrder.DESC); 
searchSourceBuilder.query(boolQueryBuilder); //构建SearchRequest SearchRequest 
searchRequest = new SearchRequest("charging_order_exception"); 
searchRequest.source(searchSourceBuilder); ActionFuture<SearchResponse> 
searchResponse = elasticsearchTemplate.getClient().search(searchRequest); 
List<OrderExceptionES> list = new LinkedList<>(); if 
(searchResponse.actionGet().status().getStatus() == RestStatus.OK.getStatus()) 
{ 
page.setTotal(Long.valueOf(String.valueOf(searchResponse.actionGet().getHits().getTotalHits()))); 
SearchHit[] searchHits = searchResponse.actionGet().getHits().getHits(); for 
(SearchHit searchHit : searchHits) { 
list.add(JSONObject.parseObject(searchHit.getSourceAsString(), 
OrderExceptionES.class)); } } 
五、其他工具
数据发到ES了,怎么查看。
笔者也是刚结束,下载了官网的kibana但是各种原因没法正常连上使用。
使用谷歌浏览器的插件看看还可以,有ElasticSearchHead
还有ElasticVue