今天讲解下如何使用 Spring Boot 结合 ES。

可以在 ES 官方文档中发现,ES 为 Java REST Client 提供了两种方式的 Client:Java Low Level Client 和 Java High Level REST Client。

低级别客户端,它允许通过 HTTP 请求与 ES 集群进行通信,API 本身不负责数据的编码解码,由用户去编码解码,它与所有的 ES 版本兼容。

高级客户端基于低级客户端,是从 6.0 才开始加入的,主要目标是为了暴露各 API 特定的方法,高版本客户端依赖于 ES 核心项目,将 Request 对象作为参数,返回一个 Response 对象,所有 API 都可以同步或异步调用。

本文就通过 Spring Boot 结合 Java High Level REST Client 来进行一些演示。

Spring Boot 集成 ES

Spring Boot 集成 ES 主要分为以下三步:

  1. 加入 ES 依赖

  2. 配置 ES

  3. 演示 ES 基本操作

加入依赖

首先创建一个项目,在项目中加入 ES 相关依赖,具体依赖如下所示:

<dependency><groupId>org.elasticsearch</groupId><artifactId>elasticsearch</artifactId><version>7.1.0</version>
</dependency>
<dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId><version>7.1.0</version>
</dependency>

创建 ES 配置

在配置文件 application.properties 中配置 ES 的相关参数,具体内容如下:

elasticsearch.host=localhost
elasticsearch.port=9200
elasticsearch.connTimeout=3000
elasticsearch.socketTimeout=5000
elasticsearch.connectionRequestTimeout=500

其中指定了 ES 的 host 和端口以及超时时间的设置,另外我们的 ES 没有添加任何的安全认证,因此 username 和 password 就没有设置。

然后在 config 包下创建 ElasticsearchConfiguration 类,会从配置文件中读取到对应的参数,接着申明一个 initRestClient 方法,返回的是一个 RestHighLevelClient,同时为它添加 @Bean(destroyMethod = "close") 注解,当 destroy 的时候做一个关闭,这个方法主要是如何初始化并创建一个 RestHighLevelClient

@Configuration
public class ElasticsearchConfiguration {@Value("${elasticsearch.host}")private String host;@Value("${elasticsearch.port}")private int port;@Value("${elasticsearch.connTimeout}")private int connTimeout;@Value("${elasticsearch.socketTimeout}")private int socketTimeout;@Value("${elasticsearch.connectionRequestTimeout}")private int connectionRequestTimeout;@Bean(destroyMethod = "close", name = "client")public RestHighLevelClient initRestClient() {RestClientBuilder builder = RestClient.builder(new HttpHost(host, port)).setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder.setConnectTimeout(connTimeout).setSocketTimeout(socketTimeout).setConnectionRequestTimeout(connectionRequestTimeout));return new RestHighLevelClient(builder);}
}

定义文档实体类

首先在 constant 包下定义常量接口,在接口中定义索引的名字为 user

public interface Constant {String INDEX = "user";
}

然后在 document 包下创建一个文档实体类:

public class UserDocument {private String id;private String name;private String sex;private Integer age;private String city;// 省略 getter/setter
}

ES 基本操作

在这里主要介绍 ES 的索引、文档、搜索相关的简单操作,在 service 包下创建 UserService 类。

索引操作

在这里演示创建索引和删除索引:

创建索引

在创建索引的时候可以在 CreateIndexRequest 中设置索引名称、分片数、副本数以及 mappings,在这里索引名称为 user,分片数 number_of_shards 为 1,副本数 number_of_replicas 为 0,具体代码如下所示:

