赞
踩
(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>
@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; } }
以上仅小弟个人记录,有帮助就看看,没帮助也别喷
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。