当前位置:   article > 正文

使用Java High Level REST Client操作es

java high level rest client

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

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

依赖

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

    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.12.1</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

创建连接

@Component
public class RestHighLevelClientRequest {

    @Bean
    public RestHighLevelClient client() {
        return new RestHighLevelClient(
                RestClient.builder(
                        HttpHost.create("http://ip:9200")//多台服务器可继续添加URL
                        HttpHost.create("http://ip:9200")
                )
        );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

工具类

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

@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;
    }
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257

整合上面的查询示例

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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

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

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

    /**
     * 多条件、聚合查询
     *
     * @param params
     * @return
     */
    Map<String, List<String>> filters(RequestParams params);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
@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)
        );
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173

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;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58

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

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号