ES操作类
EsClient.java
public class EsClient { /** * 用集群名字,集群节点地址构建es client * 保证单例,不要new 多个client */ public TransportClient client; /** * 批量处理客户端 */ public BulkProcessor bulkProcessor; /** * 每个集群都有一个固定的集群名, * 不是随便指定的,jiesi-1是测试环境的测试集群 * (通过配置文件传输进来 因为和线上的不一样) */ @Value("${es.cluster.name}") private String clusterName; /** * 要连接的ES节点的地址, * 端口是tcp端口 支持多个ip,port, * 以逗号和分号分隔。 * 格式 "ip:port,ip:port,ip:port" * 输入示例 "192.168.200.190:9203,192.168.200.191:9203" */ @Value("${es.connection.address}") private String connectionAddress; @Value("${es.connection.user}") private String connectionUser; @Value("${es.connection.pwd}") private String connectionPwd; @Value("${es.connection.processors}") private Integer processors; private final String SECURITY_KEY = "request.headers.Authorization";//固定值 @PostConstruct public void init() throws UnknownHostException { //初始化失败 服务不应该能够启动 getClient(); log.info("init es!!!"); bulkProcessor = getBulkClient(); } @PreDestroy public void destroy() { //初始化失败 服务不应该能够启动 client.close(); log.info("close es!!!"); bulkProcessor.close(); } /** * 创建ES客户端,请自己保证单例,不要new多个客户端 * * @return */ private void getClient() throws UnknownHostException { if (clusterName == null || clusterName.isEmpty() || connectionAddress.isEmpty()) { throw new RuntimeException("集群名,连接地址没有设置"); } //设置集群的名字 Settings settings = Settings.builder() .put("cluster.name", clusterName) .put("client.transport.sniff", false) .put("processors", processors) .put(SECURITY_KEY, basicAuthHeaderValue(connectionUser, connectionPwd)) .build(); log.info("clusterName={},sniff={},SECURITY_KEY={},user={},p_w_d={},auth={}", clusterName, false, SECURITY_KEY, connectionUser, connectionPwd, basicAuthHeaderValue(connectionUser, connectionPwd)); //创建集群client并添加集群节点地址,可以addTransportAddress()多个ip和端口,增加连接的稳定性。 client = new PreBuiltTransportClient(settings); String[] ipPortArr = connectionAddress.split(",");//逗号分隔 for (String ipPort : ipPortArr) { String[] ip_port = ipPort.split(":");//冒号分隔 if (ip_port.length == 2) { client.addTransportAddress(new TransportAddress(InetAddress.getByName(ip_port[0]), Integer.parseInt(ip_port[1]))); } } } /** * 获取批量的客户端 * * @return 批量处理客户端 */ private BulkProcessor getBulkClient() { BulkProcessor processor = BulkProcessor.builder(client, new BulkProcessor.Listener() { @Override public void beforeBulk(long executionId, BulkRequest bulkRequest) { log.info("序号:{} 开始执行{} 条记录", executionId, bulkRequest.numberOfActions()); } @Override public void afterBulk(long executionId, BulkRequest bulkRequest, BulkResponse bulkResponse) { log.info("序号:{} 执行{}条记录成功,耗时:{}毫秒,", executionId, bulkRequest.numberOfActions(), bulkResponse.getIngestTookInMillis()); } @Override public void afterBulk(long executionId, BulkRequest bulkRequest, Throwable throwable) { log.error(String.format("序号:%s 执行失败; 总记录数:%s", executionId, bulkRequest.numberOfActions()), throwable); } }).setBulkActions(1000) .setBulkSize(new ByteSizeValue(10, ByteSizeUnit.MB)) .setConcurrentRequests(4) .setFlushInterval(TimeValue.timeValueSeconds(5)) .setBackoffPolicy(BackoffPolicy.exponentialBackoff(TimeValue.timeValueMillis(500), 3)) //失败后等待多久及重试次数 .build(); return processor; } /*------------------------------------增---------------------------------------------*/ /** * 用java字符串创建document 不指定文档ID (已测试没有问题) 性能比自己指定id性能要好 属性不支持bigdecimal */ public void createWithStr(String indexName, String typeName, Object createObj) { createOne(indexName, typeName, createObj,WriteRequest.RefreshPolicy.NONE); } public void createWithStr(String indexName, String typeName, Object createObj, WriteRequest.RefreshPolicy policy) { createOne(indexName, typeName, createObj, policy); } public void createOne(String indexName, String typeName, Object createObj, WriteRequest.RefreshPolicy policy) { if (createObj == null) { return; } Map<String, Object> paramMap = objectToMap(createObj); //指定索引名称,type名称和documentId(documentId可选,不设置则系统自动生成)创建document IndexResponse response = client.prepareIndex(indexName, typeName) .setSource(paramMap) .setRefreshPolicy(policy) .execute() .actionGet(); if (response == null) { log.error("插入数据到es异常!response为空!content={}", JSON.toJSONString(createObj)); } else { log.debug("插入数据到es成功!content={},resultId={}", JSON.toJSONString(createObj), response.getId()); } } /** * 用java字符串创建document 指定文档id (未经过测试 但是应该没啥大问题 ..) */ public void createWithStrAndId(String indexName, String typeName, String docId, Object createObj) { if (createObj == null) { return; } Map<String, Object> paramMap = objectToMap(createObj); //指定索引名称,type名称和documentId(documentId可选,不设置则系统自动生成)创建document IndexResponse response = client.prepareIndex(indexName, typeName, docId) .setSource(paramMap) .execute() .actionGet(); if (response == null) { log.error("插入数据到es异常!response为空!content={}", JSON.toJSONString(createObj)); } else { log.debug("插入数据到es成功!content={},resultId={}", JSON.toJSONString(createObj), response.getId()); } } /** * 批量创建文档 */ public void createWithStrByBatch(String indexName, String typeName, List<?> objs) { if (CollectionUtils.isEmpty(objs)) { return; } for (Object object : objs) { String json = JSONObject.toJSONString(object); bulkProcessor.add(new IndexRequest(indexName, typeName).source(json, XContentType.JSON)); } bulkProcessor.flush(); } public void updateWithStrByBatch(String indexName,String typeName,List<String> ids,List<?> objs){ if(CollectionUtils.isEmpty(objs)){ return ; } if(CollectionUtils.isEmpty(ids)){ return ; } if(ids.size() != objs.size()){ return ; } //先查询出来 for(int i = 0 ; i<ids.size(); i++) { String id = ids.get(i); String json = JSONObject.toJSONString(objs.get(i)); bulkProcessor.add(new UpdateRequest(indexName,typeName,id).doc(json,XContentType.JSON)); } bulkProcessor.flush(); } /*------------------------------------删---------------------------------------------*/ /*------------------------------------改(es不建议有过多的修改)---------------------------------------------*/ public void updateWithStrAndId(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject){ updateOneWithPolicy(indexName, typeName, queryBuilder, updateObject,WriteRequest.RefreshPolicy.NONE); } public void updateWithStrAndIdPolicy(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject,WriteRequest.RefreshPolicy policy){ updateOneWithPolicy(indexName, typeName, queryBuilder, updateObject,policy); } //如果需要配置刷新策略 调用此方法 public void updateOneWithPolicy(String indexName, String typeName, QueryBuilder queryBuilder, Object updateObject, WriteRequest.RefreshPolicy policy) { if (updateObject == null) { return; } //先查询出来 SearchResponse sResponse = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder).get(); SearchHit[] searchHits = sResponse.getHits().getHits(); if (searchHits != null && searchHits.length > 0) { String id = searchHits[0].getId(); //在更新 Map<String, Object> paramMap = objectToMap(updateObject); UpdateRequestBuilder urb = client.prepareUpdate(indexName, typeName, id); urb.setRefreshPolicy(policy); urb.setDoc(paramMap); urb.execute().actionGet(); log.debug("update succeed, index: [{}], typeName: [{}], queryBuilder: [{}]", indexName, typeName, JSON.toJSONString(queryBuilder)); } else { log.warn("update failed, query condition matched no result, index: [{}], typeName: [{}], queryBuilder: [{}]", indexName, typeName, JSON.toJSONString(queryBuilder)); } } /** * 根据查询条件更新多个结果 * @param indexName * @param typeName * @param queryBuilder * @param updateObject */ public void updateWithStrAndIds(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject) { updateListWithPolicy(indexName, typeName, queryBuilder, updateObject, WriteRequest.RefreshPolicy.NONE, false); } public void updateWithStrAndIds(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject, WriteRequest.RefreshPolicy policy) { updateListWithPolicy(indexName, typeName, queryBuilder, updateObject, policy, false); } public void updateWithStrAndIds(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject, WriteRequest.RefreshPolicy policy, boolean loop) { updateListWithPolicy(indexName, typeName, queryBuilder, updateObject, policy, loop); } public void updateWithStrAndIds(String indexName,String typeName,QueryBuilder queryBuilder,Object updateObject, boolean loop) { updateListWithPolicy(indexName, typeName, queryBuilder, updateObject, WriteRequest.RefreshPolicy.NONE, loop); } //如果需要配置刷新策略 调用此方法 public void updateListWithPolicy(String indexName, String typeName, QueryBuilder queryBuilder, Object updateObject, WriteRequest.RefreshPolicy policy, boolean loop) { if (updateObject == null) { return; } SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder); if(loop) { searchRequestBuilder.setSize(1); } else { searchRequestBuilder.setSize(5000); } //先查询出来 SearchResponse sResponse = searchRequestBuilder.get(); SearchHit[] searchHits = sResponse.getHits().getHits(); if(searchHits != null && searchHits.length > 0) { if(loop) { long total = sResponse.getHits().getTotalHits(); List<String> docIdList = this.queryDocIdListByCondition(indexName, typeName, queryBuilder, Long.valueOf(total).intValue(), 0); docIdList.stream().distinct().parallel().forEach(docId -> { this.updateListWithDocIdList(indexName, typeName, new ArrayList<>(Arrays.asList(docId)), updateObject, policy); }); } else { this.updateListWithDocIdList(indexName, typeName, Arrays.stream(searchHits).map(SearchHit::getId).collect(Collectors.toList()), updateObject, policy); } } else { log.warn("update failed, query condition matched no result, index: [{}], typeName: [{}]", indexName, typeName); } } public List<String> queryDocIdListByCondition(String indexName, String typeName, QueryBuilder queryBuilder, Integer size, Integer from) { SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder); if(size != null) { searchRequestBuilder.setSize(size); } else { searchRequestBuilder.setSize(5000); } if(from != null) { searchRequestBuilder.setFrom(from); } //先查询出来 SearchResponse sResponse = searchRequestBuilder.get(); SearchHit[] searchHits = sResponse.getHits().getHits(); List<String> docIdList = new ArrayList<>(); if(searchHits != null && searchHits.length > 0) { docIdList = Arrays.stream(searchHits).map(SearchHit::getId).collect(Collectors.toList()); } return docIdList; } public void updateListWithDocIdList(String indexName, String typeName, List<String> docIdList, Object updateObject, WriteRequest.RefreshPolicy policy) { for(String id : docIdList) { //在更新 Map<String, Object> paramMap = objectToMap(updateObject); UpdateRequestBuilder urb= client.prepareUpdate(indexName, typeName, id); urb.setDoc(paramMap); urb.setRefreshPolicy(policy); try { urb.execute().actionGet(); log.debug("update succeed, index: [{}], typeName: [{}], id: [{}], paramMap: [{}]", indexName, typeName, id, JSONObject.toJSONString(paramMap)); } catch (VersionConflictEngineException versionConflictEngineException) { log.warn("update failed, version conflicts, index: [{}], typeName: [{}], id: [{}]", indexName, typeName); } } } /*------------------------------------查---------------------------------------------*/ /** * 根据条件进行查询 * * @param indexName 索引名 * @param typeName 类型名 * @param queryBuilder 查询条件 * @param resultClass 查询对象类型 用于封装返回参数 (主要是因为返回对象可以通用封装 不用单独分开写) */ public <T> List<T> queryByCondition(String indexName, String typeName, QueryBuilder queryBuilder, Class<T> resultClass) { return queryByConditionWithSort(indexName, typeName, queryBuilder, resultClass,null, null); } public <T> List<T> queryByCondition(String indexName, String typeName, QueryBuilder queryBuilder, Class<T> resultClass, SortBuilder sortBuilder) { return queryByConditionWithSort(indexName, typeName, queryBuilder, resultClass,sortBuilder, null); } public <T> List<T> queryByCondition(String indexName, String typeName, QueryBuilder queryBuilder, Class<T> resultClass, CollapseBuilder collapseBuilder) { return queryByConditionWithSort(indexName, typeName, queryBuilder, resultClass,null, collapseBuilder); } public <T> List<T> queryByConditionWithSort(String indexName, String typeName, QueryBuilder queryBuilder, Class<T> resultClass,SortBuilder sortBuilder, CollapseBuilder collapseBuilder) { SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder) .setFrom(0).setSize(5000); if (sortBuilder != null){ searchRequestBuilder.addSort(sortBuilder).get(); } if (collapseBuilder != null) { searchRequestBuilder.setCollapse(collapseBuilder); } SearchResponse sResponse = searchRequestBuilder.get(); List<T> list = new ArrayList<T>(); if (sResponse == null || sResponse.getHits() == null) { log.error("查询数据from es异常!response为空!typeName={},queryBuilder", typeName, JSON.toJSONString(queryBuilder)); return list; } //对结果进行抽取 for (SearchHit hit : sResponse.getHits().getHits()) { String sourceAsString = hit.getSourceAsString(); T t = JSON.parseObject(sourceAsString, resultClass); list.add(t); } log.debug("查询数据from es成功!typeName={},resultSize={}", typeName, list.size()); return list; } /** * 根据条件进行查询 返回id列表 * * @param indexName 索引名 * @param typeName 类型名 * @param queryBuilder 查询条件 */ public <T> List<EsIdObj<T>> queryIdByCondition(String indexName, String typeName, QueryBuilder queryBuilder, Class<T> resultClass) { SearchResponse sResponse = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder).get(); List<EsIdObj<T>> list = new ArrayList<>(); if (sResponse == null || sResponse.getHits() == null) { log.error("查询数据from es异常!response为空!typeName={},queryBuilder", typeName, JSON.toJSONString(queryBuilder)); return list; } //对结果进行抽取 for (SearchHit hit : sResponse.getHits().getHits()) { String id = hit.getId(); String sourceAsString = hit.getSourceAsString(); T t = JSON.parseObject(sourceAsString, resultClass); EsIdObj<T> tEsIdObj = new EsIdObj<>(); tEsIdObj.setId(id); tEsIdObj.setObj(t); list.add(tEsIdObj); } log.debug("查询数据from es成功!typeName={},resultSize={}", typeName, list.size()); return list; } /** * * 根据条件进行查询 * * @param indexName 索引名 * * @param typeName 类型名 * * @param queryBuilder 查询条件 * * @param resultClass 查询对象类型 用于封装返回参数 (主要是因为返回对象可以通用封装 不用单独分开写) * */ public <T> PageInfo<T> queryPageByCondition(String indexName, String typeName, QueryBuilder queryBuilder, SortBuilder sortBuilder,PageParam pageParam, Class<T> resultClass) { PageInfo<T> pageInfo = new PageInfo<>(); long count = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder).addSort(sortBuilder).execute().actionGet().getHits().getTotalHits(); BigDecimal countBig = new BigDecimal(count); BigDecimal rowsBig = new BigDecimal(pageParam.getRows()); BigDecimal pagesBig = countBig.divide(rowsBig, 1, RoundingMode.HALF_UP); int pages = (int) Math.ceil(pagesBig.doubleValue()); pageInfo.setPages(pages); pageInfo.setPageNum(pageParam.getPage()); pageInfo.setTotal(count); int from = (pageParam.getPage() * pageParam.getRows()) - pageParam.getRows(); int size = pageParam.getRows() ; // if (from + size > 10000) {//from和size可以查询从哪里到哪里,但不能超过1万条 // from = 9990; // size = 10; // } log.debug("ES分页查询from{},size{}", from, size); SearchResponse sResponse = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder).addSort(sortBuilder).setFrom(from).setSize(size).get(); List<T> list = new ArrayList<>(); if (sResponse != null && sResponse.getHits() != null) { pageInfo.setPageSize(sResponse.getHits().getHits().length); //对结果进行抽取 for (SearchHit hit : sResponse.getHits().getHits()) { String sourceAsString = hit.getSourceAsString(); T t = JSON.parseObject(sourceAsString, resultClass); list.add(t); } }else{ log.debug("查询数据from es异常!response为空!typeName={},queryBuilder", typeName, JSON.toJSONString(queryBuilder)); } pageInfo.setList(list); log.debug("分页查询数据es成功!typeName={},resultSize={}", typeName, list.size()); return pageInfo; } /** * 传入查询 过滤 聚合 通用查询 * * @param searchRequestBuilder 查询过滤 * @param aggregationBuilder 聚合请求 * @return 查询结果 */ public SearchResponse commonSearch(SearchRequestBuilder searchRequestBuilder, AggregationBuilder aggregationBuilder) { return searchRequestBuilder.addAggregation(aggregationBuilder).execute().actionGet(); } public SearchResponse commonSearch(SearchRequestBuilder searchRequestBuilder) { return searchRequestBuilder.execute().actionGet(); } /** * * @param indexName 索引名 * @param typeName 类型名 * @param queryBuilder 过滤条件 * @param aggregationBuilders 聚合条件 * @return */ public SearchResponse aggregation(String indexName, String typeName, QueryBuilder queryBuilder, AggregationBuilder... aggregationBuilders) { SearchRequestBuilder searchRequestBuilder = client.prepareSearch(indexName).setTypes(typeName).setQuery(queryBuilder); if(aggregationBuilders != null && aggregationBuilders.length > 0) { for(AggregationBuilder aggregationBuilder : aggregationBuilders) { searchRequestBuilder.addAggregation(aggregationBuilder); } } SearchResponse sResponse = searchRequestBuilder.get(); if (sResponse == null || sResponse.getAggregations() == null){ log.error("search failed, index: {}, type: {}, queryBuilder: {}, aggregationBuilders: {}", indexName, typeName, JSON.toJSONString(queryBuilder), JSON.toJSONString(aggregationBuilders)); return null; } return sResponse; } private static Map<String, Object> objectToMap(Object obj) { Map<String, Object> map = new HashMap<String, Object>(); Class<?> clazz = obj.getClass(); for (Field field : clazz.getDeclaredFields()) { field.setAccessible(true); String fieldName = field.getName(); Object value = null; try { value = field.get(obj); if (value == null) { continue; } if (Date.class.isAssignableFrom(field.getType())) { value = ((Date) value).getTime(); } } catch (IllegalAccessException e) { //log.error("从对象中取出属性失败!obj={},fieldName={}", JSON.toJSONString(obj), fieldName); } map.put(fieldName, value); } return map; } /** * 基础的base64生成 * * @param username 用户名 * @param passwd 密码 * @return */ private static String basicAuthHeaderValue(String username, String passwd) { CharBuffer chars = CharBuffer.allocate(username.length() + passwd.length() + 1); byte[] charBytes = null; try { chars.put(username).put(':').put(passwd.toCharArray()); charBytes = toUtf8Bytes(chars.array()); String basicToken = Base64.getEncoder().encodeToString(charBytes); return "Basic " + basicToken; } finally { Arrays.fill(chars.array(), (char) 0); if (charBytes != null) { Arrays.fill(charBytes, (byte) 0); } } } public static byte[] toUtf8Bytes(char[] chars) { CharBuffer charBuffer = CharBuffer.wrap(chars); ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(charBuffer); byte[] bytes = Arrays.copyOfRange(byteBuffer.array(), byteBuffer.position(), byteBuffer.limit()); Arrays.fill(byteBuffer.array(), (byte) 0); return bytes; } }
业务使用类:
public class CfgNodeEventEsDaoImpl implements CfgNodeEventEsDao { @Resource private EsClient esClient; @Override public void insert(CfgNodeEvent cfgNodeEvent) { esClient.createWithStr( Constants.ES_IDX_IOT_FENCE_CFG_NODE_EVENT, Constants.ES_TYPE_IOT_FENCE_CFG_NODE_EVENT, cfgNodeEvent); } @Override public List<CfgNodeEvent> queryByCondition(CfgNodeEventBo cfgNodeEventBo) { BoolQueryBuilder boolQueryBuilder = convertParam(cfgNodeEventBo); List<CfgNodeEvent> list = esClient.queryByCondition(Constants.ES_IDX_IOT_FENCE_CFG_NODE_EVENT, Constants.ES_TYPE_IOT_FENCE_CFG_NODE_EVENT, boolQueryBuilder, CfgNodeEvent.class); return list; } /** * * 根据条件进行查询 * * @param indexName 索引名 * * @param typeName 类型名 * * @param queryBuilder 查询条件 * * @param resultClass 查询对象类型 用于封装返回参数 (主要是因为返回对象可以通用封装 不用单独分开写) * */ public <T> PageInfo<T> queryPageByCondition(String indexName, String typeName, CfgNodeEventBo cfgNodeEventQuery, PageParam pageParam, Class<T> resultClass) { PageInfo<T> pageInfo = new PageInfo<>(); BoolQueryBuilder queryBuilder = convertParam(cfgNodeEventQuery); SortBuilder sortBuilder = SortBuilders.fieldSort("eventTime").order(SortOrder.DESC); pageInfo=esClient.queryPageByCondition(indexName,typeName,queryBuilder,sortBuilder,pageParam,resultClass); return pageInfo; } /** * 组装查询参数 由于每个查询都不相同 所以单独抽取 类似于mapper中的where * * @param query 查询原始参数 * @return 适用于es的查询参数 */ private BoolQueryBuilder convertParam(CfgNodeEventBo query) { BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); if (StringUtils.isNotBlank(query.getNodeCode())) { boolQueryBuilder.must(QueryBuilders.termQuery("nodeCode", query.getNodeCode())); } if (StringUtils.isNotBlank(query.getNodeName())) { boolQueryBuilder.must(QueryBuilders.matchQuery("nodeName", query.getNodeName())); } if (query.getNodeType() != null) { boolQueryBuilder.must(QueryBuilders.termQuery("nodeType", query.getNodeType())); } if (StringUtils.isNotBlank(query.getGpsNo())) { boolQueryBuilder.must(QueryBuilders.termQuery("gpsNo", query.getGpsNo())); } if (StringUtils.isNotBlank(query.getGpsId())) { boolQueryBuilder.must(QueryBuilders.termQuery("gpsId", query.getGpsId())); } if (StringUtils.isNotBlank(query.getVehicleNumber())) { boolQueryBuilder.must(QueryBuilders.termQuery("vehicleNumber", query.getVehicleNumber())); } if (query.getEventType() != null) { boolQueryBuilder.must(QueryBuilders.termQuery("eventType", query.getEventType())); } if (query.getLat() != null) { boolQueryBuilder.must(QueryBuilders.termQuery("lat", query.getLat())); } if (query.getLng() != null) { boolQueryBuilder.must(QueryBuilders.termQuery("lng", query.getLng())); } if (query.getEventTime() != null) { boolQueryBuilder.must(QueryBuilders.termQuery("eventTime", DateUtil.format(query.getEventTime(),DateUtil.FORMAT_DATE_TIME))); } if (StringUtils.isNotBlank(query.getEventTimeStart())) { boolQueryBuilder.must(QueryBuilders.rangeQuery("eventTime").gte(query.getEventTimeStart()).format(DateUtil.FORMAT_DATE_TIME)); } if (StringUtils.isNotBlank(query.getEventTimeEnd())) { boolQueryBuilder.must(QueryBuilders.rangeQuery("eventTime").lte(query.getEventTimeEnd()).format(DateUtil.FORMAT_DATE_TIME)); } if (StringUtils.isNotBlank(query.getTenantCode())) { boolQueryBuilder.must(QueryBuilders.termQuery("tenantCode", query.getTenantCode())); } return boolQueryBuilder; } }