使用Java High Level REST Client操作es

使用Java High Level REST Client操作es:单体架构

  • 依赖
  • 创建连接
  • 工具类
  • 整合上面的查询示例

(Java High Level REST Client 官方已废弃,现在推行的是 Elasticsearch Java API Client )

依赖

依赖说明:在docker安装es文章中,我们使用的版本是7.12.1,所以本文依赖也引入相同版本

    
        org.elasticsearch.client
        elasticsearch-rest-high-level-client
        7.12.1
    

创建连接

@Component
public class RestHighLevelClientRequest {

    @Bean
    public RestHighLevelClient client() {
        return new RestHighLevelClient(
                RestClient.builder(
                        HttpHost.create("http://ip:9200")//多台服务器可继续添加URL
                        HttpHost.create("http://ip:9200")
                )
        );
    }
}

工具类

将简单的增删改查进行封装

@Component
public class EsUtil {

    private RestHighLevelClient client;

	//处理返回结果
    @Autowired
    RestHighLevelClientResponse restHighLevelClientResponse;

    /**
     * 新增索引库
     *
     * @param indexName       索引库名 类似于数据库名
     * @param mappingTempLate DSL语句
     * @throws IOException
     */
    public void createIndex(String indexName, String mappingTempLate) throws IOException {
        if (isIndexExit(indexName)) {
            throw new RuntimeException("索引库已存在");
        }

        //1、创建request,入参为索引库名称
        CreateIndexRequest request = new CreateIndexRequest(indexName);

        //2、请求参数:mappingTempLate为DSL语句,内容是json
        request.source(mappingTempLate, XContentType.JSON);

        // 3、发起请求,、indices()返回索引库操作的所有方法   RequestOptions.DEFAULT:控制请求头信息,一般为默认
        client.indices().create(request, RequestOptions.DEFAULT);
    }

