引言
學(xué)習(xí)黑馬 SpringCloud 的 es 部分時(shí)發(fā)現(xiàn)老師用的是es的高級(jí)客戶端來操作es的,而高級(jí)客戶端已經(jīng)顯示棄用,上網(wǎng)搜索發(fā)現(xiàn)關(guān)于新的 Java client API 只有基礎(chǔ)的索引、文檔操作,沒有關(guān)于這種稍復(fù)雜案例的操作,于是自己琢磨整理了一份筆記,也為其他學(xué)習(xí)最新的 es 的小伙伴 提供一個(gè)思路吧。文章來源:http://www.zghlxwxcb.cn/news/detail-516755.html
項(xiàng)目結(jié)構(gòu)
?????????????????文章來源地址http://www.zghlxwxcb.cn/news/detail-516755.html
添加項(xiàng)目依賴
<!--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;
@Configuration
public class EsClientConfig {
@Bean
public ElasticsearchClient createClient(){
// 使用 RestClientBuilder 對象創(chuàng)建 Elasticsearch 的 REST 客戶端
RestClient esClient = RestClient.builder(
new HttpHost("your es server ip", 9200, "http")
).build();
// 創(chuàng)建 ElasticsearchTransport 對象,該對象用于傳輸數(shù)據(jù)。這里使用 JacksonJsonpMapper 對象,將 JSON 數(shù)據(jù)映射為 Java 對象。
RestClientTransport transport = new RestClientTransport(
esClient, new JacksonJsonpMapper()
);
// 創(chuàng)建 ElasticsearchClient 對象,該對象用于訪問 Elasticsearch 的 API
return new ElasticsearchClient(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.*;
/**
* 根據(jù)參數(shù)查詢酒店信息
* @param params 查詢參數(shù)
* @return 分頁結(jié)果
*/
@Service
@Slf4j
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {
@Resource
private ElasticsearchClient client;
@Override
public PageResult search(RequestParams params) {
String key = params.getKey(); // 搜索關(guān)鍵字
int page = params.getPage(); // 當(dāng)前頁碼
int size = params.getSize(); // 每頁記錄數(shù)
SearchResponse<HotelDoc> search;
try {
search = getHotelDocSearchResponse(params, key, page, size); // 調(diào)用方法獲取搜索結(jié)果
} catch (IOException e) {
throw new RuntimeException(e);
}
// 解析響應(yīng)結(jié)果中的文檔列表和總數(shù)
ArrayList<HotelDoc> hotelDocs = new ArrayList<>();
long total;
// 遍歷搜索結(jié)果并把酒店信息添加到列表中
search.hits().hits().forEach(h-> {
// 獲取每個(gè)文檔的排序字段,設(shè)置為距離字段(如果有)
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;
// 返回分頁結(jié)果
return new PageResult(total,hotelDocs);
}
/**
* 根據(jù)參數(shù)構(gòu)造搜索請求并返回搜索結(jié)果
* @param params 查詢參數(shù)
* @param key 搜索關(guān)鍵字
* @param page 當(dāng)前頁碼
* @param size 每頁記錄數(shù)
* @return 搜索結(jié)果
* @throws IOException
*/
private SearchResponse<HotelDoc> getHotelDocSearchResponse(RequestParams params, String key, int page, int size) throws IOException {
SearchResponse<HotelDoc> search;
SearchRequest.Builder builder = new SearchRequest.Builder(); // 創(chuàng)建搜索請求構(gòu)建器
BoolQuery.Builder bool = QueryBuilders.bool(); // 創(chuàng)建布爾查詢構(gòu)建器
// 如果搜索關(guān)鍵字為空,則匹配所有記錄,否則匹配包含關(guān)鍵字的記錄
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())));
}
// 如果請求參數(shù)中指定了城市,則添加一個(gè) term 過濾條件
if (params.getCity()!=null&&!params.getCity().equals("")) {
bool.filter(f -> f.term(t -> t.field("city").value(params.getCity())));
}
// 如果請求參數(shù)中指定了品牌,則添加一個(gè) term 過濾條件
if (params.getBrand()!=null&&!Objects.equals(params.getBrand(), "")) {
bool.filter(f -> f.term(t -> t.field("brand").value(params.getBrand())));
}
// 如果請求參數(shù)中指定了星級(jí),則添加一個(gè) term 過濾條件
if (params.getStarName()!=null&&!params.getStarName().equals("")) {
bool.filter(f -> f.term(t -> t.field("starName").value(params.getStarName())));
}
// 如果請求參數(shù)中指定了價(jià)格范圍,則添加一個(gè) 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()))));
}
// 創(chuàng)建一個(gè) function score 查詢構(gòu)造器,用于添加權(quán)重和評(píng)分模式
FunctionScoreQuery.Builder function = new FunctionScoreQuery.Builder();
// 添加查詢條件,使用一個(gè) BoolQuery 構(gòu)建器構(gòu)建的查詢
function.query(bool.build()._toQuery())
// 添加函數(shù),如果符合 "isAD" 字段等于 "true" 的條件,權(quán)重為 10.0
.functions(functions->functions.filter(fi -> fi.term(t -> t.field("isAD").value("true"))).weight(10.0))
// 設(shè)置函數(shù)計(jì)算得分時(shí)的模式為 "Sum"(即求和)
.scoreMode(FunctionScoreMode.Sum);
// 將 FunctionScoreQuery 添加到查詢構(gòu)建器中
builder.query(function.build()._toQuery());
// 分頁查詢,設(shè)置查詢結(jié)果的起始位置和查詢的數(shù)量
builder.from((page -1)* size).size(size);
// 獲取請求中的位置參數(shù)
String location = params.getLocation();
// 如果位置參數(shù)不為空
if(location!=null) {
// 將位置參數(shù)按逗號(hào)分隔為經(jīng)度和緯度數(shù)組
String[] locationArr = location.split(",");
// 創(chuàng)建一個(gè)基于距離排序的構(gòu)建器,以 "location" 字段作為排序依據(jù)
GeoDistanceSort geoDistanceSort = new GeoDistanceSort.Builder().field("location")
// 設(shè)置排序基準(zhǔn)點(diǎn)的經(jīng)緯度坐標(biāo)
.location(l->l.latlon(la->la.lat(Double.parseDouble(locationArr[0])).lon(Double.parseDouble(locationArr[1]))))
// 設(shè)置排序方式為升序
.order(SortOrder.Asc)
// 設(shè)置排序的距離單位為公里
.unit(DistanceUnit.Kilometers).build();
// 將距離排序添加到查詢構(gòu)建器中
builder.sort(s -> s.geoDistance(geoDistanceSort));
}
// 構(gòu)建搜索請求,指定搜索的索引為 "hotel"
SearchRequest request = builder.index("hotel").build();
// 打印請求日志
log.info("request:{}",request);
// 執(zhí)行搜索請求,并將結(jié)果保存到 search 變量中
search = client.search(request, HotelDoc.class);
// 返回搜索結(jié)果
return search;
}
}
到了這里,關(guān)于黑馬旅游案例(包括搜索,分頁,廣告置頂)中使用 elasticsearch 7.17.9 Java API的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!