SpringBoot 整合es(elasticsearch)使用elasticsearch-rest-high-level-client实现增删改查
官方文档:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/6.5/java-rest-high-search.html (这个版本是6.5的)根据自己的来选择
- index可以类比为MySQL中的表这个概念,他是一类型数据存储的集合。
- document其实就是index这个集合里面单条数据的一种称呼,这个概念和MySQL中的行记录比较类似。
- type是这个代表document属于index中的哪个类别(type),一个index通常会划分为多个type,逻辑上对index中有些许不同的几类数据进行分类:因为一批相同的数据,可能有很多相同的fields,但是还是可能会有一些轻微的不同,可能会有少数fields是不一样的,举个例子,就比如说,商品,可能划分为电子商品,生鲜商品,日化商品,等等。
引入依赖
<dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>7.8.0</version> </dependency> <!-- elasticsearch的客户端 --> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>elasticsearch-rest-high-level-client</artifactId> <version>7.8.0</version> </dependency> <!-- elasticsearch依赖2.x的log4j --> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.8.2</version> </dependency> <!-- 阿里JSON解析器 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>fastjson</artifactId> <version>1.2.75</version> </dependency>
yml文件
#elasticsearch
esHostName: 192.168.1.25
esPort: 9200
ContentModel.java 根据自己的实际业务来
import lombok.Data; import lombok.ToString; import lombok.experimental.Accessors; /** * es存放实体类 */ @Data @Accessors(chain = true) @ToString public class ContentModel { private static final long serialVersionUID = 6320548148250372657L; private Integer contentId; private String title; }
配置类
EsConfig.java
import org.apache.http.HttpHost; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * @author yvioo。 */ @Configuration public class EsConfig { @Value("${esHostName}") private String esHostName; @Value("${esPort}") private Integer esPort; public static final RequestOptions COMMON_OPTIONS; static { RequestOptions.Builder builder=RequestOptions.DEFAULT.toBuilder(); COMMON_OPTIONS=builder.build(); } @Bean public RestHighLevelClient esRestClient(){ RestClientBuilder builder = RestClient.builder(new HttpHost(esHostName, esPort, "http")); RestHighLevelClient client=new RestHighLevelClient(builder); return client; } }
常量
EsConstant.java 可以不用
/** * @author yvioo。 */ public class EsConstant { public static final String CONTENT_INDEX="索引名称"; public static final String CONTENT_TYPE="类型"; }
工具类
EsService.java
import com.alibaba.fastjson.JSON; import com.example.es.elasticsearch.entity.ContentModel; import lombok.extern.slf4j.Slf4j; import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.delete.DeleteRequest; import org.elasticsearch.action.delete.DeleteResponse; import org.elasticsearch.action.get.GetRequest; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.action.update.UpdateResponse; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.fetch.subphase.FetchSourceContext; import org.springframework.stereotype.Service; import javax.annotation.Resource; import java.io.IOException; import java.util.*; import java.util.stream.Collectors; /** * es操作类 * * @author 洪。 */ @Slf4j @Service public class EsService { @Resource private RestHighLevelClient restHighLevelClient; /** * 批量插入文档数据 * @return 返回true 表示有错误 */ public boolean batchEsContent(List<ContentModel> contentModelList) throws IOException { BulkRequest bulkRequest = new BulkRequest(); List<Integer> delIds=new LinkedList<>(); for (ContentModel model : contentModelList) { IndexRequest indexRequest = new IndexRequest(EsConstant.CONTENT_INDEX).type(EsConstant.CONTENT_TYPE); indexRequest.id(model.getContentId().toString()); String s = JSON.toJSONString(model); indexRequest.source(s, XContentType.JSON); bulkRequest.add(indexRequest); } BulkResponse bulk = restHighLevelClient.bulk(bulkRequest, EsConfig.COMMON_OPTIONS); List<String> collect = Arrays.stream(bulk.getItems()).map(item -> { return item.getId(); }).collect(Collectors.toList()); log.error("内容索引生成:{}", collect); return bulk.hasFailures(); } /** * 判断是否存在文档数据 * * @param id 索引的ID * @return * @throws IOException */ public boolean existIndex(Integer id) throws IOException { GetRequest getRequest = new GetRequest( EsConstant.CONTENT_INDEX, id.toString()); getRequest.fetchSourceContext(new FetchSourceContext(false)); getRequest.storedFields("_none_"); return restHighLevelClient.exists(getRequest, EsConfig.COMMON_OPTIONS); } /** * 删除文档数据 * @param id * @return * @throws IOException */ public boolean deleteIndex(Integer id) throws IOException { DeleteRequest request = new DeleteRequest( EsConstant.CONTENT_INDEX, id.toString()); DeleteResponse deleteResponse = restHighLevelClient.delete( request, EsConfig.COMMON_OPTIONS); if (deleteResponse.status().getStatus()== RestStatus.OK.getStatus()){ return true; } return false; } /** * 批量删除索引 * @param ids * @return 返回true 表示有错误 * @throws IOException */ public boolean deleteBatchIndex(List<Integer> ids) throws IOException { // 批量删除数据 BulkRequest request = new BulkRequest(); ids.forEach(s->{ request.add(new DeleteRequest().index(EsConstant.CONTENT_INDEX).type(EsConstant.CONTENT_TYPE).id(s.toString())); }); BulkResponse response = restHighLevelClient.bulk(request, EsConfig.COMMON_OPTIONS); return response.hasFailures(); } /** * 更新文档数据 * @param contentModel * @return * @throws IOException */ public boolean updateIndex(ContentModel contentModel) throws IOException { // 修改数据 UpdateRequest request = new UpdateRequest(); request.index(EsConstant.CONTENT_INDEX).id(contentModel.getContentId().toString()); String s = JSON.toJSONString(contentModel); request.doc(s, XContentType.JSON); UpdateResponse updateResponse = restHighLevelClient.update(request, EsConfig.COMMON_OPTIONS); if (updateResponse.status().getStatus()== RestStatus.OK.getStatus()){ return true; } return false; } }
使用直接注入 EsService 然后调用里面的方法即可
由于每种业务查询的写法都不一定,没有通用性 所以这里只提供一些基础的方法
官网地址:https://www.elastic.co/guide/en/elasticsearch/client/java-rest/7.3/java-rest-high-search.html
基础的查询所有的demo
@Resource private RestHighLevelClient restHighLevelClient;
//创建检索请求 SearchRequest searchRequest = new SearchRequest("这里可以直接指定索引"); //创建检索条件 SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); //这个表示查询所有 searchSourceBuilder.query(QueryBuilders.matchAllQuery()); searchRequest.source(searchSourceBuilder); //执行检索 SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT); SearchHits searchHits = searchResponse.getHits(); //所有条数 long totalHits = searchHits.getTotalHits(); //遍历结果 for (SearchHit hit : searchHits) { ContentDto content = new ContentDto(); Map<String, Object> sourceAsMap = hit.getSourceAsMap(); //取出对应的结果 String documentTitle = (String) sourceAsMap.get("title"); }
数据量超过一万条1w就需要加下面这个才会反正正确的页码
searchSourceBuilder.trackTotalHits(true);
但是也可以报错 查询报错参考: Elasticsearch(es)查询报错:Result window is too large, from + size must be less than or equal to: [10000] but was [20000
精确查询匹配多个字段
BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("db.database", "库")) .must(QueryBuilders.termQuery("db.table", "表")) .must(QueryBuilders.termQuery("addressId", "地址"));
模糊查询
BoolQueryBuilder builder = QueryBuilders.boolQuery(); // 手机号模糊查询 String phone = bo.getPhone(); if (StringUtils.isNotBlank(phone)) { phone = "*"+phone+"*"; BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery(); WildcardQueryBuilder phoneBuilder = QueryBuilders.wildcardQuery("phone", phone); WildcardQueryBuilder mobileBuilder = QueryBuilders.wildcardQuery("mobile", phone); boolQueryBuilder.should(phoneBuilder); boolQueryBuilder.should(mobileeBuilder); builder.must(boolQueryBuilder); }
聚合函数-统计某个字段的值
// 构建搜索请求 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.aggregation(AggregationBuilders.sum("field_sum").field("your_field"));
使用 sum
聚合来计算指定字段的总和。将 your_field
替换为你实际想要统计的字段名。
取值
// 获取聚合结果 Sum sumAgg = response.getAggregations().get("field_sum"); double sumValue = sumAgg.getValue();
下面的field_sum与上面查询设置的对应
分页
sourceBuilder.from((query.getPageNo() > 0 ? (query.getPageNo() - 1) : 0) * query.getPageSize());
sourceBuilder.size(query.getPageSize());
数值范围筛选,大于0
query.must(QueryBuilders.rangeQuery("total").gt(0));
-----------------------有任何问题可以在评论区评论,也可以私信我,我看到的话会进行回复,欢迎大家指教------------------------
(蓝奏云官网有些地址失效了,需要把请求地址lanzous改成lanzoux才可以)