    /**
     * 删除索引库
     *
     * @param indexName 索引库名 类似于数据库名
     * @throws IOException
     */
    public void delIndex(String indexName) throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        client.indices().delete(request, RequestOptions.DEFAULT);
    }

    /**
     * 判断索引库是否存在
     *
     * @param indexName 索引库名 类似于数据库名
     */
    public boolean isIndexExit(String indexName) throws IOException {
        GetIndexRequest request = new GetIndexRequest(indexName);
        boolean exists = client.indices().exists(request, RequestOptions.DEFAULT);
        return exists;
    }
    
    /**
     * 判断文档是否存在
     * @param indexName     索引库
     * @param id            文档id
     * @throws IOException
     */
    public boolean documentIsExists(String indexName , String id) throws IOException {

        GetRequest getRequest = new GetRequest(indexName, id);
        // 不获取返回的 _source 的上下文了
//        getRequest.fetchSourceContext(new FetchSourceContext(false));
//        getRequest.storedFields("_none_");
        return client.exists(getRequest, RequestOptions.DEFAULT);
    }

    /**
     * (DELETE  //索引名称/_doc/id)
     * 删除文档
     * @param indexName     索引库
     * @param id            文档id
     * @throws IOException
     */
    public void documentDeleteRequest(String indexName,String id) throws IOException {
        DeleteRequest request = new DeleteRequest(indexName, id);
        DeleteResponse deleteResponse = client.delete(request, RequestOptions.DEFAULT);
        System.out.println(deleteResponse.status()); // 对应命令返回的状态OK
    }

    /**
     * 添加单条数据  如果id已经存在则会全量修改
     *
     * @param indexName 索引库名
     * @param id        数据ID
     * @param document  数据文本,json
     * @throws IOException
     */
    public void setIndexDocument(String indexName, String id, String document) throws IOException {
        IndexRequest request = new IndexRequest(indexName).id(id);
        request.source(document, XContentType.JSON);
        client.index(request, RequestOptions.DEFAULT);
    }


    /**
     * 批量写入
     *
     * @param list      数据集合
     * @param indexName 索引名
     * 考虑到可能会传入多个实体类类型,list指定类型Object,如果传入object就强转一下,也可以指定具体实体类类型就不用指定object
     * @throws IOException
     */
    public <T> void bulkDocument(List<Object> list, String indexName) throws IOException {
    	
        //1、创建bulkRequest对象
        BulkRequest request = new BulkRequest();
        for (T o : list) {
            //转换数据并循环插入es
            //假如转User类型
        User user = (User) o;
            request.add(new IndexRequest(indexName)
                    .id(user.getId())
                    .source(JSONObject.toJSONString(user), XContentType.JSON));
        }
        client.bulk(request, RequestOptions.DEFAULT);
    }


    /**
     * 查询全部(全量查询)
     *   # query:查询  match_all:查询全部(全量查询)
     * DSL语句
     * GET /test/_search
     * 	{
     * 		"query": {
     * 			"match_all": {
     * 				}
     * 			}
     * }
     * @param indexName
     * @throws IOException
     */
    public List<Object> matchAll(String indexName) throws IOException {
        SearchRequest request = new SearchRequest(indexName);
        //准备DSL语句
        //source()为请求DSL,大DSL
        //query()查询
        //matchAllQuery全量查询
        request.source().query(QueryBuilders.matchAllQuery());
        //es将结果封装成了searchResponse对象返回,根据对象进行解析
        List<Object> objects = handleResponse(request);
        //将objects返回出去,处理成自己想要的格式
        return objects;
    }


    /**
     * multiMatchQuery 指定多字段搜索 类似 where (a = 'zs' or b = 'zs')
     * multi_match:多字段全文检索查询,与match查询类似
     * DSL语句
     * GET /test/_search
     * 	{
     * 		"query": {
     * 			"multi_match": {
     * 				"query": "文本",
     * 				"fields": ["字段1","字段2"...]
     * 					}
     * 				}
     * }
     * @param indexName 索引名
     * @param keyword 搜索文本
     * @param indexName 搜索字段
     */
    public List<Object> multiMatchQuery(String indexName, String keyword, String... fieldNames) throws IOException {
        SearchRequest request = new SearchRequest(indexName);
        //multiMatchQuery 指定多字段搜索
        request.source().query(QueryBuilders.multiMatchQuery(keyword, fieldNames));
        return handleResponse(request);
    }

    /**
     * termQuery 词条精确查询 termQuery("name",基本数据类型、object)
     * 精确查询 类似 where name = name
     * 精确查询(keyword)(term类型)语法 :FIELD(查询的具体字段) value(查询的具体值)
     * GET /test/_search
     *  {
     *      "query": {
     *          "term": {
     *          "FIELD": {
     *              "value": "VALUE"
     *                  }
     *              }
     *          }
     * }
     * @param indexName 索引库
     * @param keyword   查询keyword
     * @param condition 查询条件
     * @throws IOException
     */
    public List<Object> termQuery(String indexName, String keyword, Object condition) throws IOException {
        SearchRequest request = new SearchRequest(indexName);
        //termQuery 精确查询
        request.source().query(QueryBuilders.termQuery(keyword, condition));
        return handleResponse(request);
    }

    /**
     * rangeQuery 范围查询
     * # range(范围)类型查询语法:  FIELD(字段) gt:大于 ,gte:大于等于 ,lt:小于,lte小于等于
     * GET /test/_search
     * 	{
     * 		"query": {
     * 			"range": {
     *			 	"FIELD": {
     * 					"gte": 10,
     * 					"lte": 20
     * 					}
     * 				}
     * 			}
     * }
     * 范围查询  时间、价格   类似于  where price <= from and price <= to
     *
     * @param indexName 索引名
     * @param field     字段名
     * @param from      在前
     * @param to        在后
     * @return
     * @throws IOException
     */
    public List<Object> rangeQuery(String indexName, String field, Object from, Object to) throws IOException {
        SearchRequest request = new SearchRequest(indexName);
        //准备DSL语句
        //source()为请求DSL,大DSL
        //query()查询
        //rangeQuery范围查询 get大于等于 lte小于等于  gt大于  lt小于
        request.source().query(QueryBuilders.rangeQuery(field).gte(from).lte(to));
        return handleResponse(request);
    }

    /**
     * 处理es返回结果
     *
     * @param request
     * @return
     * @throws IOException
     */
    public List<Object> handleResponse(SearchRequest request) throws IOException {
        //es将结果封装成了searchResponse对象返回,根据对象进行解析
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析结果,取hits
        SearchHits searchHits = response.getHits();
        //取查询的总条数
        long value = searchHits.getTotalHits().value;
        //查询的结果数组
        SearchHit[] hits = searchHits.getHits();

        List<Object> objects = new ArrayList<>();
        for (SearchHit hit : hits) {
            //得到source
            String sourceAsString = hit.getSourceAsString();
            objects.add(sourceAsString);
        }
        return objects;
    }
 }

