elasticsearch8.x Api方法

自己学习elasticsearch8.x写的Api方法,有点乱没怎么整理,如有不足不吝赐教。如果有帮助到您,麻烦点个赞~

废话不多说直接上api,配置有不明白的可以搜其他博主的文档解决一下~

部分方法可能跟我用于学习es8的业务耦合性较高,这个根据不同业务做调整~

public class HotelDoc {

    private String id;
    private String name;//酒店名
    private String address;//酒店地址
    private int price;//酒店价格
    private int score;//打分
    private String brand;//品牌
    private String city;//城市
    private String star_name;//酒店星级 1钻-5钻 1星-5星
    private String business;//商圈
    private String location;//酒店坐标
    private String pic;//酒店图片


    private double distance;//酒店距离
    private boolean ad;//是否广告
    private List<String> suggestion;
}
/**
     * 判断索引库是否存在
     *
     * @param index 索引名
     * @return boolean
     * @throws IOException
     */
    public static boolean ifExist(String index) throws IOException {
        BooleanResponse response = client.indices().exists(builder -> builder.index(index));
        return response.value();

    }

    /**
     * 根据索引库名删除
     *
     * @param index 索引库名
     * @return
     * @throws IOException
     */
    public static boolean deteleIndex(String index) throws IOException {
        DeleteIndexResponse response = client.indices().delete(builder -> builder.index(index));
        return response.acknowledged();
    }

    /**
     * 代码创建索引库
     *
     * @param index 索引名
     * @param map   字段以及字段对应的type类型
     * @return boolean
     * @throws IOException
     */
    public static boolean createIndex(String index, Map<String, Property> map) throws IOException {
        CreateIndexRequest indexRequest = CreateIndexRequest.of(builder ->
                builder.index(index).mappings(objBuild -> objBuild.properties(map)));
        // 发送请求
        CreateIndexResponse response = client.indices().create(indexRequest);
        return response.acknowledged();

    }

    /**
     * 根据索引json内容创建索引库
     *
     * @param index 索引名
     * @return boolean
     * @throws IOException
     */
    public static boolean createIndexForStr(String index) throws IOException {
        String mapping_str = Templet.getTemplet(index);
        if (mapping_str == null) return false;
        log.info("mapping_str:【{}】", mapping_str);
        CreateIndexRequest indexRequest = CreateIndexRequest.of(builder ->
                builder.index(index)
                        .withJson(new StringReader(mapping_str)));
        // 发送请求
        CreateIndexResponse response = client.indices().create(indexRequest);
        return response.acknowledged();

    }

    /**
     * 根据索引json内容创建索引库 字符串只需要包含{"properties":{}}内容
     *
     * @param index 索引名
     * @return boolean
     * @throws IOException
     */
    public static boolean createIndexForStr2(String index) throws IOException {

        JsonpMapper mapper = client._transport().jsonpMapper();
        String mapping_str = Templet.getTemplet(index);
        if (mapping_str == null) return false;
        log.info("mapping_str:【{}】", mapping_str);
        JsonParser parser = mapper.jsonProvider().createParser(new StringReader(mapping_str));

        // 发送请求
        CreateIndexResponse response = client.indices().create(builder ->
                builder.index(index).mappings(TypeMapping._DESERIALIZER.deserialize(parser, mapper)));
        return response.acknowledged();

    }


    /**
     * 根据索引库创建json文件路径创建索引库
     *
     * @param index 索引名
     * @param path  xx.json文件
     * @return boolean
     * @throws IOException
     */
    public static boolean createIndexForPath(String index, String path) throws IOException {

        JsonpMapper mapper = client._transport().jsonpMapper();
        String mapping_str = new String(Files.readAllBytes(Paths.get(path)));
        log.info("mapping_str:【{}】", mapping_str);
        JsonParser parser = mapper.jsonProvider().createParser(new StringReader(mapping_str));

        // 发送请求
        CreateIndexResponse response = client.indices().create(builder ->
                builder.index(index).mappings(TypeMapping._DESERIALIZER.deserialize(parser, mapper)));
        return response.acknowledged();

    }


    /**
     * 根据索引名以及文档id添加文档
     *
     * @param index 索引名
     * @param obj   单个对象
     * @return
     * @throws IOException
     */
    public static <T> void createDoc(String index, T obj) throws IOException, IllegalAccessException {
        boolean b = ifExist(index);
        if (!b) return;

        Field[] fields = obj.getClass().getDeclaredFields();
        fields[0].setAccessible(true);
        String id = fields[0].get(obj).toString();
        client.create(x -> x.index(index).id(id).document(obj));
    }

    /**
     * 根据索引名以及文档id添加文档
     *
     * @param index   索引名
     * @param id      文档id
     * @param jsonStr json格式的文档数据
     * @return
     * @throws IOException
     */
    public static <T> void createDocForStr(String index, String id, String jsonStr) throws IOException {
        boolean b = ifExist(index);
        if (!b) return;

//        IndexRequest<Object> request = IndexRequest.of(builder -> builder.index(index).id(id).withJson(new StringReader(jsonStr)));
//        client.index(request);
        client.create(builder -> builder.index(index).id(id).withJson(new StringReader(jsonStr)));
    }

    /**
     * 根据索引名批量添加文档 通过BulkOperation来操作
     *
     * @param index 索引名
     * @param lst   对象集合
     * @return
     * @throws IOException
     */
    public static <T> boolean createBatchDoc(String index, List<T> lst) throws IOException, IllegalAccessException {
        boolean b = ifExist(index);
        if (!b) return false;

        List<BulkOperation> blkLst = new ArrayList<>();
        for (T t : lst) {
            Field[] fields = t.getClass().getDeclaredFields();
            fields[0].setAccessible(true);
            String id = fields[0].get(t).toString();
            blkLst.add(BulkOperation.of(x -> x.create(y -> y.index(index).id(id).document(t))));
        }
        BulkResponse response = client.bulk(builder -> builder.operations(blkLst));
        return !response.errors();
    }


    /**
     * 根据索引名以及id查询文档
     *
     * @param index 索引名
     * @param id    文档id
     * @return
     * @throws IOException
     */
    public static <T> T getDoc(String index, String id, Class<T> t) throws IOException {
        boolean b = ifExist(index);
        if (!b) return null;

        GetResponse<T> response = client.get(x -> x.index(index).id(id), t);
        return response.source();
    }

    /**
     * 根据索引名以及id修改文档
     *
     * @param index 索引名
     * @param id    文档id
     * @return
     * @throws IOException
     */
    public static void updateDoc(String index, String id, Map<String, Object> map) throws IOException {
        boolean b = ifExist(index);
        if (!b) return;

        client.update(builder -> builder.index(index).id(id).doc(map), User.class);
    }

    /**
     * 根据索引名以及id批量修改文档
     *
     * @param index 索引名
     * @param lst   List<Map<String, Object>> 包含文档id的map
     * @return
     * @throws IOException
     */
    public static boolean updateBatchDoc(String index, List<Map<String, Object>> lst) throws IOException {
        boolean b = ifExist(index);
        if (!b) return false;

        List<BulkOperation> bulkLst = new ArrayList<>();
        for (Map<String, Object> map : lst) {
            String id = map.get("id").toString();
            if (id == null) continue;

            bulkLst.add(BulkOperation.of(x -> x.update(y -> y.index(index).id(id).action(UpdateAction.of(z -> z.doc(map))))));
        }

        BulkResponse response = client.bulk(builder -> builder.operations(bulkLst));
        return !response.errors();
    }

    /**
     * 根据索引名以及id删除文档
     *
     * @param index 索引名
     * @param id    文档id
     * @return
     * @throws IOException
     */
    public static void deleteDoc(String index, String id) throws IOException {
        boolean b = ifExist(index);
        if (!b) return;
        DeleteResponse response = client.delete(builder -> builder.index(index).id(id));
        System.out.println(response.result().jsonValue());
    }

    /**
     * 根据索引名以及文档id批量删除文档 通过BulkOperation来操作
     *
     * @param index 索引名
     * @param lst   含有文档id对象集合
     * @return
     * @throws IOException
     */
    public static <T> boolean deleteBatchDoc(String index, List<T> lst) throws IOException, IllegalAccessException {
        boolean b = ifExist(index);
        if (!b) return false;

        List<BulkOperation> bulkLst = new ArrayList<>();
        for (T t : lst) {
            Field[] fields = t.getClass().getDeclaredFields();
            fields[0].setAccessible(true);
            String id = fields[0].get(t).toString();
            bulkLst.add(BulkOperation.of(builder -> builder.delete(builder1 -> builder1.index(index).id(id))));
        }

        BulkResponse bulk = client.bulk(builder -> builder.operations(bulkLst));
        return !bulk.errors();
    }

    /**
     * @param index 索引库名
     * @param t     文档id映射对象.class
     * @param <T>   文档id映射对象
     * @return List<T>
     * @throws IOException
     */
    public static <T> List<T> matchAll(String index, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(x -> x.index(index).query(y -> y.matchAll(z -> z)), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }


    /**
     * field为汇总字段时效果与multiMatch一致且效率更高
     *
     * @param index 索引库名
     * @param t     t  文档id映射对象.class
     * @param field 字段名
     * @param value 搜索词条
     * @param <T>   文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> match(String index, String field, String value, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(
                x -> x.index(index).query(
                        y -> y.match(
                                z -> z.field(field).query(value))), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 与match查询类似,只不过允许同时查询多个字段
     *
     * @param index  索引库名
     * @param t      t  文档id映射对象.class
     * @param fields 多个查询字段的集合
     * @param value  搜索词条
     * @param <T>    文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> multiMatch(String index, String value, List<String> fields, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(
                x -> x.index(index).query(
                        y -> y.multiMatch(
                                z -> z.query(value).fields(fields))), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 精确查询,必须字段值与查询值一致,否则不匹配
     *
     * @param index 索引库名
     * @param t     t  文档id映射对象.class
     * @param field 字段名
     * @param value 搜索词条
     * @param <T>   文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> term(String index, String field, String value, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(
                x -> x.index(index).query(
                        y -> y.term(
                                z -> z.field(field).value(value))), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 范围查询
     *
     * @param index    索引库名
     * @param field    字段名
     * @param gteValue 范围要大于的值
     * @param lteValue 范围要小于的值
     * @param t        t  文档id映射对象.class
     * @param <T>      文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> range(String index, String field, String gteValue, String lteValue, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(
                x -> x.index(index).query(
                        y -> y.range(
                                z -> z.field(field)
                                        .gte(JsonData.of(gteValue))
                                        .lte(JsonData.of(lteValue)))), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 地理坐标查询矩形范围内的文档数据
     *
     * @param index 索引库名
     * @param field 字段名
     * @param lat   经度
     * @param lon   纬度
     * @param t     t  文档id映射对象.class
     * @param <T>   文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> geoBoundingBox(String index, String field, String topRightLon, String topRightLat, Double lat, Double lon, Class<T> t) throws IOException {
        return null;
    }

    /**
     * 地理坐标查询distance以内的文档数据
     *
     * @param index    索引库名
     * @param field    字段名
     * @param distance 查询距离
     * @param lat      经度
     * @param lon      纬度
     * @param t        t  文档id映射对象.class
     * @param <T>      文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> geoDistance(String index, String field, String distance, Double lat, Double lon, Class<T> t) throws IOException {
        SearchResponse<T> response = client.search(
                x -> x.index(index).query(
                        y -> y.geoDistance(
                                z -> z.distance(distance).field(field).location(
                                        j -> j.latlon(LatLonGeoLocation.of(
                                                k -> k.lat(lat).lon(lon)))))), t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 复合查询,先对查询数据进行初次匹配,在通过filter过滤出符合条件的文档进行重新算分
     *
     * @param index             索引库名
     * @param matchField        原始条件匹配字段
     * @param matchValue        原始条件匹配字段值
     * @param filterField       过滤字段(只有符合过滤条件的文档才会被重新算分)
     * @param filterValue       过滤字段值
     * @param weight            算分函数 funtion score 将来回去query score计算得到新算分进行排序
     * @param functionBoostMode 加权模式  相乘/最大/最小/.....
     * @param t                 t  文档id映射对象.class
     * @param <T>               文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> funtionScoreQuery(String index, String matchField, String matchValue, String filterField, String filterValue, Double weight, FunctionBoostMode functionBoostMode, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index).query(
                x -> x.functionScore(
                        y -> y.query(
                                z -> z.match(
                                        j -> j.field(matchField).query(matchValue)
                                )
                        ).functions(
                                k -> k.filter(
                                                u -> u.term(
                                                        i -> i.field(filterField).value(filterValue)))
                                        .weight(weight)).boostMode(functionBoostMode)
                )).build();
        SearchResponse<T> response = client.search(request, t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }


    /**
     * 布尔查询
     *
     * @param index         索引库名
     * @param matchField    匹配字段
     * @param matchValue    匹配字段值
     * @param priceField    价格字段
     * @param priceValue    价格值
     * @param distance      距离
     * @param locationField 坐标字段
     * @param lat           坐标经度
     * @param lon           坐标纬度
     * @param t             t  文档id映射对象.class
     * @param <T>           文档id映射对象
     * @return
     * @throws IOException
     */
    // 搜索名字包含“如家”,价格不高于400,在坐标31.21,121.5周围10km范围内的酒店。
    public static <T> List<T> booleanQuery(String index, String matchField, String matchValue, String priceField, String priceValue, String distance, String locationField, Double lat, Double lon, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index).query(
                x -> x.bool(
                        y -> y.must(
                                z -> z.match(
                                        j -> j.field(matchField).query(matchValue)
                                )
                        ).mustNot(
                                k -> k.range(u -> u.field(priceField).gte(JsonData.of(priceValue))
                                )
                        ).should(
                                l -> l.geoDistance(u -> u.distance(distance).field("location").location(GeoLocation.of(i -> i.latlon(o -> o.lat(lat).lon(lon)))))
                        )
                )).build();
        SearchResponse<T> response = client.search(request, t);
        System.out.println(response.hits());
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 返回结果自定义排序
     *
     * @param index     索引库名
     * @param sortField 排序的字段
     * @param order     排序方式
     * @param t         t  文档id映射对象.class
     * @param <T>       文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> sort(String index, String sortField, SortOrder order, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index)
                .sort(
                        x -> x.field(FieldSort.of(
                                y -> y.field(sortField).order(order)
                        ))
                ).build();
        SearchResponse<T> response = client.search(request, t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 根据地理坐标自定义排序
     *
     * @param index     索引库名
     * @param sortField 排序的字段
     * @param lat       经度
     * @param lon       纬度
     * @param order     排序方式
     * @param t         t  文档id映射对象.class
     * @param <T>       文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> sortByGeoDistance(String index, String sortField, Double lat, Double lon, SortOrder order, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index).sort(
                x -> x.geoDistance(
                        y -> y.field(sortField)
                                .location(
                                        z -> z.latlon(
                                                j -> j.lat(lat).lon(lon)
                                        ))
                                .unit(DistanceUnit.Kilometers)
                                .order(order)
                )).build();
        SearchResponse<T> response = client.search(request, t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }


    /**
     * 分页查询
     *
     * @param index 索引库名
     * @param size  分页开始的位置
     * @param total 期望获取的文档总数
     * @param t     t  文档id映射对象.class
     * @param <T>   文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<T> page(String index, Integer total, Integer size, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index)
                .query(
                        x -> x.matchAll(y -> y)
                )
                // .sort(
                //         z->z.field(
                //                 j->j.field("age").order(SortOrder.Desc)
                //         )
                // )
                .from(total)
                .size(size)
                .build();
        SearchResponse<T> response = client.search(request, t);
        List<Hit<T>> hits = response.hits().hits();
        return hits.stream().map(Hit::source).collect(Collectors.toList());
    }

    /**
     * 数据查询返回高亮字段
     *
     * @param index           索引库名
     * @param matchField      匹配查询字段
     * @param matchValue      匹配查询字段值
     * @param highLightFields 需要高亮字段值的字段
     * @param match           查询字段是否与高亮字段一致
     * @param t               t  文档id映射对象.class
     * @param <T>             文档id映射对象
     * @return
     * @throws IOException
     */
    public static <T> List<Hit<T>> highlight(String index, String matchField, String matchValue, List<String> highLightFields
            , boolean match, Class<T> t) throws IOException {
        SearchRequest request = new SearchRequest.Builder().index(index)
                .query(
                        x -> x.match(
                                y -> y.field(matchField).query(matchValue)
                        )
                ).highlight(
                        x -> x.fields(
                                "name", y -> y.requireFieldMatch(match)
                        )
                )
                .build();
        SearchResponse<T> response = client.search(request, t);
        return response.hits().hits();
    }

    /**
     * 首先根据queryField以及value指定查询范围,在通过bucket聚合进行数据聚合
     *
     * @param index      索引库名
     * @param queryField 范围查询字段
     * @param value      字段值
     * @param aggName    聚合名称 自定义
     * @param aggField   聚合字段
     * @param aggSize    聚合数据显示条数
     * @return
     * @throws IOException
     */
    public static List<StringTermsBucket> bucket(String index, String queryField, Double value, String aggName, String aggField, Integer aggSize) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder().index(index);
        builder.query(
                x -> x.range(
                        y -> y.field(queryField).lte(JsonData.of(value))
                )
        );
        builder.size(0)
                .aggregations(aggName, x -> x
                        .terms(y -> y
                                .field(aggField)
                                .size(aggSize)
                                .order(NamedValue.of("_count", SortOrder.Desc))));
        SearchResponse<TypeQuery> response = client.search(builder.build(), TypeQuery.class);
        Map<String, Aggregate> map = response.aggregations();

        Aggregate aggs = map.get(aggName);
        StringTermsAggregate sterms = aggs.sterms();
        return sterms.buckets().array();
    }

    /**
     * 获取每个品牌的用户评分的min,max,avg值
     * @param index 索引库名
     * @param bucketName bucket聚合名称
     * @param bucketField bucket聚合字段
     * @param metricsName metrics聚合名称
     * @param metricsField metrics聚合字段
     * @return
     * @throws IOException
     */
    public static List<StringTermsBucket> metrics(String index, String bucketName,String bucketField, String metricsName, String metricsField) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder().index(index);
        builder.aggregations(bucketName,x->x
                .terms(y->y
                        .field(bucketField)
                        .size(5)
                        .order(NamedValue.of(metricsName+".avg",SortOrder.Desc)))
                .aggregations(metricsName,z->z
                        .stats(j->j
                                .field(metricsField)))
        );
        SearchResponse<HotelDoc> response = client.search(builder.build(), HotelDoc.class);
        Map<String, Aggregate> aggregations = response.aggregations();

        StringTermsAggregate sterms = aggregations.get(bucketName).sterms();
        return sterms.buckets().array();
    }

    /**
     * 实现对酒店品牌,城市,星级的数据聚合
     * 搜索页面的品牌城市以及星级不应该是写死的,而是通过聚合索引库里的数据得到的
     * @param index 索引库名
     * @return
     * @throws IOException
     */
    public static Map<String, List<String>> hotelSearch(String index) throws IOException {
        SearchRequest.Builder builder = new SearchRequest.Builder().index(index);
        builder.aggregations("brandAgg",x->x
                .terms(y->y
                        .field("brand")
                        .size(10)));
        builder.aggregations("cityAgg",x->x
                .terms(y->y
                        .field("city")
                        .size(10)));
        builder.aggregations("star_nameAgg",x->x
                .terms(y->y
                        .field("star_name")
                        .size(10)));
        SearchResponse<HotelDoc> response = client.search(builder.build(), HotelDoc.class);
        return getAggregateMap(response);
    }

    private static Map<String, List<String>> getAggregateMap(SearchResponse<HotelDoc> response) {
        Map<String, Aggregate> map = response.aggregations();
        StringTermsAggregate brandAgg = map.get("brandAgg").sterms();
        StringTermsAggregate cityAgg = map.get("cityAgg").sterms();
        StringTermsAggregate starNameAgg = map.get("star_nameAgg").sterms();
        List<StringTermsBucket> brandLst = brandAgg.buckets().array();
        List<StringTermsBucket> cityLst = cityAgg.buckets().array();
        List<StringTermsBucket> starNameLst = starNameAgg.buckets().array();

        HashMap<String, List<String>> retMap = new HashMap<>();
        retMap.put("brand",brandLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
        retMap.put("city",cityLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
        retMap.put("star_name",starNameLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
        return retMap;
    }

还有包括一些业务示例应用:

/**
    * 根据查询酒店参数:
               name:酒店名 匹配查询
               city:城市名 精确查询
               brand:品牌名 精确查询
               star_name:星级 精确查询
               price:价格 精确查询
               ad:是否为广告
    查询数据,且打过广告的酒店靠前高亮显示
    * @param hotel 查询条件对象
    * @return
    * @throws IOException
    */
   @Override
   public List<HotelDoc> search(HotelForSearch hotel) throws IOException {
       SearchRequest.Builder builder = new SearchRequest.Builder().index("hotel");
       BoolQuery.Builder bool = QueryBuilders.bool();
       buildQuery(hotel, bool);
       BoolQuery boolQuery = bool.build();

       FunctionScoreQuery.Builder func = QueryBuilders.functionScore();
       func.query(x->x.bool(boolQuery));
       func.functions(x->x.filter(y->y.term(z->z.field("ad").value(true))).weight(10.0)).boostMode(FunctionBoostMode.Sum);

       builder.query(y -> y.functionScore(func.build()));
       builder.highlight(x->x.fields("name",y->y.requireFieldMatch(true)));

       SearchRequest request = builder.from((hotel.getPage() - 1) * hotel.getSize())
               .size(hotel.getSize()).build();
       SearchResponse<HotelDoc> response = client.search(request, HotelDoc.class);
       List<Hit<HotelDoc>> hits = response.hits().hits();

       for (Hit<HotelDoc> hit : hits) {
           List<String> lst = hit.highlight().get("name");
           if (lst.isEmpty()) continue;
           if (Objects.isNull(hit.source())) continue;
           hit.source().setName(lst.get(0));
       }
       return hits.stream().map(Hit::source).collect(Collectors.toList());
   }

   /**
    * 根据地理坐标附近的酒店远近排序并分页
    * @param hotel  查询条件对象
    * @return
    * @throws IOException
    */
   @Override
   public List<HotelDoc> searchByDistance(HotelForSearch hotel) throws IOException {
       String location = hotel.getLocation();
       if (StrUtil.isBlank(location)) throw new RuntimeException("未获取到当前位置");

       SearchRequest.Builder builder = new SearchRequest.Builder().index("hotel");
       builder.sort(
               x->x.geoDistance(
                       y->y.field("location")
                               .location(z->z.text(location))
                               .unit(DistanceUnit.Kilometers)
                               .order(SortOrder.Asc)
               )
       )
               .from((hotel.getPage()-1)*hotel.getSize())
               .size(hotel.getSize());
       SearchRequest request = builder.build();
       SearchResponse<HotelDoc> response = client.search(request, HotelDoc.class);
       List<Hit<HotelDoc>> hitList = response.hits().hits();

       hitList.forEach(hit -> {
           HotelDoc doc = hit.source();
           List<FieldValue> sortLst = hit.sort();
           if (sortLst.isEmpty()) return;
           doc.setDistance(sortLst.get(0).doubleValue());
       });
       return hitList.stream().map(Hit::source).collect(Collectors.toList());
   }


    /**
    * 检索所有数据并使广告位数据靠前显示
    * @param hotel  查询条件对象
    * @return
    * @throws IOException
    */
   @Override
   public List<HotelDoc> searchForTopAd(HotelForSearch hotel) throws IOException {
       SearchRequest.Builder builder = new SearchRequest.Builder().index("hotel");
       builder.query(x->x
                       .functionScore(y->y
                               .query(z->z
                                       .matchAll(j->j))
                               .functions(j->j
                                       .filter(k->k
                                               .term(l->l
                                                       .field("ad").value(true)))
                                       .weight(10.0))
                               .boostMode(FunctionBoostMode.Multiply)))
               .from((hotel.getPage()-1)*hotel.getSize())
               .size(hotel.getSize());
       SearchRequest build = builder.build();
       SearchResponse<HotelDoc> response = client.search(build, HotelDoc.class);
       List<Hit<HotelDoc>> hits = response.hits().hits();
       return hits.stream().map(Hit::source).collect(Collectors.toList());
   }


   /**
    * 实现对酒店品牌,城市,星级的数据聚合
    * 搜索页面的品牌城市以及星级不应该是写死的,而是通过聚合索引库里的数据得到的,且可实现搜索框内容的输入动态展示
    * @param hotel 查询对象
    * @return
    */
   @Override
   public Map<String, List<String>> filters(HotelForSearch hotel) throws IOException {
       SearchRequest.Builder builder = new SearchRequest.Builder().index("hotel");
       BoolQuery.Builder bool = new BoolQuery.Builder();
       buildQuery(hotel, bool);
       builder.query(x->x.bool(bool.build()));
       builder.aggregations("brandAgg",x->x
               .terms(y->y
                       .field("brand")
                       .size(100)));
       builder.aggregations("cityAgg",x->x
               .terms(y->y
                       .field("city")
                       .size(100)));
       builder.aggregations("star_nameAgg",x->x
               .terms(y->y
                       .field("star_name")
                       .size(100)));
       SearchResponse<HotelDoc> response = client.search(builder.build(), HotelDoc.class);
       return getAggregateMap(response);
   }

   /**
    * 搜索框自动补全
    * @param text 搜索框输入内容
    * @return
    * @throws IOException
    */
   @Override
   public List<String> autoComplete(String text) throws IOException {
       SearchRequest.Builder builder = new SearchRequest.Builder().index("hotel");
       builder.suggest(x->x
               .suggesters("suggestions",y->y
                       .text(text)
                       .completion(z->z
                               .field("suggestion")
                               .skipDuplicates(true)
                               .size(10))));
       SearchResponse<HotelDoc> response = client.search(builder.build(), HotelDoc.class);
       List<Suggestion<HotelDoc>> lst = response.suggest().get("suggestions");
       System.out.println(lst);
       Suggestion<HotelDoc> suggestion = lst.get(0);
       List<CompletionSuggestOption<HotelDoc>> retLst = suggestion.completion().options();
       return retLst.stream().map(CompletionSuggestOption::text).collect(Collectors.toList());
   }

   /**
    * 结果的处理 Map<String,List<String>>
    */
   private static Map<String, List<String>> getAggregateMap(SearchResponse<HotelDoc> response) {
       Map<String, Aggregate> map = response.aggregations();
       StringTermsAggregate brandAgg = map.get("brandAgg").sterms();
       StringTermsAggregate cityAgg = map.get("cityAgg").sterms();
       StringTermsAggregate starNameAgg = map.get("star_nameAgg").sterms();
       List<StringTermsBucket> brandLst = brandAgg.buckets().array();
       List<StringTermsBucket> cityLst = cityAgg.buckets().array();
       List<StringTermsBucket> starNameLst = starNameAgg.buckets().array();

       HashMap<String, List<String>> retMap = new HashMap<>();
       retMap.put("brand",brandLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
       retMap.put("city",cityLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
       retMap.put("star_name",starNameLst.stream().map(x->x.key().stringValue()).collect(Collectors.toList()));
       return retMap;
   }

   /**
    * 根据页面查询条件进行范围查询
    */
   private void buildQuery(HotelForSearch hotel, BoolQuery.Builder bool) {
       if (StrUtil.isBlank(hotel.getName())) {
           bool.must(x->x.matchAll(y->y));
       }else {
           bool.must(x->x.match(y->y.field("name").query(hotel.getName())));
       }

       if (!StrUtil.isBlank(hotel.getCity())) {
           bool.filter(x->x.term(y->y.field("city").value(hotel.getCity())));
       }
       if (!StrUtil.isBlank(hotel.getBrand())) {
           bool.filter(x->x.term(y->y.field("brand").value(hotel.getBrand())));
       }
       if (!StrUtil.isBlank(hotel.getStar_name())) {
           bool.filter(x->x.term(y->y.field("star_name").value(hotel.getStar_name())));
       }
       if (!ifZero(hotel.getMinPrice())) {
           bool.mustNot(x->x.range(y->y.field("price").lte(JsonData.of(hotel.getMinPrice()))));
       }
       if (!ifZero(hotel.getMaxPrice())) {
           bool.mustNot(x->x.range(y->y.field("price").gte(JsonData.of(hotel.getMaxPrice()))));
       }
   }

   private boolean ifZero(int str){
       return str == 0;
   }

  • 8
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值