Elasticsearch使用
es数据的基础功能使用(为了配合7.1.1版本es使用)
一、客户端配置
ElasticsearchConfig使用 Spring Data ES 的RestClients创建RestHighLevelClient:
@Configuration
public class ElasticsearchConfig extends AbstractElasticsearchConfiguration {
@Bean
public RestHighLevelClient elasticsearchClient() {
return RestClients.create(ClientConfiguration.builder()
.connectedTo(uris) // "host:port"
.withConnectTimeout(Duration.ofSeconds(connectTimeout))
.withSocketTimeout(Duration.ofSeconds(socketTimeout))
.withBasicAuth(username, password)
.build()).rest();
}
}
二、构建查询
SearchRequest
/** 构建索引查询请求 */
SearchRequest searchRequest = new SearchRequest(searchFieldVo.getIndexName());
/**用来构建搜索请求体的核心工具类,它帮你把查询条件、分页、排序等参数组装 */
SearchSourceBuilder
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
- 创建实例:
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); - 设置查询条件:用
sourceBuilder.query(QueryBuilders.matchQuery("字段", "值"))或sourceBuilder.query(QueryBuilders.matchAllQuery())来指定查什么。 - 分页控制:
sourceBuilder.from(起始位置)和sourceBuilder.size(每页条数),from默认0,size默认10。 - 排序:
sourceBuilder.sort("字段名", SortOrder.ASC)可添加多个sort实现多级排序。 - 返回字段筛选:
sourceBuilder.fetchSource(new String{"字段1", "字段2"}, null)只返回指定字段。
BoolQueryBuilder
/** 用于构建复杂布尔逻辑查询的核心类,通过组合must、should、must_not、filter子句实现多条件精准检索 */
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
核心机制与子句语义
- must:逻辑“与”(AND),所有子句必须匹配,参与相关性评分。
- should:逻辑“或”(OR)倾向,默认非强制;若与
must共存则提升得分,若单独使用需配合minimumShouldMatch生效,参与评分。 - must_not:逻辑“非”(NOT),匹配该条件的文档被排除,不参与评分。
- filter:逻辑“与”(AND),强制过滤且零评分开销,支持缓存,适用于精确匹配或范围过滤 。
功能
支持 nested 嵌套数组字段查询(如 JSON 数组内的字段)
支持 term 精确匹配、fuzzy 模糊匹配、exists 存在、range 区间
使用 from/size 分页(适用于前 10000 条
支持的查询条件
boolQuery
├── must: nestedQuery(queryField → secField = secFieldValue) ← 嵌套字段匹配
├── must: termQuery(queryMapVoList[] 每个元素) ← 多字段精确 AND
├── must: fuzzyQuery(fuzzyField, fuzzyFieldValue) ← 模糊匹配
├── must: existsQuery(existField) ← 存在判断
├── must: rangeQuery(rangeField, filedValueStart, filedValueEnd) ← 区间
└── from/size 分页 + sortField 排序
三、案例
例:searchFieldVo为请求参数,用不同字段来组建复杂的查询条件
/** 设置区间查询 */ if (!StringUtils.isEmpty(searchFieldVo.getRangeField())) { boolQuery.must(addRangeQuery(searchFieldVo)); }addRangeQuery方法:
RangeQueryBuilder rangeQuery = QueryBuilders.rangeQuery(rangeField); if (valueStart != null) rangeQuery.gte(valueStart); if (valueEnd != null) rangeQuery.lte(valueEnd);
/** 集合内字段查询([{"A":"B"},{"A":"C"}])比如查询集合内A的值 */ if (!StringUtils.isEmpty(searchFieldVo.getQueryField())) { NestedQueryBuilder nestedQuery = QueryBuilders.nestedQuery( searchFieldVo.getQueryField(), QueryBuilders.matchQuery(searchFieldVo.getSecField(), searchFieldVo.getSecFieldValue()), ScoreMode.None ); boolQuery.must(nestedQuery); }/** 不存在某值(not in) */if (StrUtil.isNotBlank(searchFieldVo.getNotField()) && searchFieldVo.getNotValues() != null) { boolQuery.mustNot(QueryBuilders.termsQuery(searchFieldVo.getNotField(), searchFieldVo.getNotValues())); } if (CollectionUtil.isNotEmpty(searchFieldVo.getQueryMapVoList())) { for (QueryMapVo queryMapVo : searchFieldVo.getQueryMapVoList()) { if (queryMapVo.getField() != null) { boolQuery.must(QueryBuilders.termQuery(queryMapVo.getField(),queryMapVo.getFiledValue())); } } }/** 存在某值(in) */if (StrUtil.isNotBlank(searchFieldVo.getShouldField()) && searchFieldVo.getShouldValues() != null) { boolQuery.should(QueryBuilders.termsQuery(searchFieldVo.getShouldField(), searchFieldVo.getShouldValues())); boolQuery.minimumShouldMatch(1); }/** 将查询层层设置到searchRequest中 */
searchSourceBuilder.query(boolQuery); searchRequest.source(searchSourceBuilder);
/** 用客户端执行查询 */ SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);
四、其他
新建索引
/** * 新建索引 * @param index * @param id * @param jsonSource * @return */ public boolean indexDocument(String index, String id, String jsonSource) { boolean ackFlag = false; IndexRequest request = new IndexRequest(index) .id(id) .source(jsonSource, XContentType.JSON); try { IndexResponse response = client.index(request, RequestOptions.DEFAULT); ackFlag = response.status() == RestStatus.CREATED || response.status() == RestStatus.OK; } catch (IOException e) { e.printStackTrace(); } return ackFlag; }删除索引
/** * 删除索引 */ public boolean deleteIndex(String indexName) throws IOException { if (!indexExists(indexName)) { return false; } DeleteIndexRequest request = new DeleteIndexRequest(indexName); AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT); return response.isAcknowledged(); }添加文档
/** * 添加文档(使用默认_doc类型) */ public boolean addDocumentJson(String indexName, String id, String document) throws IOException { IndexRequest request = new IndexRequest(indexName); request.id(id); request.source(document, XContentType.JSON); client.index(request, RequestOptions.DEFAULT); return true; }删除文档
/** * 删除文档 */ public boolean deleteDocument(String indexName, String id) throws IOException { DeleteRequest request = new DeleteRequest(indexName, id); client.delete(request, RequestOptions.DEFAULT); return true; }更新文档
/** * 更新文档 */ public boolean updateDocument(String index, String id, String jsonSource) { boolean ackFLag = false; UpdateRequest request = new UpdateRequest(index, id) .doc(jsonSource, XContentType.JSON); try { UpdateResponse response = client.update(request, RequestOptions.DEFAULT); ackFLag = response.status() == RestStatus.CREATED || response.status() == RestStatus.OK; } catch (IOException e) { e.printStackTrace(); } return ackFLag; }根据id获取文档
/** * 根据ID获取文档 */ public Map<String, Object> getDocumentById(String indexName, String id) throws IOException { GetRequest request = new GetRequest(indexName, id); GetResponse response = client.get(request, RequestOptions.DEFAULT); if (response.isExists()) { return response.getSourceAsMap(); } return null; }解析搜索结果
/** * 解析搜索结果 * @param response 响应信息 * @return 查询数据 */ private List<Map<String, Object>> parseSearchResponse(SearchResponse response) { List<Map<String, Object>> resultList = new ArrayList<>(); log.info("查询到的数据总数量:{}", response.getHits().getTotalHits()); for (SearchHit hit : response.getHits().getHits()) { resultList.add(hit.getSourceAsMap()); } return resultList; }