public boolean createUserIndex(String index) throws IOException {CreateIndexRequest createIndexRequest = new CreateIndexRequest(index);createIndexRequest.settings(Settings.builder().put("index.number_of_shards", 1).put("index.number_of_replicas", 0));createIndexRequest.mapping("{\n" +"  \"properties\": {\n" +"    \"city\": {\n" +"      \"type\": \"keyword\"\n" +"    },\n" +"    \"sex\": {\n" +"      \"type\": \"keyword\"\n" +"    },\n" +"    \"name\": {\n" +"      \"type\": \"keyword\"\n" +"    },\n" +"    \"id\": {\n" +"      \"type\": \"keyword\"\n" +"    },\n" +"    \"age\": {\n" +"      \"type\": \"integer\"\n" +"    }\n" +"  }\n" +"}", XContentType.JSON);CreateIndexResponse createIndexResponse = client.indices().create(createIndexRequest, RequestOptions.DEFAULT);return createIndexResponse.isAcknowledged();
}

通过调用该方法,就可以创建一个索引 user,索引信息如下:

删除索引

DeleteIndexRequest 中传入索引名称就可以删除索引,具体代码如下所示:

public Boolean deleteUserIndex(String index) throws IOException {DeleteIndexRequest deleteIndexRequest = new DeleteIndexRequest(index);AcknowledgedResponse deleteIndexResponse = client.indices().delete(deleteIndexRequest, RequestOptions.DEFAULT);return deleteIndexResponse.isAcknowledged();
}

介绍完索引的基本操作,下面介绍文档的相关操作:

文档操作

在这里演示下创建文档、批量创建文档、查看文档、更新文档以及删除文档:

创建文档

创建文档的时候需要在 IndexRequest 中指定索引名称,id 如果不传的话会由 ES 自动生成,然后传入 source,具体代码如下:

public Boolean createUserDocument(UserDocument document) throws Exception {UUID uuid = UUID.randomUUID();document.setId(uuid.toString());IndexRequest indexRequest = new IndexRequest(Constant.INDEX).id(document.getId()).source(JSON.toJSONString(document), XContentType.JSON);IndexResponse indexResponse = client.index(indexRequest, RequestOptions.DEFAULT);return indexResponse.status().equals(RestStatus.OK);
}

下面通过调用这个方法,创建两个文档,具体内容如下:

批量创建文档

在一个 REST 请求中,重新建立网络开销是十分损耗性能的,因此 ES 提供 Bulk API,支持在一次 API 调用中,对不同的索引进行操作,从而减少网络传输开销,提升写入速率。

下面方法是批量创建文档,一个 BulkRequest 里可以添加多个 Request,具体代码如下:

public Boolean bulkCreateUserDocument(List<UserDocument> documents) throws IOException {BulkRequest bulkRequest = new BulkRequest();for (UserDocument document : documents) {String id = UUID.randomUUID().toString();document.setId(id);IndexRequest indexRequest = new IndexRequest(Constant.INDEX).id(id).source(JSON.toJSONString(document), XContentType.JSON);bulkRequest.add(indexRequest);}BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT);return bulkResponse.status().equals(RestStatus.OK);
}

下面通过该方法创建些文档,便于下面的搜索演示。

查看文档

查看文档需要在 GetRequest 中传入索引名称和文档 id,具体代码如下所示:

public UserDocument getUserDocument(String id) throws IOException {GetRequest getRequest = new GetRequest(Constant.INDEX, id);GetResponse getResponse = client.get(getRequest, RequestOptions.DEFAULT);UserDocument result = new UserDocument();if (getResponse.isExists()) {String sourceAsString = getResponse.getSourceAsString();result = JSON.parseObject(sourceAsString, UserDocument.class);} else {logger.error("没有找到该 id 的文档");}return result;
}

下面传入文档 id 调用该方法,结果如下所示:

更新文档

更新文档则是先给 UpdateRequest 传入索引名称和文档 id,然后通过传入新的 doc 来进行更新,具体代码如下:

public Boolean updateUserDocument(UserDocument document) throws Exception {UserDocument resultDocument = getUserDocument(document.getId());UpdateRequest updateRequest = new UpdateRequest(Constant.INDEX, resultDocument.getId());updateRequest.doc(JSON.toJSONString(document), XContentType.JSON);UpdateResponse updateResponse = client.update(updateRequest, RequestOptions.DEFAULT);return updateResponse.status().equals(RestStatus.OK);
}

