-
先实现基本分页查询
- 1)先新建了一个requestParams类,方便接收前端页面传过来的查询条件参数
- 2)业务接口继承了mybatisplus的业务接口
- 3)编写业务代码:
-
@Service public class HotelServiceImpl extends ServiceImpl<HotelMapper,Hotel> implements HotelService { @Autowired private RestHighLevelClient client;//如果容器当中没有注入,需要在启动类中注入 @Override//ctrl + alt + b public PageResult search(RequestParams params) { try { //request SearchRequest request = new SearchRequest("hotel"); //dsl String key = params.getKey(); if(key==null || "".equals(key)){ //如果没有输如要搜索的内容,就全搜 request.source().query(QueryBuilders.matchAllQuery()); }else{ request.source().query(QueryBuilders.matchQuery("all",key)); } //分页 int page = params.getPage(); int size = params.getSize(); request.source().from((page-1)*size).size(size); //发请求 SearchResponse response = client.search(request, RequestOptions.DEFAULT); //处理结果 PageResult pageResult = resHandler(response); return pageResult; } catch (Exception e) { throw new RuntimeException(e); } } //处理响应结果的方法 public PageResult resHandler(SearchResponse response){ SearchHits searchHits = response.getHits(); //total long total = searchHits.getTotalHits().value; System.out.println("total"+total); //文档数组在hits>hits中 SearchHit[] hits = searchHits.getHits(); List<HotelDoc> hotelDocList = new ArrayList<>(); for (SearchHit hit : hits) { String hotelJson = hit.getSourceAsString(); HotelDoc hotelDoc = JSON.parseObject(hotelJson, HotelDoc.class); //高亮相关 Map<String, HighlightField> highlightFields = hit.getHighlightFields(); if(highlightFields != null){ HighlightField highlightField = highlightFields.get("name"); if (highlightField != null){ String name = highlightField.getFragments()[0].string(); //替换为高亮的name hotelDoc.setName(name); } } //搜索的hoteldoc集合结果 hotelDocList.add(hotelDoc); } return new PageResult(total,hotelDocList); } }
- 4)编写接口:
- 5)启动项目,postman测试接口
-
项目启动报了如下错,根据提示,需要添加字符编码和useSSL=false
- 解决办法:
-
spring.datasource.url=jdbc:mysql://192.168.8.171:3306/hotel?characterEncoding=utf8&useSSL=false
- 启动之后,用postman测试接口是否能够正常查
-
上面我们实现了基本查询,现在我们想要实现多条件过滤查询
- 1)那么我们需要修改RequestParams类
- 2)修改业务实现类,用布尔查询,增加四个查询条件
- 我们将这些查询条件抽成一个方法,便于后续使用
-
//抽出来的布尔查询条件的方法 private void buildBoolQuery(RequestParams params, SearchRequest request) { //dsl,构建一个复合查询 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); String key = params.getKey(); if(key==null || "".equals(key)){ //如果没有输如要搜索的内容,就全搜 //request.source().query(QueryBuilders.matchAllQuery()); boolQuery.must(QueryBuilders.matchAllQuery()); }else{ //request.source().query(QueryBuilders.matchQuery("all",key)); boolQuery.must(QueryBuilders.matchQuery("all",key)); } //围绕查询加条件 //城市: if(params.getCity()!=null && !"".equals(params.getCity())){ boolQuery.filter(QueryBuilders.termQuery("city", params.getCity())); } //品牌: if(params.getBrand()!=null && !"".equals(params.getBrand())){ boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand())); } //星级: if(params.getStarName()!=null && !"".equals(params.getStarName())){ boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName())); } //价格: if(params.getMinPrice()!=null && !"".equals(params.getMinPrice())&& params.getMaxPrice()!=null && !"".equals(params.getMaxPrice())){ boolQuery.filter(QueryBuilders.rangeQuery("price") .gte(params.getMinPrice()) .lte(params.getMaxPrice())); } //设置条件 request.source().query(boolQuery); }
- 3)postman测试接口bool复合条件查询成功
-
我们搜索附近的酒店,需要增加条件地理坐标
- 1)修改请求参数类,增加坐标属性,提供get,set方法
- 2)修改业务层实现类的方法,根据离指定地理坐标的距离升序排列(由近到远)
-
//排序 String location = params.getLocation(); if(location!=null && !"".equals(location)){ request.source().sort( SortBuilders.geoDistanceSort("location",new GeoPoint(location))//相对的地点坐标 .order(SortOrder.ASC) //排序方式:升序 .unit(DistanceUnit.KILOMETERS) //单位:千米 ); }
- 3)但是我们现在虽然可以按距离排序,但是还看不到酒店距离目标地点的距离是多远
- 因为我们的hoteldoc里面并没有距离这个属性,所以我们需要加
- 将查出来的距离放到对象的属性中
-
//得到距离 Object[] sortValues = hit.getSortValues(); //判断并取出数组当中的距离 if(sortValues!=null && sortValues.length>0){ Object sortValue = sortValues[0]; //将距离放进对象中 hotelDoc.setDistance(sortValue); }
- 4)postman测试成功:
-
使用算分函数,给搜索出来的文档置顶(类似淘宝推广置顶)
- 1)先去请求参数类当中增加“是否广告置顶”的属性:isAD
- 2)然后在索引库当中选几个文档,将其设置为置顶广告
- 这里要注意修改文档时选用哪一种方式:
- 这里我们修改了数据库当中倒序排序的前四条记录
-
POST /hotel/_update/2062643512 { "doc":{ "isAD":true } } POST /hotel/_update/2060618247 { "doc":{ "isAD":true } } POST /hotel/_update/2060510277 { "doc":{ "isAD":true } } POST /hotel/_update/2058250574 { "doc":{ "isAD":true } }
- 2)有了广告置顶之后,我们现在就需要写算分控制来控制置顶效果了
-
//算分控制 FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery( //复合查询dsl其中的算分条件 boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ new FunctionScoreQueryBuilder.FilterFunctionBuilder( //过滤条件 QueryBuilders.termQuery("isAD",true), //算分方法 ScoreFunctionBuilders.weightFactorFunction(100) ) } ); //设置条件 request.source().query(functionScoreQuery);
- 那么我们整个bool查询的条件如下:
-
//抽出来的布尔查询条件的方法 private void buildBoolQuery(RequestParams params, SearchRequest request) { //dsl,构建一个复合查询 BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); String key = params.getKey(); if(key==null || "".equals(key)){ //如果没有输如要搜索的内容,就全搜 //request.source().query(QueryBuilders.matchAllQuery()); boolQuery.must(QueryBuilders.matchAllQuery()); }else{ //request.source().query(QueryBuilders.matchQuery("all",key)); boolQuery.must(QueryBuilders.matchQuery("all",key)); } //围绕查询加条件 //城市: if(params.getCity()!=null && !"".equals(params.getCity())){ boolQuery.filter(QueryBuilders.termQuery("city", params.getCity())); } //品牌: if(params.getBrand()!=null && !"".equals(params.getBrand())){ boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand())); } //星级: if(params.getStarName()!=null && !"".equals(params.getStarName())){ boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName())); } //价格: if(params.getMinPrice()!=null && !"".equals(params.getMinPrice())&& params.getMaxPrice()!=null && !"".equals(params.getMaxPrice())){ boolQuery.filter(QueryBuilders.rangeQuery("price") .gte(params.getMinPrice()) .lte(params.getMaxPrice())); } //算分控制 FunctionScoreQueryBuilder functionScoreQuery = QueryBuilders.functionScoreQuery( //复合查询dsl其中的算分条件 boolQuery, new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ new FunctionScoreQueryBuilder.FilterFunctionBuilder( //过滤条件 QueryBuilders.termQuery("isAD",true), //算分方法 ScoreFunctionBuilders.weightFactorFunction(100) ) } ); //设置条件 request.source().query(functionScoreQuery); }
- 3)测试就可以看到我们设置的置顶文档显示在上面了