整合上面的查询示例

RequestParams.java 为入参的实体类,目的就是为了方便传参

@Data
@AllArgsConstructor
@NoArgsConstructor
public class RequestParams {
    //关键字
    private String key;

    //页码

    private Integer page;
    //大小
    private Integer size;

    //排序字段
    private String sortBy;

    //品牌
    private String brand;
    //城市
    private String city;
    //星级
    private String starName;
    //最小价格
    private Integer minPrice;
    //最大价格
    private Integer maxPrice;
    //坐标
    private String location;
}

定义一个接口,入参为 RequestParams 实体类

public interface TestService {
    /**
     * 单条件查询
     *
     * @param params
     * @return
     */
    List<Object> search(RequestParams params);

    /**
     * 多条件、聚合查询
     *
     * @param params
     * @return
     */
    Map<String, List<String>> filters(RequestParams params);
}
@Service
public class TestServiceImpl  implements TestService {
    @Autowired
    RestHighLevelClientResponse restHighLevelClientResponse;


    @Override
    public List<Object> search(RequestParams params) {
        try {
            //构建请求
            //indexName为索引库名
            SearchRequest request = new SearchRequest("indexName");
            SearchRequest reqData = buildBasicQuery(params, request);
            return restHighLevelClientResponse.handleResponse(reqData);
        } catch (IOException e) {
            throw new RuntimeException("查询失败");
        }
    }


     /**
     * 多聚合查询(对文档进行统计,类似于group by分组)+普通条件查询
     *
     * @param params
     * @return
     */
    @Override
    public Map<String, List<String>> filters(RequestParams params) {
        try {
        	//构建请求
            //indexName为索引库名
            SearchRequest request = new SearchRequest("indexName");
            //普通条件查询
            buildBasicQuery(params, request);
            request.source().size(0);
            //设置多聚合查询条件
            buildAggregation(request);
            Map<String, List<String>> stringListMap =restHighLevelClientResponse.handleBucketResponse(request);
            return stringListMap;
        } catch (IOException e) {
        }
        return null;
    }

    /**
     * 多条件查询  and
     *
     * @param params
     * @return
     */
    private SearchRequest buildBasicQuery(RequestParams params, SearchRequest request) {
        /**
         * 查询条件由两部分组成,一是BoolQueryBuilder算分,二是 FunctionScoreQueryBuilder 操作分数,如果不需要对分数进行修改的话,第二部分可不要
         * BoolQueryBuilder 是用来算分的原始查询,用来算分,不能操作分数
         * 第一部分 BoolQueryBuilder 开始
         */
        //-----------------------多条件拼接start-----------------------------
        //根据关键字搜索
        String key = params.getKey();
        //构建DSL
        //构建 booleanQuery(多条件查询)
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery();
        //must部分(must参与算分) 关键字搜索
        if (StringUtils.isBlank(key)) {
            // matchAllQuery : 全量查询,没有条件
            boolQuery.must(QueryBuilders.matchAllQuery());
        } else {
            // matchQuery 根据条件全量查询 多字段全文搜索(全量查询) all为指定多个字段的集合
            // 也可以使用 multiMatchQuery 多字段查询,这里是将多个字段合并了一个集合为all
            boolQuery.must(QueryBuilders.matchQuery("all", key));
        }

        // filter 过滤条件 类似and
        //filter过滤条件 term()查询是过滤查询,不能放must,因为放must会影响得分,影响得分就会影响性能
        if (StringUtils.isNotBlank(params.getCity())) {
            boolQuery.filter(QueryBuilders.termQuery("city", params.getCity()));
        }
        if (StringUtils.isNotBlank(params.getBrand())) {
            boolQuery.filter(QueryBuilders.termQuery("brand", params.getBrand()));
        }
        if (StringUtils.isNotBlank(params.getStarName())) {
            boolQuery.filter(QueryBuilders.termQuery("starName", params.getStarName()));
        }

        //范围条件
        if (null != params.getMinPrice() && null != params.getMaxPrice()) {
            boolQuery.filter(
                    QueryBuilders.rangeQuery("price")
                            .gte(params.getMinPrice())
                            .lte(params.getMaxPrice()));
        }

        //-----------------------多条件拼接end-----------------------------
        //-----------------------排序 start-----------------------------

        //分页条件
        int page = params.getPage();
        int size = params.getSize();
        request.source().from((page - 1) * size).size(size);

        //价格排序
//        request.source().trackScores(true);
//        request.source().sort("price", SortOrder.DESC);
        //-----------------------排序 end-----------------------------
        /**
         * 第一部分 BoolQueryBuilder算分结束
         */

        /**
         * 第二部分、算分控制
         * 组合查询-function score
         * POST /hotel/_search
         * {
         *   "query": {
         *     "function_score": {
         *       "query": {
         *         "match": {
         *           "搜索的字段": "搜索的文本"
         *         }
         *       },
         *       "functions": [ 
         *         {
         *           "filter": {
         *             "term": {
         *               "字段": "文本"
         *             }
         *           },
         *           "weight": 5
         *         }
         *       ]
         *     }
         *   }
         * }
         */
        FunctionScoreQueryBuilder functionScoreQueryBuilder = QueryBuilders.functionScoreQuery(
                //原始查询(相关算分的查询)
                boolQuery,
                //functions score (functions)数组
                new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
                        // 其中一个functions score (filter)元素(对象)
                        new FunctionScoreQueryBuilder.FilterFunctionBuilder(
                                //过滤条件,满足条件才会参与算分
                                //isAd为参与算分的字段
                                QueryBuilders.termQuery("isAd", true),
                                //算分函数
                                ScoreFunctionBuilders.weightFactorFunction(10))
                });