下面将文档 id 为 9b8d9897-3352-4ef3-9636-afc6fce43b20 的文档的城市信息改为 handan,调用方法结果如下:

删除文档

删除文档只需要在 DeleteRequest 中传入索引名称和文档 id,然后执行 delete 方法就可以完成文档的删除,具体代码如下:

public String deleteUserDocument(String id) throws Exception {DeleteRequest deleteRequest = new DeleteRequest(Constant.INDEX, id);DeleteResponse response = client.delete(deleteRequest, RequestOptions.DEFAULT);return response.getResult().name();
}

介绍完文档的基本操作,接下来对搜索进行简单介绍:

搜索操作

简单的搜索操作需要在 SearchRequest 中设置将要搜索的索引名称(可以设置多个索引名称),然后通过 SearchSourceBuilder 构造搜索源,下面将 TermQueryBuilder 搜索查询传给 searchSourceBuilder,最后将 searchRequest 的搜索源设置为 searchSourceBuilder,执行 search 方法实现通过城市进行搜索,具体代码如下所示:

public List<UserDocument> searchUserByCity(String city) throws Exception {SearchRequest searchRequest = new SearchRequest();searchRequest.indices(Constant.INDEX);SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();TermQueryBuilder termQueryBuilder = QueryBuilders.termQuery("city", city);searchSourceBuilder.query(termQueryBuilder);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);return getSearchResult(searchResponse);
}

该方法的执行结果如图所示:

聚合搜索

聚合搜索就是给 searchSourceBuilder 添加聚合搜索,下面方法是通过 TermsAggregationBuilder 构造一个先通过城市就行分类聚合,其中还包括一个子聚合,是对年龄求平均值,然后在获取聚合结果的时候,可以使用通过在构建聚合时的聚合名称获取到聚合结果,具体代码如下所示:

public List<UserCityDTO> aggregationsSearchUser() throws Exception {SearchRequest searchRequest = new SearchRequest(Constant.INDEX);SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();TermsAggregationBuilder aggregation = AggregationBuilders.terms("by_city").field("city").subAggregation(AggregationBuilders.avg("average_age").field("age"));searchSourceBuilder.aggregation(aggregation);searchRequest.source(searchSourceBuilder);SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT);Aggregations aggregations = searchResponse.getAggregations();Terms byCityAggregation = aggregations.get("by_city");List<UserCityDTO> userCityList = new ArrayList<>();for (Terms.Bucket buck : byCityAggregation.getBuckets()) {UserCityDTO userCityDTO = new UserCityDTO();userCityDTO.setCity(buck.getKeyAsString());userCityDTO.setCount(buck.getDocCount());// 获取子聚合Avg averageBalance = buck.getAggregations().get("average_age");userCityDTO.setAvgAge(averageBalance.getValue());userCityList.add(userCityDTO);}return userCityList;
}

下面是执行该方法的结果:

到此为止,ES 的基本操作就简单介绍完了,大家可以多动手试试,不会的可以看下官方文档。

总结

本文的完整代码在 https://github.com/wupeixuan/SpringBoot-Learnelasticsearch 目录下。

Spring Boot 结合 ES 还是比较简单的,大家可以下载项目源码,自己在本地运行调试这个项目,更好地理解如何在 Spring Boot 中构建基于 ES 的应用。

有道无术,术可成;有术无道,止于术

欢迎大家关注Java之道公众号

好文章,我在看❤️

