Spring Boot整合Elasticsearch
Elasticsearch是一个全文搜索引擎,专门用于处理大型数据集。根据描述,自然而然使用它来存储和搜索应用程序日志。与Logstash和Kibana一起,它是强大的解决方案Elastic Stack的一部分,我之前的一些文章中已经对此进行了描述。
保留应用程序日志不是Elasticsearch的唯一使用场景。它通常用作应用程序的辅助数据库,是一个主关系数据库。如果您必须对大型数据集执行全文搜索或仅存储应用程序不再修改的许多历史记录,这个方法尤其有用。当然,该方法也有优缺点。当您使用包含相同数据的两个不同数据源时,您必须首先考虑同步。你有几个选择:根据关系数据库供应商,您可以利用二进制或事务日志,其中包含SQL更新的历史记录。这种方法需要一些中间件来读取日志,然后将数据放入Elasticsearch。您始终可以将整个职责移至数据库端(触发器)或Elasticsearch端(JDBC插件)。
无论您如何将数据导入Elasticsearch,都必须考虑另一个问题:数据结构。关系数据库中的数据可能分布在几个表之间。如果您想利用Elasticsearch,您应该将其存储为单一类型。它会强制您保留冗余数据,这会导致更大的磁盘空间使用量。当然,如果Elasticsearch查询比等效的关系数据库中的查询能更快,那么这种影响是可以接受的。
好的,在长时间的介绍之后继续这个例子。 Spring Boot提供了一种通过Spring Data存储库与Elasticsearch进行交互的简便方法。
1 启用Elasticsearch支持
按照Spring Boot的惯例,我们不必在上下文中提供任何bean来启用对Elasticsearch的支持。我们只需要在pom.xml中添加以下依赖项:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-elasticsearch</artifactId></dependency>
默认情况下,应用程序尝试在localhost上与Elasticsearch连接。如果我们使用另一个目标URL,我们需要在配置设置中覆盖它。这是我们的application.yml文件的片段,它覆盖了默认的集群名称和地址,以及在Docker容器上启动的Elasticsearch的地址:
spring:data:elasticsearch:cluster-name: docker-clustercluster-nodes: 192.168.99.100:9300
应用程序可以通过Spring Boot Actuator health端点监测Elasticsearch连接的运行状况。首先,您需要添加以下Maven依赖项:
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency>
默认情况下启用Healthcheck,并自动配置Elasticsearch检查。但是,这验证是通过Elasticsearch Rest API客户端执行的。在这种情况下,我们需要覆盖属性spring.elasticsearch.rest.uris-负责设置REST客户端使用的地址:
spring:elasticsearch:rest:uris: http://192.168.99.100:9200
2 运行 Elasticsearch
对于我们的测试,我们需要在开发模式下运行单节点Elasticsearch实例。像往常一样,我们将使用Docker容器。这是Docker容器启动并在9200和9300端口上公开的命令。
$ docker run -d --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:6.6.2
3 构建Spring Data库
要启用Elasticsearch存储库,我们只需要使用@EnableElasticsearchRepositories注释主类或配置类:
@SpringBootApplication@EnableElasticsearchRepositoriespublic class SampleApplication { ... }
下一步是创建扩展CrudRepository的存储库接口。它提供了一些基本操作,如save或findById。如果您想要一些额外的find方法,您应该在跟随Spring Data命名规范在接口内定义新方法。
public interface EmployeeRepository extends CrudRepository<Employee, Long> {List<Employee> findByOrganizationName(String name);List<Employee> findByName(String name);}
4 构建文档
我们的实体关系结构平铺为包含相关对象(组织,部门)的单个Employee对象。您可以将此方法与在RDBMS中为相关表组创建视图进行比较。在Spring Data Elasticsearch命名法中,单个对象存储为文档。因此,需要使用@Document注释对象。您还应该为Elasticsearch设置目标索引的名称,类型和ID。可以使用@Field注解配置其他映射。
@Document(indexName = "sample", type = "employee")public class Employee {@Idprivate Long id;@Field(type = FieldType.Object)private Organization organization;@Field(type = FieldType.Object)private Department department;private String name;private int age;private String position;// Getters and Setters ...}
5 初始化数据
正如在前言中提到的,您可能决定使用Elasticsearch的主要原因是需要处理大数据。因此,最好使用大量文档填充我们的测试Elasticsearch节点。如果您想在一步就插入许多文档,那么您一定要使用Bulk API。bulk API使得在单个API调用中执行许多索引/删除操作成为可能。这可以大大提高索引速度。可以使用Spring Data ElasticsearchTemplate bean执行批量操作。它在Spring Boot上也可以自动配置。 Template提供了bulkIndex方法,该方法将索引查询列表作为输入参数。这是在应用程序启动时插入样本测试数据的bean的实现:
public class SampleDataSet {private static final Logger LOGGER = LoggerFactory.getLogger(SampleDataSet.class);private static final String INDEX_NAME = "sample";private static final String INDEX_TYPE = "employee";@AutowiredEmployeeRepository repository;@AutowiredElasticsearchTemplate template;@PostConstructpublic void init() {for (int i = 0; i < 10000; i++) {bulk(i);}}public void bulk(int ii) {try {if (!template.indexExists(INDEX_NAME)) {template.createIndex(INDEX_NAME);}ObjectMapper mapper = new ObjectMapper();List<IndexQuery> queries = new ArrayList<>();List<Employee> employees = employees();for (Employee employee : employees) {IndexQuery indexQuery = new IndexQuery();indexQuery.setId(employee.getId().toString());indexQuery.setSource(mapper.writeValueAsString(employee));indexQuery.setIndexName(INDEX_NAME);indexQuery.setType(INDEX_TYPE);queries.add(indexQuery);}if (queries.size() > 0) {template.bulkIndex(queries);}template.refresh(INDEX_NAME);LOGGER.info("BulkIndex completed: {}", ii);} catch (Exception e) {LOGGER.error("Error bulk index", e);}}// sample data set implementation ...}
如果您不需要在启动时插入数据,则可以通过将属性initial-import由enabled转变为false来禁用该过程。这是SampleDataSet bean的声明:
@Bean@ConditionalOnProperty("initial-import.enabled")public SampleDataSet dataSet() {return new SampleDataSet();}
6 查看数据和运行查询
假设您已经启动了示例应用程序,负责扩充索引的bean没有被禁用,并且有足够的耐心等待几个小时,直到所有数据都插入到Elasticsearch节点中,现在它包含100M的员工类型文档。显示集群有关的一些信息是值得的。您可以使用Elasticsearch查询来执行此操作,也可以下载一个可用的GUI工具,例如ElasticHQ。碰巧的是,ElasticHQ也可以作为Docker容器使用。您必须执行以下命令才能启动ElasticHQ容器:
$ docker run -d --name elastichq -p 5000:5000 elastichq/elasticsearch-hq
启动ElasticHQ后,Web浏览器通过端口5000访问GUI。它的Web控制台提供有关集群,索引和允许执行查询的基本信息。您只需要输入Elasticsearch节点地址,您将被重定向到带有统计信息的主仪表盘。这是ElasticHQ的主仪表盘。
如您所见,我们有一个名为sample的索引,分为5个分片。这是Spring Data @Document提供的默认值,可以使用分片字段覆盖它。点击后我们可以导航到索引管理面板。您可以对索引执行某些操作例如清除缓存或刷新索引等。您还可以查看所有分片的统计信息。
出于当前的测试目的,我有大约25M(约3GB的空间)Employee类型的文档。我们可以执行一些测试查询。我已经公开了两个用于搜索的端点:按员工姓名GET/employees/{name}和组织名称GET/employees / organization / {organizationName}。结果并不是压倒性的。我认为关系数据库使用相同数量的数据也可以获得相同的结果。
7 测试
好的,我们已经完成了开发并对大型数据集进行了一些手动测试。现在,是时候创建一些在构建时运行的集成测试了。我们可以使用允许在JUnit测试期间自动启动数据库的Docker容器的库 - Testcontainers。有关此库的更多信息,请参阅其站点https://www.testcontainers.org或我以前的一篇文章:使用Testcontainers Framework测试Spring与Vault和Postgres的集成。幸运的是,Testcontainers支持Elasticsearch。要在测试范围内启用它,首先需要在pom.xml中添加以下依赖项:
<dependency><groupId>org.testcontainers</groupId><artifactId>elasticsearch</artifactId><version>1.11.1</version><scope>test</scope></dependency>
下一步是定义指向Elasticsearch容器的@ClassRule或@Rule bean。它在测试类之前或每个依赖使用的注释之前自动启动。公开的端口号是自动生成的,因此您需要将其设置为spring.data.elasticsearch.cluster-nodes属性的值。这是我们的JUnit集成测试的完整实现:
@RunWith(SpringRunner.class)@SpringBootTest@FixMethodOrder(MethodSorters.NAME_ASCENDING)public class EmployeeRepositoryTest {@ClassRulepublic static ElasticsearchContainer container = new ElasticsearchContainer();@AutowiredEmployeeRepository repository;@BeforeClasspublic static void before() {System.setProperty("spring.data.elasticsearch.cluster-nodes", container.getContainerIpAddress() + ":" + container.getMappedPort(9300));}@Testpublic void testAdd() {Employee employee = new Employee();employee.setId(1L);employee.setName("John Smith");employee.setAge(33);employee.setPosition("Developer");employee.setDepartment(new Department(1L, "TestD"));employee.setOrganization(new Organization(1L, "TestO", "Test Street No. 1"));employee = repository.save(employee);Assert.assertNotNull(employee);}@Testpublic void testFindAll() {Iterable<Employee> employees = repository.findAll();Assert.assertTrue(employees.iterator().hasNext());}@Testpublic void testFindByOrganization() {List<Employee> employees = repository.findByOrganizationName("TestO");Assert.assertTrue(employees.
Spring Boot整合Elasticsearch的更多相关文章
- 【spring boot】【elasticsearch】spring boot整合elasticsearch,启动报错Caused by: java.lang.IllegalStateException: availableProcessors is already set to [8], rejecting [8
spring boot整合elasticsearch, 启动报错: Caused by: java.lang.IllegalStateException: availableProcessors ], ...
- Elasticsearch学习(3) spring boot整合Elasticsearch的原生方式
前面我们已经介绍了spring boot整合Elasticsearch的jpa方式,这种方式虽然简便,但是依旧无法解决我们较为复杂的业务,所以原生的实现方式学习能够解决这些问题,而原生的学习方式也是E ...
- Spring Boot 整合 Elasticsearch,实现 function score query 权重分查询
摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢! 『 预见未来最好的方式就是亲手创造未来 – <史蒂夫·乔布斯传> 』 运行环境: ...
- spring boot 整合 elasticsearch 5.x
spring boot与elasticsearch集成有两种方式.一种是直接使用elasticsearch.一种是使用data中间件. 本文只指针使用maven集成elasticsearch 5.x, ...
- Spring Boot 整合 elasticsearch
一.简介 我们的应用经常需要添加检索功能,开源的 ElasticSearch 是目前全文搜索引擎的 首选.他可以快速的存储.搜索和分析海量数据.Spring Boot通过整合Spring Data E ...
- Elasticsearch学习(1) Spring boot整合Elasticsearch
本文的Spring Boot版本为1.5.9,Elasticsearch版本为2.4.4,话不多说,直接上代码. 一.启动Elasticsearch 在官网上下载Elasticsearch后,打开bi ...
- Spring Boot整合ElasticSearch和Mysql 附案例源码
导读 前二天,写了一篇ElasticSearch7.8.1从入门到精通的(点我直达),但是还没有整合到SpringBoot中,下面演示将ElasticSearch和mysql整合到Spring Boo ...
- Elasticsearch学习(4) spring boot整合Elasticsearch的聚合操作
之前已将spring boot原生方式介绍了,接下将结介绍的是Elasticsearch聚合操作.聚合操作一般来说是解决一下复杂的业务,比如mysql中的求和和分组,由于博主踩的坑比较多,所以博客可能 ...
- spring boot 整合elasticsearch
1.导入jar包 <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncodi ...
随机推荐
- Ajax - Apache安装配置
apache安装配置 1.安装wamp2.配置根路径3.默认的网站根路径是安装目录的www子目录,如果不想使用默认目录,可以自己配置.配置方式如下: --找到文件wamp\bin\apache\Apa ...
- SQL Server一致性错误修复案例总结
今天遇到了一个关于数据库一致性错误的案例.海外工厂的一台SQL Server 2005(9.00.5069.00 Standard Edition)数据库在做DBCC CHECKDB的时候出现了一致性 ...
- C#中++i与i++的区别
日常编程中经常用到++i与i++,知识点虽然很小,但有时候会犯迷糊,在这里小小的记录一下. ++i 即前递增,顾名思义也就是先自增后传值: 举个栗子 int i=5; int j=++i; 此时i的值 ...
- Web Storage:浏览器端数据储存机制
目录 概述 操作方法 存入/读取数据 清除数据 遍历操作 storage事件 参考链接 概述 这个API的作用是,使得网页可以在浏览器端储存数据.它分成两类:sessionStorage和localS ...
- apache ranger源码编译
官方文档 http://ranger.apache.org/quick_start_guide.html Quick Start Guide Build Process 1. Check out th ...
- 【转】C# 定时器事件(设置时间间隔,间歇性执行某一函数,控制台程序)
using System.Timers;定时器事件代码 static void Main(string[] args) { Method(); #region 定时器事件 Timer aTimer = ...
- springMVC 实现redis分布式锁
1.先配置spring-data-redis 首先是依赖 <dependency> <groupId>org.springframework.data</groupId& ...
- Vue (二) --- Vue对象提供的属性功能
--------------------------------------------不是井里没有水,而是你挖的不够深. 3. Vue对象提供的属性功能 3.1 过滤器 过滤器,就是vue允许开发者 ...
- EasyUI的Datagrid鼠标悬停显示单元格内容
功能描述:table鼠标悬停显示单元格内容 1.js函数 function hoveringShow(value) { return "<span title='" + va ...
- Quick Sort(三向切分的快速排序)(Java)
//三向切分的快速排序 //这种切分方法对于数组中有大量重复元素的情况有比较大的性能提升 public static void main(String[] args) { Scanner input ...