        request.source().query(functionScoreQueryBuilder);
        return request;
    }
	//设置多聚合查询条件 group by分组
    private void buildAggregation(SearchRequest request) {
        request.source().aggregation(AggregationBuilders
        		//设置名称
                .terms("brandAgg")
                //字段
                .field("brand")
                //大小
                .size(200)
        );
        request.source().aggregation(AggregationBuilders
                .terms("cityAgg")
                .field("city")
                .size(200)
        );
        request.source().aggregation(AggregationBuilders
                .terms("starAgg")
                .field("starName")
                .size(200)
        );
    }
}

RestHighLevelClientResponse .java 解析es请求后的 SearchResponse 数据

@Component
public class RestHighLevelClientResponse {

    @Autowired
    RestHighLevelClient client;

    /**
     * 解析普通请求 response
     *
     * @param request
     * @throws IOException
     */
    public List<Object> handleResponse(SearchRequest request) throws IOException {
        //es将结果封装成了searchResponse对象返回,根据对象进行解析
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        //解析结果,取hits
        SearchHits searchHits = response.getHits();
        //取查询的总条数
        long value = searchHits.getTotalHits().value;
        //查询的结果数组
        SearchHit[] hits = searchHits.getHits();

        List<Object> lists = new ArrayList<>();
        for (SearchHit hit : hits) {
            //得到source
            String sourceAsString = hit.getSourceAsString();
            lists .add(sourceAsString );
        }
        return lists ;
    }

    /**
     * 解析 bucket 桶聚合 请求 response
     *
     * @param request
     * @throws IOException
     */
    public Map<String, List<String>> handleBucketResponse(SearchRequest request) throws IOException {
        //es将结果封装成了searchResponse对象返回,根据对象进行解析
        SearchResponse response = client.search(request, RequestOptions.DEFAULT);
        Aggregations aggregations = response.getAggregations();
        Map<String, List<String>> result = new HashMap<>();
        result.put("brand", getAggResult(aggregations, "brandAgg"));
        result.put("city", getAggResult(aggregations, "cityAgg"));
        result.put("star", getAggResult(aggregations, "starAgg"));
        return result;
    }

    private List<String> getAggResult(Aggregations aggregations, String aggName) {
        Terms terms = aggregations.get(aggName);
        List<? extends Terms.Bucket> buckets = terms.getBuckets();
        List<String> b = new ArrayList<>();
        for (Terms.Bucket bucket : buckets) {
            b.add(bucket.getKeyAsString());
        }
        return b;
    }
}

以上仅小弟个人记录,有帮助就看看,没帮助也别喷

你可能感兴趣的:(elasticsearch,java,java,elasticsearch,开发语言)