引言
学习黑马 SpringCloud 的 es 部分时发现老师用的是es的高级客户端来操作es的,而高级客户端已经显示弃用,上网搜索发现关于新的 Java client API 只有基础的索引、文档操作,没有关于这种稍复杂案例的操作,于是自己琢磨整理了一份笔记,也为其他学习最新的 es 的小伙伴 提供一个思路吧。
项目结构
添加项目依赖
<!--es7.17.9--><dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.17.9</version></dependency><dependency><groupId>co.elastic.clients</groupId><artifactId>elasticsearch-java</artifactId><version>7.17.9</version><exclusions><exclusion><groupId>jakarta.json</groupId><artifactId>jakarta.json-api</artifactId></exclusion></exclusions></dependency><dependency><groupId>com.fasterxml.jackson.core</groupId><artifactId>jackson-databind</artifactId><version>2.14.2</version></dependency><dependency><groupId>jakarta.json</groupId><artifactId>jakarta.json-api</artifactId><version>2.1.1</version><scope>compile</scope></dependency>
EsClientConfig
package cn.itcast.hotel.config;import co.elastic.clients.elasticsearch.ElasticsearchClient;import co.elastic.clients.json.jackson.JacksonJsonpMapper;import co.elastic.clients.transport.rest_client.RestClientTransport;import org.apache.http.HttpHost;import org.elasticsearch.client.RestClient;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@ConfigurationpublicclassEsClientConfig{@Beanpublic ElasticsearchClient createClient(){// 使用 RestClientBuilder 对象创建 Elasticsearch 的 REST 客户端
RestClient esClient = RestClient.builder(newHttpHost("your es server ip",9200,"http")).build();// 创建 ElasticsearchTransport 对象,该对象用于传输数据。这里使用 JacksonJsonpMapper 对象,将 JSON 数据映射为 Java 对象。
RestClientTransport transport =newRestClientTransport(
esClient,newJacksonJsonpMapper());// 创建 ElasticsearchClient 对象,该对象用于访问 Elasticsearch 的 APIreturnnewElasticsearchClient(transport);}}
HotelService
package cn.itcast.hotel.service.impl;import cn.itcast.hotel.mapper.HotelMapper;import cn.itcast.hotel.pojo.Hotel;import cn.itcast.hotel.pojo.HotelDoc;import cn.itcast.hotel.pojo.PageResult;import cn.itcast.hotel.pojo.RequestParams;import cn.itcast.hotel.service.IHotelService;import co.elastic.clients.elasticsearch.ElasticsearchClient;import co.elastic.clients.elasticsearch._types.*;import co.elastic.clients.elasticsearch._types.query_dsl.*;import co.elastic.clients.elasticsearch.core.SearchRequest;import co.elastic.clients.elasticsearch.core.SearchResponse;import co.elastic.clients.json.JsonData;import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;import lombok.extern.slf4j.Slf4j;import org.springframework.stereotype.Service;import javax.annotation.Resource;import java.io.IOException;import java.util.*;/**
* 根据参数查询酒店信息
* @param params 查询参数
* @return 分页结果
*/@Service@Slf4jpublicclassHotelServiceextendsServiceImpl<HotelMapper, Hotel>implementsIHotelService{@Resourceprivate ElasticsearchClient client;@Overridepublic PageResult search(RequestParams params){
String key = params.getKey();// 搜索关键字int page = params.getPage();// 当前页码int size = params.getSize();// 每页记录数
SearchResponse<HotelDoc> search;try{
search =getHotelDocSearchResponse(params, key, page, size);// 调用方法获取搜索结果}catch(IOException e){thrownewRuntimeException(e);}// 解析响应结果中的文档列表和总数
ArrayList<HotelDoc> hotelDocs =newArrayList<>();long total;// 遍历搜索结果并把酒店信息添加到列表中
search.hits().hits().forEach(h->{// 获取每个文档的排序字段,设置为距离字段(如果有)
List<FieldValue> sort = h.sort();if(!sort.isEmpty()){
FieldValue fieldValue = sort.get(0);if(h.source()!= null) h.source().setDistance(fieldValue.doubleValue());}
hotelDocs.add(h.source());});if(search.hits().total()!=null){
total = search.hits().total().value();}else total =0;// 返回分页结果returnnewPageResult(total,hotelDocs);}/**
* 根据参数构造搜索请求并返回搜索结果
* @param params 查询参数
* @param key 搜索关键字
* @param page 当前页码
* @param size 每页记录数
* @return 搜索结果
* @throws IOException
*/private SearchResponse<HotelDoc>getHotelDocSearchResponse(RequestParams params, String key,int page,int size)throws IOException {
SearchResponse<HotelDoc> search;
SearchRequest.Builder builder =newSearchRequest.Builder();// 创建搜索请求构建器
BoolQuery.Builder bool = QueryBuilders.bool();// 创建布尔查询构建器// 如果搜索关键字为空,则匹配所有记录,否则匹配包含关键字的记录if(key == null ||"".equals(key)){
bool.must(must -> must.matchAll(m -> m));}else{
bool.must(must -> must.match(m -> m.field("all").query(params.getKey())));}// 如果请求参数中指定了城市,则添加一个 term 过滤条件if(params.getCity()!=null&&!params.getCity().equals("")){
bool.filter(f -> f.term(t -> t.field("city").value(params.getCity())));}// 如果请求参数中指定了品牌,则添加一个 term 过滤条件if(params.getBrand()!=null&&!Objects.equals(params.getBrand(),"")){
bool.filter(f -> f.term(t -> t.field("brand").value(params.getBrand())));}// 如果请求参数中指定了星级,则添加一个 term 过滤条件if(params.getStarName()!=null&&!params.getStarName().equals("")){
bool.filter(f -> f.term(t -> t.field("starName").value(params.getStarName())));}// 如果请求参数中指定了价格范围,则添加一个 range 过滤条件if(params.getMinPrice()!=null&& params.getMaxPrice()!=null){
bool.filter(f -> f.range(t -> t.field("price").gte(JsonData.of(params.getMinPrice())).lte(JsonData.of(params.getMaxPrice()))));}// 创建一个 function score 查询构造器,用于添加权重和评分模式
FunctionScoreQuery.Builder function =newFunctionScoreQuery.Builder();// 添加查询条件,使用一个 BoolQuery 构建器构建的查询
function.query(bool.build()._toQuery())// 添加函数,如果符合 "isAD" 字段等于 "true" 的条件,权重为 10.0.functions(functions->functions.filter(fi -> fi.term(t -> t.field("isAD").value("true"))).weight(10.0))// 设置函数计算得分时的模式为 "Sum"(即求和).scoreMode(FunctionScoreMode.Sum);// 将 FunctionScoreQuery 添加到查询构建器中
builder.query(function.build()._toQuery());// 分页查询,设置查询结果的起始位置和查询的数量
builder.from((page -1)* size).size(size);// 获取请求中的位置参数
String location = params.getLocation();// 如果位置参数不为空if(location!=null){// 将位置参数按逗号分隔为经度和纬度数组
String[] locationArr = location.split(",");// 创建一个基于距离排序的构建器,以 "location" 字段作为排序依据
GeoDistanceSort geoDistanceSort =newGeoDistanceSort.Builder().field("location")// 设置排序基准点的经纬度坐标.location(l->l.latlon(la->la.lat(Double.parseDouble(locationArr[0])).lon(Double.parseDouble(locationArr[1]))))// 设置排序方式为升序.order(SortOrder.Asc)// 设置排序的距离单位为公里.unit(DistanceUnit.Kilometers).build();// 将距离排序添加到查询构建器中
builder.sort(s -> s.geoDistance(geoDistanceSort));}// 构建搜索请求,指定搜索的索引为 "hotel"
SearchRequest request = builder.index("hotel").build();// 打印请求日志
log.info("request:{}",request);// 执行搜索请求,并将结果保存到 search 变量中
search = client.search(request, HotelDoc.class);// 返回搜索结果return search;}}
版权归原作者 IsALian 所有, 如有侵权,请联系我们删除。