es 基于地址做范围排序

基础排序功能,包括两种:

  • 普通字段排序

  • 地理坐标排序

 然后我们要修改实体类中 添加实体类的字段 (我的是location 这个字段是坐标)

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.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;


@Service
public class HotelService extends ServiceImpl<HotelMapper, Hotel> implements IHotelService {

    @Resource
    private HotelMapper hotelMapper;

    @Resource
    private RestHighLevelClient client;

    @Override
    public PageResult search(RequestParams params) throws IOException {
        //准备Request
        SearchRequest request = new SearchRequest("hotel");//操作的数组
        //构建boolQuery组合条件
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //boolQuery才是搜索条件 其他查询只是boolQuery中的一部分
        request.source().query(boolQuery);
        String key = params.getKey();
        if (key != null && key != "") {
            //match查询,会将搜索词分词,再与目标查询字段进行匹配,若分词中的任意一个词与目标字段匹配上,则可查询到。
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        } else {
            //must 中的语句是必须满足的,会影响最终文档的得分
            //filter 中的语句是必须满足的,但是不会影响最终的得分
            //must_not 中的语句是必须不满足的, 不影响最终的得分
            //should中的语句是可以满足的,影响得分,minimum_should_match就是为这兄弟设置的
            boolQuery.must(QueryBuilders.matchAllQuery());
        }
        //城市条件(精确匹配QueryBuilders.termQuery)
        if (params.getCity() != null && !"".equals(params.getCity())) {
            //termQuery输入的查询内容是什么,就会按照什么去查询,并不会解析查询内容,对它分词。
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }//品牌条件(精确匹配QueryBuilders.termQuery)
        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()));
        }
        //价格条件 (范围匹配QueryBuilders.rangeQuery)
        if (params.getMinPrice() != null & params.getMaxPrice() != null) {
            boolQuery.filter(QueryBuilders.rangeQuery("price")
                    .gte(params.getMinPrice()).lt(params.getMaxPrice()));
            //gte大于等于 gt大于  lte小于等于 lt小于
        }
        //分页内容
        int page = params.getPage();
        int size = params.getSize();
        //              偏移量 (page-1)*size
        request.source().from((page - 1) * size).size(size);

        //排序 按地理坐标排序
        if (params.getLocation()!= null&&!"".equals(params.getLocation())) {
            request.source().sort(SortBuilders
                    //参数1 地理位置的字段  参数2 地理坐标
                    .geoDistanceSort("location",new GeoPoint(params.getLocation()))
                    .order(SortOrder.ASC) //排序(升序)
                    .unit(DistanceUnit.KILOMETERS) //设置单位km
            );
        }

        //发送请求
        SearchResponse search = client.search(request, RequestOptions.DEFAULT);
        return getPageResult(search);
    }

    //对结果进行处理
    private PageResult getPageResult(SearchResponse search) {
        SearchHits searchHits = search.getHits();
        PageResult pageResult = new PageResult();
        pageResult.setTotal(searchHits.getTotalHits().value);
        SearchHit[] hits = searchHits.getHits();
        ArrayList<HotelDoc> list = new ArrayList<>();
        for (SearchHit hit : hits) {
            // 获取文档source
            String json = hit.getSourceAsString();
            // 反序列化
            HotelDoc hotelDoc = JSON.parseObject(json, HotelDoc.class);
            //获取排序值
            Object[] sortValues = hit.getSortValues();
            if (sortValues.length>0){
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }

            // 放入集合
            list.add(hotelDoc);
        }
        pageResult.setHotels(list);
        // 4.4.封装返回
        return pageResult;
    }


}

注意事项1: 三个参数的设置 

//排序 按地理坐标排序
        if (params.getLocation()!= null&&!"".equals(params.getLocation())) {
            request.source().sort(SortBuilders
                    //参数1 地理位置的字段  参数2 地理坐标
                    .geoDistanceSort("location",new GeoPoint(params.getLocation()))
                    .order(SortOrder.ASC) //排序(升序)
                    .unit(DistanceUnit.KILOMETERS) //设置单位km
            );
        }

 因为我接受的String类型的坐标参数 所以 new GeoPoint 来操作

注意事项2: 

   Object[] sortValues = hit.getSortValues();
            if (sortValues.length>0){
                Object sortValue = sortValues[0];
                hotelDoc.setDistance(sortValue);
            }

判断地址有没有传值过来 (因为查询第一次是没值的)

通过hit.getSortValues()获取坐标集合 然后取下标为0的坐标set方法设置到hotelDoc中返回

 其实可以将判断的语句封装为一个方法 这样看起来不会那么臃肿

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值