Spring Boot 集成 Elasticsearch 实战相关推荐

  1. 第 4-8 课:Spring Boot 集成 ElasticSearch

    ElasticSearch 是⼀个开源的搜索引擎,建⽴在⼀个全⽂搜索引擎库 Apache Lucene™ 基础之上. Lucene 可以说是当下最先进.⾼性能.全功能的搜索引擎库--⽆论是开源还是私有 ...

  2. springboot 单测加入参数_Spring Boot集成Elasticsearch实战分享

    作者|java梦想口服液|简书 最近有读者问我能不能写下如何使用 Spring Boot 开发 Elasticsearch(以下简称 ES) 相关应用,今天就讲解下如何使用 Spring Boot 结 ...

  3. spring boot集成Elasticsearch客户端

    spring boot整合Elasticsearch客户端 在spring boot程序应用中集成Elasticsearch客户端,并通过配置对连接进行管理. Elasticsearch的客户端Jav ...

  4. Spring Boot 集成 Elasticsearch

    Elasticsearch (简称ES) 是一个基于 Lucene 的分布式.高扩展.高实时的搜索与数据分析引擎.本章介绍 Spring Boot 应用集成 Elasticsearch ,通过 Spr ...

  5. Spring Boot 集成 ElasticSearch,实现高性能搜索

    1.ElasticSearch介绍 Elasticsearch 是java开发的,基于 Lucene 的搜索引擎.它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful Web接口.Elast ...

  6. spring boot集成Elasticsearch-SpringBoot(25)

    1. Elasticsearch-搜索应用服务器   1.1 什么是搜索引擎   搜索引擎(search engine )通常意义上是指:根据特定策略,运用特定的爬虫程序从互联网上搜集信息,然后对信息 ...

  7. Elasticsearch实战篇——Spring Boot整合ElasticSearch

    2019独角兽企业重金招聘Python工程师标准>>> 当前Spring Boot很是流行,包括我自己,也是在用Spring Boot集成其他框架进行项目开发,所以这一节,我们一起来 ...

  8. ElasticSearch实战篇 - Spring Boot 整合 ElasticSearch

    点击上方 Java后端,选择 设为星标 优质文章,及时送达 作者:冯文议 链接:segmentfault.com/a/1190000018625101 当前Spring Boot很是流行,包括我自己, ...

  9. ideal新建springboot工程_MyBatis初级实战之一:Spring Boot集成

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...

最新文章

  1. k8s mysql operator_将 MySQL 通过 presslabs/mysql-operator 部署到 k8s 内部
  2. jQuery使用手册
  3. 【java的多态性】
  4. 触发器代码(更新表A数据自动更新表B字段列)
  5. CEPH给用户创建读写权限
  6. android listview 横向滚动,Android支持水平滚动的ListView控件
  7. XNA中FPS统计刷新率频率类
  8. 前端学习(589):在console中调试日志
  9. 分数小数互换图_重复控制器学习心得(二)——超前环节的分数化和校正因子的引入...
  10. HTML学习笔记:让div在屏幕居中,图片在div里居中
  11. iOS设备中的推送(三):页面跳转
  12. 4固定在底部_有线鼠标之灵魂伴侣,火线竞技4号RGB鼠标线夹
  13. Word文档编辑技巧(一)
  14. msp430入门编程47
  15. IEEE期刊如何查找论文模板
  16. 2018年新浪微博产品笔试题目
  17. 用图形编程编写国际象棋游戏
  18. Python:混合动力汽车能量管理_动态规划简版(2/2)
  19. 别错过,教你如何用电脑玩手机
  20. 推荐的这22个高频 CLI 工具,确定不收藏吗?

热门文章

  1. python海贼王logo_Python 实现的下载op海贼王网的图片(网络爬虫)
  2. wxpython控件绑定事件_wxPython事件处理
  3. linux将所有文件生成lst_10行Python代码自动清理电脑内重复文件,解放双手!
  4. TraceView(profile) and Systrace
  5. mysql80连接不上本地服务器_小白教程:ubuntu服务器安装jupyter notebook, 并能够实现本地远程连接
  6. python 分类 投票_LightGBM——提升机器算法(图解+理论+安装方法+python代码)
  7. 十四、List,Set,Collection,Collections
  8. (计算机组成原理)第六章总线-第一节:总线概述(概念,分类,系统总线的结构和性能指标)
  9. 快速幂(求A^B的最后三位数表示的整数(A^B的含义是A的B次方))(java)
  10. Java 网络实例一(获取指定主机的IP地址、查看端口是否已使用、获取本机ip地址及主机名、获取远程文件大小)