编辑
2025-10-03
java
00

目录

1.elasticsearch中的搜索结果处理
2.分页结果
3.结果高亮显示
4.使用RestClient实现es查询
5.使用RestClient实现结果处理

1.elasticsearch中的搜索结果处理

案例1

image.png

DSL
GET /hotel/_search { "query":{ "match_all": {} }, "sort":[ { "score":"desc" }, { "price":"asc" } ] }

案例2

image.png

DSL
# 31.034661 121.612282 GET /hotel/_search { "query":{ "match_all": {} }, "sort":[ { "_geo_distance": { "location": { "lat": 31.034661, "lon": 121.612282 }, "order": "asc", "unit": "km" } }] }

2.分页结果

image.png

示例

DSL
GET /hotel/_search { "query":{ "match_all": {} }, "sort":[ { "price":"asc" } ], "from": 0, "size": 20 }

深度分页问题

image.png

解决方案

image.png

3.结果高亮显示

image.png

DSL
GET /hotel/_search { "query":{ "match": { "all": "如家" } }, "highlight": { "fields": { "name": { "require_field_match": "false" } } } }

4.使用RestClient实现es查询

快速入门 image.png

java
@Test void testMatchAll() throws IOException { // 准备reuqest SearchRequest request = new SearchRequest("hotel"); // 准备DSL request.source().query(QueryBuilders.matchAllQuery()); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); System.out.println(response); }

解析结果

image.png

java
@Test void testMatchAll() throws IOException { // 准备reuqest SearchRequest request = new SearchRequest("hotel"); // 准备DSL request.source().query(QueryBuilders.matchAllQuery()); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); System.out.println(json); } }

match查询

image.png

java
@Test void testMatch() throws IOException { // 准备reuqest SearchRequest request = new SearchRequest("hotel"); // 准备DSL request.source().query(QueryBuilders.matchQuery("all","如家")); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); System.out.println(json); } }

精确查询

image.png

复合查询

image.png

java
@Test void testBoolQuery() throws IOException { // 准备reuqest SearchRequest request = new SearchRequest("hotel"); // 创建boolQueryBuilder对象 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // 添加term boolQueryBuilder.must(QueryBuilders.termQuery("city","上海")); // 添加range boolQueryBuilder.filter(QueryBuilders.rangeQuery("price").lte(250)); request.source().query(boolQueryBuilder); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); System.out.println(json); } }

5.使用RestClient实现结果处理

image.png

java
@Test void testPageAndSort() throws IOException { // 准备reuqest int page = 2, size = 5; SearchRequest request = new SearchRequest("hotel"); request.source().query(QueryBuilders.matchAllQuery()); request.source().sort("price", SortOrder.ASC); request.source().from((page-1)*size).size(size); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; System.out.println("共"+total+"条数据"); SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class); System.out.println(hotelDoc.toString()); } }

RestClient处理高亮

image.png

java
@Test void testHeightLight() throws IOException { // 准备reuqest int page = 2, size = 5; SearchRequest request = new SearchRequest("hotel"); request.source().query(QueryBuilders.matchQuery("all","如家")); request.source().highlighter(new HighlightBuilder().field("name").requireFieldMatch(false)); // 发送请求 SearchResponse response = client.search(request,RequestOptions.DEFAULT); SearchHits searchHits = response.getHits(); long total = searchHits.getTotalHits().value; System.out.println("共"+total+"条数据"); SearchHit[] hits = searchHits.getHits(); for (SearchHit hit : hits) { String json = hit.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(json,HotelDoc.class); Map<String,HighlightField> highlightFields = hit.getHighlightFields(); if (!CollectionUtils.isEmpty(highlightFields)){ // 根据字段名获取高亮结果 HighlightField highlightField = highlightFields.get("name"); if (highlightField!=null){ // 获取高亮值 String name = highlightField.getFragments()[0].string(); // 覆盖非非高亮结果 hotelDoc.setName(name); } } // System.out.println("hotelDoc = "+hotelDoc.toString()); } }

地理距离排序

image.png

添加权重

image.png

案例关键代码

java
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 com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.common.unit.DistanceUnit; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.SearchHits; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; import org.elasticsearch.search.sort.SortBuilders; import org.elasticsearch.search.sort.SortOrder; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import javax.swing.text.Highlighter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Map; @Service public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService { // 注入Elasticsearch的高级客户端 @Autowired private RestHighLevelClient client; /** * 酒店搜索方法 * @param requestParams 搜索请求参数 * @return 分页结果 */ @Override public PageResult search(RequestParams requestParams) { try { // 1. 准备SearchRequest,指定索引名为"hotel" SearchRequest request = new SearchRequest("hotel"); // 2. 构建基本查询条件 buildBasicQuery(requestParams, request); // 3. 设置分页参数 int page = requestParams.getPage(); int size = requestParams.getSize(); request.source().from((page-1)*size).size(size); // 4. 地理位置排序(如果提供了位置参数) String location = requestParams.getLocation(); if(location != null && !"".equals(location)){ request.source().sort(SortBuilders.geoDistanceSort("location", new GeoPoint(location)) .order(SortOrder.ASC) // 按距离升序排序 .unit(DistanceUnit.KILOMETERS)); // 距离单位为公里 } // 5. 执行搜索请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); // 6. 处理搜索结果并返回 return handleResponse(response); } catch (IOException e) { throw new RuntimeException("搜索酒店失败", e); } } /** * 构建基本查询条件 * @param requestParams 请求参数 * @param request SearchRequest对象 */ private void buildBasicQuery(RequestParams requestParams, SearchRequest request) { // 1. 创建布尔查询构建器 BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); // 2. 关键字查询 String key = requestParams.getKey(); if (key == null || key.equals("")){ // 如果关键字为空,则匹配所有文档 boolQueryBuilder.must(QueryBuilders.matchAllQuery()); } else { // 否则在"all"字段中搜索关键字 boolQueryBuilder.must(QueryBuilders.matchQuery("all", key)); } // 3. 城市过滤条件 if (requestParams.getCity() != null && !requestParams.getCity().equals("")){ boolQueryBuilder.filter(QueryBuilders.termQuery("city", requestParams.getCity())); } // 4. 品牌过滤条件 if (requestParams.getBrand() != null && !requestParams.getBrand().equals("")){ boolQueryBuilder.filter(QueryBuilders.termQuery("brand", requestParams.getBrand())); } // 5. 星级过滤条件 if (requestParams.getStarName() != null && !requestParams.getStarName().equals("")){ boolQueryBuilder.filter(QueryBuilders.termQuery("starName", requestParams.getStarName())); } // 6. 价格范围过滤 if (requestParams.getMaxPrice() != null && requestParams.getMinPrice() != null){ boolQueryBuilder.filter(QueryBuilders.rangeQuery("price") .gte(requestParams.getMinPrice()) // 大于等于最小值 .lte(requestParams.getMaxPrice())); // 小于等于最大值 } // 7. 构建函数评分查询(广告置顶功能) FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery( boolQueryBuilder, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ new FunctionScoreQueryBuilder.FilterFunctionBuilder( QueryBuilders.termQuery("isAd", true), // 广告标识字段 ScoreFunctionBuilders.weightFactorFunction(10) // 权重因子为10 ) } ); // 8. 将查询设置到请求中 request.source().query(functionScoreQueryBuilder); } /** * 处理搜索响应结果 * @param response Elasticsearch的搜索响应 * @return 分页结果对象 */ public PageResult handleResponse(SearchResponse response) { PageResult pageResult = new PageResult(); // 1. 获取命中结果 SearchHits searchHits = response.getHits(); // 2. 设置总命中数 long total = searchHits.getTotalHits().value; pageResult.setTotal(total); // 3. 处理每条命中记录 SearchHit[] hits = searchHits.getHits(); List<HotelDoc> hotelDocList = new ArrayList<>(); for (SearchHit hit : hits) { // 3.1 将JSON格式的源数据转换为HotelDoc对象 String json = hit.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class); // 3.2 处理距离排序值(如果有) Object[] sortValues = hit.getSortValues(); if (sortValues != null && sortValues.length > 0) { Object sortValue = sortValues[0]; hotelDoc.setDistance(sortValue); } // 3.3 处理高亮字段(如果有) Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if (!CollectionUtils.isEmpty(highlightFields)) { HighlightField highlightField = highlightFields.get("name"); if (highlightField != null) { // 获取高亮后的名称 String name = highlightField.getFragments()[0].string(); hotelDoc.setName(name); } } // 3.4 将处理后的酒店文档添加到列表 hotelDocList.add(hotelDoc); } // 4. 设置结果列表并返回 pageResult.setHotels(hotelDocList); return pageResult; } }

本文作者:钱小杰

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!