网站开发西安中软,网上平台,淮南建设厅网站,wordpress菜单的功能es client api 升级
背景
公司项目从sring-boot2 升级到了spring-boot3 #xff0c;es的服务端也跟着升级到了es8 #xff0c;而es的客户端7和服务端8 是不兼容的#xff0c;
客户端es 7使用的是#xff1a; elasticsearch-rest-high-level-client
es 8 升级到#xf…es client api 升级
背景
公司项目从sring-boot2 升级到了spring-boot3 es的服务端也跟着升级到了es8 而es的客户端7和服务端8 是不兼容的
客户端es 7使用的是 elasticsearch-rest-high-level-client
es 8 升级到 elasticsearch-java
两者之间查询api的变化还是比较大的也花了不少时间在这个修改上所以记录下中间的切换姿势仅供大家参考
升级过程
依赖调整 !--es7 版本客户端 --
!-- dependency--
!-- groupIdcom.baibu.platform/groupId--
!-- artifactIdka-order-server-interface/artifactId--
!-- version7.1.0/version--
!-- /dependency--!--es8 版本客户端 --dependencygroupIdco.elastic.clients/groupIdartifactIdelasticsearch-java/artifactIdversion8.10.4/version/dependency查询api代码调整
参考官方文档 https://www.elastic.co/guide/en/elasticsearch/client/java-api-client/current/getting-started-java.html
创建client
Beanpublic ElasticsearchClient elasticsearchClient(ESProperties esProperties) {HttpHost[] httpHosts new HttpHost[esProperties.getNodes().size()];// 这里配置你的es服务端hostfor (int i 0; i esProperties.getNodes().size(); i) {ESProperties.Node node esProperties.getNodes().get(i);HttpHost httpHost new HttpHost(node.getHost(), node.getPort(), node.getScheme());httpHosts[i] httpHost;}// RestClient restClient RestClient.builder(httpHosts).setHttpClientConfigCallback(httpClientBuilder - {CredentialsProvider credentialsProvider new BasicCredentialsProvider();// 这里是设置服务端账户密码没有可以不用credentialsProvider.setCredentials(AuthScope.ANY,new UsernamePasswordCredentials(esProperties.getUsername(), esProperties.getPasswd()));httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);return httpClientBuilder;}).build();ElasticsearchTransport transport new RestClientTransport(restClient, new JacksonJsonpMapper());// And create the API clientElasticsearchClient elasticsearchClient new ElasticsearchClient(transport);return elasticsearchClient;}查询api // 构建boolquery
BoolQuery.Builder boolQueryBuilder QueryBuilders.bool()
// must wildcard 模糊查询
boolQueryBuilder.must(query - query.wildcard(t - t.field(wildcard).value(* 1111)));
// terms 多个值匹配ListString list ;boolQueryBuilder.must(query - query.terms(t - t.field(terms).terms(s - s.value(.stream().map(FieldValue::of).collect(Collectors.toList())))));
// term 匹配boolQueryBuilder.must(query - query.term(t - t.field(term).value(111)));// rang 范围 查询boolQueryBuilder.must(query - query.range(t - t.field(range).gte(JsonData.of(格式化的日期.replaceFirst( , T)))));
// nested 嵌套查询
boolQueryBuilder.must(query - query.nested(nestedQuery - nestedQuery.query(wildcardQuery - wildcardQuery.range(t - t.field(nested.wildcardQuery).gte(JsonData.of(格式化的日期.replaceFirst( , T))))).scoreMode(ChildScoreMode.None).path(nested)));SearchRequest searchRequest SearchRequest.of(s - s// 要查询的索引名.index(vo.getIndex())// 查询 条件.query(q - q.bool(boolQueryBuilder.build())// 分页).from((vo.getPageNum() - 1) * vo.getPageSize()).size(vo.getPageSize())// 排序字段 .sort(sorts.stream().map(sort - SortOptions.of(a - a.field(f - f.field(sort.getSortColumn()).order(sort.getSortType())))).collect(Collectors.toList()))// 查询结果包含哪些字段.source(source - source.filter(f - f.includes(Arrays.stream(vo.getInclude()).toList()).excludes()))); // 这里可以打印es查询 Query DSL 可以复制到es 控制台验证查询结果log.info(ES搜索引擎分页请求参数{}, searchRequest.toString());
// 获取查询结果 返回结果是一个map id是key
SearchResponseMap elasticsearchClient.search(searchRequest, Map.class)ListLong id searchResponse.hits().hits().stream().map(e - e.source().get(id)).collect(Collectors.toList());
当然你也可以参考官网的方式 一个Query 一个Query 的must个人觉得不是很方便
tring searchText bike;
double maxPrice 200.0;// Search by product name
Query byName MatchQuery.of(m - m .field(name).query(searchText)
)._toQuery(); // Search by max price
Query byMaxPrice RangeQuery.of(r - r.field(price).gte(JsonData.of(maxPrice))
)._toQuery();// Combine name and price queries to search the product index
SearchResponseProduct response esClient.search(s - s.index(products).query(q - q.bool(b - b .must(byName) .must(byMaxPrice))),Product.class
);// 获取查询结果
ListHitProduct hits response.hits().hits();
for (HitProduct hit: hits) {Product product hit.source();logger.info(Found product product.getSku() , score hit.score());
}聚合统计
// Aggregation 统计 terms 字段每个值和对应值的数量也可以统计avg 、interval、等
Aggregation aggregation AggregationBuilders.terms(terms - terms.field(terms));SearchRequest searchRequest SearchRequest.of(s - s.index(索引name))// 查询条件.query(q - q.bool(vo.getBoolQuery()))// 聚合条件 这里 aggregation 也可以通过lambda 自定义 a - a.histogram(h - h.field(price).interval(50.0)).aggregations(aggregations,aggregation));SearchResponse searchResponse elasticsearchClient.search(searchRequest, Map.class);
// 获取统计结果Aggregate terms (Aggregate) searchResponse.aggregations().get(aggregations);searchTypeList.lterms().buckets().array().forEach(e - {long quantity e.docCount();String key e.key()});
注解方式
上面的方式很繁琐每增加一个条件都需要我们手动设置条件查询语句我们可以通过在字段上加上自定义注解的方式 去生成对用的查询条件
主要逻辑如下 源码放在github 大家自取 https://github.com/Rfruelu/es-search-api-generator
/*** 查询模式*/
public enum EsQueryMode {TERM,TERMS,WILDCARD,RANGE,
}
/*** 通用转换** author LuTshoes* version 1.0*/
public class GeneralConvertHandler implements IConvertHandler {/*** 将注解和对象转换为BoolQuery** param annotation 注解* param o 对象* return 转换后的BoolQuery*/Overridepublic BoolQuery convert(Annotation annotation, Object o) {// 判断注解是否为GeneralConvert类型并且对象不为空if (annotation instanceof GeneralConvert Objects.nonNull(o)) {// 获取注解的key值String key ((GeneralConvert) annotation).key();// 获取注解的查询模式EsQueryMode mode ((GeneralConvert) annotation).mode();// 使用switch语句根据查询模式执行不同的逻辑switch (mode) {case TERM:// 如果查询模式是TERM则构建BoolQuery对象添加term查询条件return QueryBuilders.bool().must(t - t.term(f - f.field(key).value(FieldValue.of(JsonData.of(o))))).build();case TERMS:// 如果查询模式是TERMS并且对象是集合类型if (o instanceof Collection) {// 将对象转换为集合Collection? collection (Collection?) o;// 将集合中的每个元素转换为FieldValue对象并构建成列表ListFieldValue fieldValues collection.stream().map(c - FieldValue.of(JsonData.of(c))).collect(Collectors.toList());// 构建BoolQuery对象添加terms查询条件return QueryBuilders.bool().must(t - t.terms(f - f.field(key).terms(v - v.value(fieldValues)))).build();}break;case WILDCARD:// 如果查询模式是WILDCARD则构建BoolQuery对象添加wildcard查询条件return QueryBuilders.bool().must(t - t.wildcard(f - f.field(key).value(* o *))).build();case RANGE:// 如果查询模式是RANGE并且对象是EsRangeObject类型if (o instanceof EsRangeObject) {// 将对象转换为EsRangeObject类型EsRangeObject rangeObject (EsRangeObject) o;// 创建RangeQuery.Builder对象设置查询的字段RangeQuery.Builder range QueryBuilders.range().field(key);// 如果EsRangeObject的from属性不为空则添加gte查询条件Optional.ofNullable(rangeObject.getFrom()).ifPresent(from - range.gte(JsonData.of(from)));// 如果EsRangeObject的to属性不为空则添加lte查询条件Optional.ofNullable(rangeObject.getTo()).ifPresent(to - range.lte(JsonData.of(to)));// 构建BoolQuery对象添加range查询条件return QueryBuilders.bool().must(range.build()._toQuery()).build();}break;default:// 如果查询模式不匹配任何已知模式则不执行任何操作break;}}// 如果注解不是GeneralConvert类型或者对象为空则返回nullreturn null;}}/*** description: 通用转换*/
Documented
Retention(RetentionPolicy.RUNTIME)
Target({ElementType.TYPE, ElementType.FIELD})
public interface GeneralConvert {/*** 获取键值** return 返回键值*/String key();/*** 获取当前ES查询模式** return 返回当前ES查询模式*/EsQueryMode mode();}
Data
Accessors(chain true)
public class LuTshoes extends AbstractEsConditionReqDto{GeneralConvert(key term, mode EsQueryMode.TERM)private String term;GeneralConvert(key terms, mode EsQueryMode.TERMS)private ListString terms;GeneralConvert(key wildcard, mode EsQueryMode.WILDCARD)private String wildcard;GeneralConvert(key rangeObject, mode EsQueryMode.RANGE)private EsRangeObject rangeObject;public static void main(String[] args) throws IllegalAccessException {LuTshoes luTshoes new LuTshoes().setTerm(term).setRangeObject(newEsRangeObject().setFrom(100).setTo(200)).setWildcard(123456).setTerms(List.of(terms,2));System.out.println(luTshoes.build());}Overridepublic BoolQuery build() throws IllegalAccessException {// 也可以自己定义实现return BoolQueryAdapter.convert(this);}
}