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();

  1. 创建实例‌:SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
  2. 设置查询条件‌:用sourceBuilder.query(QueryBuilders.matchQuery("字段", "值"))sourceBuilder.query(QueryBuilders.matchAllQuery())来指定查什么。
  3. 分页控制‌:sourceBuilder.from(起始位置)sourceBuilder.size(每页条数),from默认0,size默认10。
  4. 排序‌:sourceBuilder.sort("字段名", SortOrder.ASC)可添加多个sort实现多级排序。
  5. 返回字段筛选‌:sourceBuilder.fetchSource(new String{"字段1", "字段2"}, null)只返回指定字段。‌‌‌
BoolQueryBuilder

/** 用于构建复杂布尔逻辑查询的核心类,通过组合mustshouldmust_notfilter子句实现多条件精准检索 */

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; }