引言
最近小编负责的一个语音质检 项目中用到了ES,下面结合实例代码分享一下java操作ES查用的查询写法。
关于es的基本操作,例如新建索引、查询封装类,请参考前面博客:【ElasticSearch实战】——封装java操作es基础架构
1、ES在项目中的位置

2、项目查询需求
从上面查询条件来看,其中包括了精确查询,模糊查询及时间范围查询等,这些查询 都会在下面 样例代码中给出,并且还有部分统计的写法,例如机器质检不合格的数量, 人工审核不合格的数量等。
3、查询代码
package com.jack.search.es.service;
import com.jack.common.constant.SearchConstants;
import com.jack.search.es.model.CaseCallCheckListQueryInfo;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.metrics.cardinality.Cardinality;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* @author zhenghao
* @description: 录音库查询
* @date 2019/10/1115:49
*/
@Service
public class CallCheckQueryService {
@Autowired
private QueryService queryService;
@Autowired
private ElasticSearchService elasticSearchService;
public Map<String, Object> getCallCheckList(CaseCallCheckListQueryInfo queryInfo) {
if (queryInfo == null) {
return null;
}
//构造查询条件
BoolQueryBuilder boolQueryBuilder = this.getCallCheckQueryBuilder(queryInfo);
//排序
String orderBy = queryInfo.getOrderBy();
if (StringUtils.isEmpty(orderBy)) {
orderBy = String.format("%s:%s", "telTime", "desc");
}
//分页
Integer pageNo = queryInfo.getPageNo();
if ((pageNo == null) || (pageNo <= 0)) {
pageNo = 0;
} else {
pageNo -= 1;
}
Integer pageSize = queryInfo.getPageSize();
if ((pageSize == null) || (pageSize < 1)) {
pageSize = 10;
}
//构造排序构造器FieldSortBuilder,设置排序参数
String[] orderStr = orderBy.split(":");
FieldSortBuilder sort = SortBuilders.fieldSort(orderStr[0]).order("desc".equalsIgnoreCase(orderStr[1])? SortOrder.DESC:SortOrder.ASC);
//AggregationBuilder 相当于 mysql中的 group by
//第一级机器质检不合格数据聚合 聚合名称为 hasError ,聚合数据条件为 字段 hasError>=1
FilterAggregationBuilder hasErrorAggregationBuilder = AggregationBuilders.filter("hasError", QueryBuilders.rangeQuery("hasError").gte(1));
//构造第二级子聚合 每一个质检项的值 >=1 注意:每一个checkItem 是一个字段,代表一个质检项 0代表没有命中该质检项,大于0代表表中
for (int i = SearchConstants.CHECK_ITEM_MIN; i<= SearchConstants.CHECK_ITEM_MAX; i++) {
String checkItemName = String.format("checkItem%d", i);
hasErrorAggregationBuilder.subAggregation(AggregationBuilders.filter(checkItemName, QueryBuilders.rangeQuery(checkItemName).gte(1)));
}
//第一级人工审核不合格的数据聚合
FilterAggregationBuilder auditHasErrorAggregationBuilder = AggregationBuilders.filter("auditHasError", QueryBuilders.rangeQuery("auditHasError").gte(1));
//整合查询条件,相当于组长sql cardinality 表示去重
FilterAggregationBuilder allCheckAggregationBuilder = AggregationBuilders.filter("allCheck", boolQueryBuilder)
.subAggregation(hasErrorAggregationBuilder)
.subAggregation(auditHasErrorAggregationBuilder)
.subAggregation(AggregationBuilders.sum("totalTelLength").field("telLength"))
.subAggregation(AggregationBuilders.cardinality("userId").field("userId"));
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
searchSourceBuilder.query(boolQueryBuilder).sort(sort).from(pageNo*pageSize).size(pageSize).aggregation(allCheckAggregationBuilder);
//执行查询
SearchRequest searchRequest = new SearchRequest();
searchRequest.indices(SearchConstants.CALL_INDEX_NAME).types(SearchConstants.CALL_INDEX_TYPE).source(searchSourceBuilder);
SearchResponse searchResponse = elasticSearchService.search(searchRequest);
if (searchResponse == null) {
return null;
}
//从查询结果中获得想要数据
SearchHits searchHits = searchResponse.getHits();
//获得查询结果条数
long total = searchHits.getTotalHits();
Map<String, Object> resultMap = new HashMap<>(10);
resultMap.put("total", total);
resultMap.put("tookInMillis", searchResponse.getTook().getMillis());
//获得查询结果并转换为map
if (total > 0) {
SearchHit[] searchHitsArr = searchHits.getHits();
List<Map<String, Object>> resultMapList = new ArrayList<>(searchHitsArr.length);
for (int i = 0; i < searchHitsArr.length; i++) {
Map<String, Object> map = searchHitsArr[i].getSourceAsMap();
resultMapList.add(map);
}
resultMap.put("list", resultMapList);
}
//获得聚合桶数据
Filter allCheckFilter = searchResponse.getAggregations().get("allCheck");
Aggregations allCheckAggregations = allCheckFilter.getAggregations();
//通话总时长
Sum sum = allCheckAggregations.get("totalTelLength");
Cardinality userIdCardinality = allCheckAggregations.get("userId");
//机器审核错误的数量
Filter hasErrorFilter = allCheckAggregations.get("hasError");
Aggregations hasErrorAggregations = hasErrorFilter.getAggregations();
//人工审核错误的数量
Filter auditHasErrorFilter = allCheckAggregations.get("auditHasError");
long errorCount = hasErrorFilter.getDocCount();
long auditErrorCount = auditHasErrorFilter.getDocCount();
resultMap.put("errorCount", errorCount);
resultMap.put("auditErrorCount", auditErrorCount);
resultMap.put("goodRate", total>0?1.0*(total-errorCount)/total:0);
resultMap.put("auditGoodRate", total>0?1.0*(total-auditErrorCount)/total:0);
resultMap.put("totalTelLength", sum.getValue());
resultMap.put("averageTelLength", total>0?sum.getValue()/total:0);
resultMap.put("userCount", userIdCardinality.getValue());
for (int k = SearchConstants.CHECK_ITEM_MIN; k<= SearchConstants.CHECK_ITEM_MAX; k++) {
Filter checkItemFilter = hasErrorAggregations.get(String.format("checkItem%d", k));
resultMap.put(String.format("checkItem%dCount", k), checkItemFilter.getDocCount());
}
return resultMap;
}
/**
* @Description: 构造查询条件
* @author: zhenghao
* @date: 2019/10/11 15:54
*/
private BoolQueryBuilder getCallCheckQueryBuilder(CaseCallCheckListQueryInfo queryInfo) {
/**
* BoolQueryBuilder 是es提供的一个查询接口,可以对其进行参数设置完成对应的查询
*/
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder();
//根据主键id查询
Long[] callRecordIds = queryInfo.getCallRecordIds();
if ((callRecordIds != null) && (callRecordIds.length > 0)) {
String[] strCallRecordIds = new String[callRecordIds.length];
for (int i = 0; i < callRecordIds.length; i++) {
strCallRecordIds[i] = String.valueOf(callRecordIds[i]);
}
//idsQuery查询多个id 相当于mysql中的 where id in(1,2,3)
//filter必须匹配,但他以不评分、过滤模式来进行,这些语句对评分没有贡献,只是根据过滤标准来排除或包含文档
boolQueryBuilder.filter(QueryBuilders.idsQuery().addIds(strCallRecordIds));
}
//根据caseId精确查询 termQuery 完全匹配
Long caseId = queryInfo.getCaseId();
if (caseId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("caseId", caseId));
}
//termsQuery 一次匹配多个值,查询多个公司的数据
Long[] partnerIds = queryInfo.getPartnerIds();
if ((partnerIds != null) && (partnerIds.length > 0)) {
long[] pids = new long[partnerIds.length];
for (int i = 0; i < pids.length; i++) {
pids[i] = partnerIds[i];
}
boolQueryBuilder.filter(QueryBuilders.termsQuery("partnerId", pids));
}
//注意在es中是long类型 非包装类型Long
Long[] departmentIds = queryInfo.getDepartmentIds();
if ((departmentIds != null) && (departmentIds.length > 0)) {
long[] dids = new long[departmentIds.length];
for (int i = 0; i < dids.length; i++) {
dids[i] = departmentIds[i];
}
boolQueryBuilder.filter(QueryBuilders.termsQuery("departmentId", dids));
}
//根据web端传递的参数不同,区分对应的userId不同的值
Integer allotState = queryInfo.getAllotState();
if (allotState != null) {
if (allotState == 0) {
//精确查询
boolQueryBuilder.filter(QueryBuilders.termQuery("userId", -1));
} else {
Long userId = queryInfo.getUserId();
if (userId != null) {
//精确查询
boolQueryBuilder.filter(QueryBuilders.termQuery("userId", userId));
} else {
//范围查询 gt 代表大于
boolQueryBuilder.filter(QueryBuilders.rangeQuery("userId").gt(0));
}
}
} else {
Long userId = queryInfo.getUserId();
if (userId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("userId", userId));
} else {
Integer auditHasError = queryInfo.getAuditHasError();
// 查询已经分配质检用户的质检列表
if ((auditHasError != null) && (auditHasError == -1)) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("userId").gt(0));
}
}
}
//将string类型的字段值 去掉*匹配符及空格
String userName = queryService.trimWildcardQuery(queryInfo.getUserName());
if (!StringUtils.isEmpty(userName)) {
//精确查询
boolQueryBuilder.filter(QueryBuilders.termQuery("userName", userName));
}
Long auditUserId = queryInfo.getAuditUserId();
if (auditUserId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("auditUserId", auditUserId));
}
String auditUserName = queryService.trimWildcardQuery(queryInfo.getAuditUserName());
if (!StringUtils.isEmpty(auditUserName)) {
boolQueryBuilder.filter(QueryBuilders.termQuery("auditUserName", auditUserName));
}
Long clientId = queryInfo.getClientId();
if (clientId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("clientId", clientId));
}
Long batchId = queryInfo.getBatchId();
if (batchId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("batchId", batchId));
}
String caseCode = queryService.trimWildcardQuery(queryInfo.getCaseCode());
if (caseCode != null) {
//wildcardQuery模糊查询,相当于mysql中的like
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("caseCode", String.format("*%s*", caseCode)));
}
String borrowerName = queryService.trimWildcardQuery(queryInfo.getBorrowerName());
if (!StringUtils.isEmpty(borrowerName)) {
//wildcardQuery模糊查询,相当于mysql中的like
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("borrowerName", String.format("*%s*", borrowerName)));
}
String contactName = queryService.trimWildcardQuery(queryInfo.getContactName());
if (!StringUtils.isEmpty(contactName)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("contactName", String.format("*%s*", contactName)));
}
String contactTel = queryService.trimWildcardQuery(queryInfo.getContactTel());
if (!StringUtils.isEmpty(contactTel)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("contactTel", String.format("*%s*", contactTel)));
}
String fileName = queryService.trimWildcardQuery(queryInfo.getFileName());
if (!StringUtils.isEmpty(fileName)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("fileName", String.format("*%s*", fileName)));
}
//常见需求范围查询 查询某个时间段范围内的数据
Long telTimeMin = queryInfo.getTelTimeMin();
Long telTimeMax = queryInfo.getTelTimeMax();
if ((telTimeMin != null) || (telTimeMax != null)) {
//获得范围查询builder
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("telTime");
if (telTimeMin != null) {
//gte 代表大于等于
rangeQueryBuilder.gte(telTimeMin);
}
if (telTimeMax != null) {
//lt 代表小于某个值 lte代表小于等于某个值
rangeQueryBuilder.lt(telTimeMax);
}
boolQueryBuilder.filter(rangeQueryBuilder);
}
//查询某个时间段范围内的数据
Long telMillSecMin = queryInfo.getTelMillSecMin();
Long telMillSecMax = queryInfo.getTelMillSecMax();
if ((telMillSecMin != null) || telMillSecMax != null) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("telMillSec");
if (telMillSecMin != null) {
rangeQueryBuilder.gte(telMillSecMin);
}
if (telMillSecMax != null) {
rangeQueryBuilder.lt(telMillSecMax);
}
}
//时间范围查询
Long auditTimeMin = queryInfo.getAuditTimeMin();
Long auditTimeMax = queryInfo.getAuditTimeMax();
if ((auditTimeMin != null) || (auditTimeMax != null)) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("auditTime");
if (auditTimeMin != null) {
rangeQueryBuilder.gte(auditTimeMin);
}
if (auditTimeMax != null) {
rangeQueryBuilder.lt(auditTimeMax);
}
boolQueryBuilder.filter(rangeQueryBuilder);
}
String contactRelationName = queryService.trimWildcardQuery(queryInfo.getContactRelationName());
if (!StringUtils.isEmpty(contactRelationName)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("contactRelationName", String.format("*%s*", contactRelationName)));
}
String telNumber = queryService.trimWildcardQuery(queryInfo.getTelNumber());
if (!StringUtils.isEmpty(telNumber)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("telNumber", String.format("*%s*", telNumber)));
}
Integer hasError = queryInfo.getHasError();
if (hasError == null) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("hasError").gte(-1));
} else {
if (hasError >= 0) {
boolQueryBuilder.filter(QueryBuilders.termQuery("hasError", hasError));
} else {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("hasError").gte(0));
}
}
Integer auditHasError = queryInfo.getAuditHasError();
if (auditHasError == null) {
boolQueryBuilder.filter(QueryBuilders.rangeQuery("auditHasError").gte(-1));
} else if (auditHasError >= -1) {
boolQueryBuilder.filter(QueryBuilders.termQuery("auditHasError", auditHasError));
}
String auditRemark = queryService.trimWildcardQuery(queryInfo.getAuditRemark());
if (!StringUtils.isEmpty(contactName)) {
boolQueryBuilder.filter(QueryBuilders.wildcardQuery("auditRemark", String.format("*%s*", auditRemark)));
}
Long[] recheckDepartmentIds = queryInfo.getRecheckDepartmentIds();
if ((recheckDepartmentIds != null) && (recheckDepartmentIds.length > 0)) {
long[] rdids = new long[recheckDepartmentIds.length];
for (int i = 0; i < rdids.length; i++) {
rdids[i] = recheckDepartmentIds[i];
}
boolQueryBuilder.filter(QueryBuilders.termsQuery("recheckDepartmentId", rdids));
}
//根据数据记录中是否存在某个字段进行查询
Long recheckUserId = queryInfo.getRecheckUserId();
if (recheckUserId != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("recheckUserId", recheckUserId));
} else {
Integer allotRecheckState = queryInfo.getAllotRecheckState();
if (allotRecheckState != null) {
if (allotRecheckState == 0) {
//mustNot 档必须不匹配这些条件才能被包含进来,existsQuery 存在指定字段
BoolQueryBuilder recheckUserIdQueryBuilder = new BoolQueryBuilder();
//本条件是:返回不包含recheckUserId的字段的数据记录
recheckUserIdQueryBuilder.mustNot(QueryBuilders.existsQuery("recheckUserId"));
boolQueryBuilder.filter(recheckUserIdQueryBuilder);
} else {
//本条件是:返回包含recheckUserId 这个字段的数据记录
boolQueryBuilder.filter(QueryBuilders.existsQuery("recheckUserId"));
}
}
Integer recheckHasError = queryInfo.getRecheckHasError();
if (recheckHasError != null) {
boolQueryBuilder.filter(QueryBuilders.termQuery("recheckHasError", recheckHasError));
} else {
Integer hasRecheck = queryInfo.getHasRecheck();
if (hasRecheck != null) {
if (hasRecheck == -1) {
boolQueryBuilder.filter(QueryBuilders.existsQuery("recheckUserId"));
} else if (hasRecheck == 0) {
//和上面不同的写法
boolQueryBuilder.mustNot(QueryBuilders.existsQuery("recheckHasError"));
} else {
boolQueryBuilder.filter(QueryBuilders.existsQuery("recheckHasError"));
}
}
}
Long recheckTimeMin = queryInfo.getRecheckTimeMin();
Long recheckTimeMax = queryInfo.getRecheckTimeMax();
if ((recheckTimeMin != null) || (recheckTimeMax != null)) {
RangeQueryBuilder rangeQueryBuilder = QueryBuilders.rangeQuery("recheckTime");
if (recheckTimeMin != null) {
rangeQueryBuilder.gte(recheckTimeMin);
}
if (recheckTimeMax != null) {
rangeQueryBuilder.lt(recheckTimeMax);
}
boolQueryBuilder.filter(rangeQueryBuilder);
}
}
return boolQueryBuilder;
}
}
小编在项目中将代码做了详细的 注释,通过注释可以看到所有的写法。
如果 本项目对您有帮助,记得给 星星。本项目后续会继续完善java对ES的操作,包括各种复杂查询和统计。
本文介绍了在语音质检项目中,如何使用Java进行Elasticsearch的基本查询,包括精确查询、模糊查询和时间范围查询的实现。同时,文章提供了统计机器和人工质检不合格数量的代码示例,并鼓励读者关注项目以获取更多关于Java操作ES的高级查询和统计方法。
6412

被折叠的 条评论
为什么被折叠?



