前言 在使用springboot2.0.x
时,整合elasticsearch
,更多的是使用es提供的高级客户端RestHighLevelClient
。在elasticsearch8
后好多都被标注为过时了。
本文主要基于Springboot3
,对Elasticsearch
的索引、文档进行操作。版本信息如下:
1 2 3 JDK版本: JDK17 Springboot版本:3.0.2 Elasticsearch:8.5.3
PS: springboot
和Elasticsearch
的版本对应关系参考Spring官网-https://docs.spring.io/spring-data/elasticsearch/reference/elasticsearch/versions.html
前置工作
使用的是docker镜像,拉取镜像: docker pull elasticsearch:8.5.3
启动Elasticsearch
,将配置文件和插件目录都挂载到外部文件夹:
1 2 3 4 5 6 7 docker run --name elasticsearch --restart=always --privileged -p 9200:9200 -p 9300:9300 \ -e "discovery.type=single-node" \ -e ES_JAVA_OPTS="-Xms64m -Xmx128m" \ -v /mydata/elasticsearch/config/elasticsearch.yml:/usr/share/elasticsearch/config/elasticsearch.yml \ -v /mydata/elasticsearch/data:/usr/share/elasticsearch/data \ -v /mydata/elasticsearch/plugins:/usr/share/elasticsearch/plugins \ -d docker.elastic.co/elasticsearch/elasticsearch:8.5.3
es默认开启了SSL认证,可以修改配置文件或使用https访问9200端口,输入用户名和密码。为了方便,直接注掉下面配置文件,关闭安全认证:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 xpack.security.enabled: false xpack.security.enrollment.enabled: true xpack.security.http.ssl: enabled: false xpack.security.transport.ssl: enabled: false
重新启动即可
这里用的是GitHub提供的测试数据,GitHub链接:https://github.com/elastic/elasticsearch/blob/7.5/docs/src/test/resources/accounts.json
直接使用postman调用REST API创建索引和文档
创建索引,索引名为bank
POST请求: http://${IP}:9200/bank/
批量创建文档
PUT请求:http://${IP}:9200/bank/_bulk
请求体复制GitHub文件里面的数据就可以,如果请求报错,在请求体最后一行回车一下加个空行就行
测试
使用bank_search
查询数据看看插入成功没
整合Springboot 引入依赖:
1 2 3 4 <dependency > <groupId > org.springframework.boot</groupId > <artifactId > spring-boot-starter-data-elasticsearch</artifactId > </dependency >
添加配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 @Configuration public class MyElasticsearchConfiguration extends ElasticsearchConfiguration { @Value("${es.host}") private String url; @Override public @NotNull ClientConfiguration clientConfiguration () { return ClientConfiguration.builder() .connectedTo(url) .build(); } }
这样就可以了。。。
索引创建 新建一个实体类, 注解@Document
中有一个属性boolean createIndex() default true;
会自动创建索引。
注解Field
用来标注字段的类型、是否可以被搜索等。
并且可以指定作为id的字段,使用注解org.springframework.data.annotation.Id
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 import lombok.Data;import lombok.ToString;import org.springframework.data.elasticsearch.annotations.Document;import org.springframework.data.elasticsearch.annotations.Field;import org.springframework.data.elasticsearch.annotations.FieldType;@Data @Document(indexName = "bank") @ToString public class Balance { @Field(type = FieldType.Long, name = "account_number") @Id private long accountNumber; @Field(type = FieldType.Text) private String address; @Field(type = FieldType.Text) private String firstname; @Field(type = FieldType.Text) private String lastname; @Field(type = FieldType.Long) private long age; @Field(type = FieldType.Text) private String gender; @Field(type = FieldType.Text) private String employer; @Field(type = FieldType.Text) private String email; @Field(type = FieldType.Text) private String city; @Field(type = FieldType.Text) private String state; @Field(type = FieldType.Long) private long balance; }
使用ElasticsearchTemplate
Spring官网中描述了Spring对ES操作的一些接口定义,分别如下:
1 2 3 4 5 6 7 IndexOperations 索引操作,例如:创建、删除 DocumentOperations 文档操作,存储、基于id的更新、获取 SearchOperations 查询 ElasticsearchOperations 整合了文档和查询操作
而ElasticsearchTemplate
封装了所有ES操作。使用时只需注入即可
1 2 @Autowired ElasticsearchTemplate template;
索引 使用indexOps
方法获取索引操作对象IndexOperations
1 IndexOperations indexOperations = elasticsearchTemplate.indexOps(Balance.class);
判断索引是否存在
1 2 3 4 @Test void indexExistsTest () { Assertions.assertTrue(indexOperations.exists()); }
创建索引
1 2 3 4 @Test void indexCreateTest () { Assertions.assertTrue(indexOperations.create()); }
删除索引
1 2 3 4 @Test void indexDeleteTest () { Assertions.assertTrue(indexOperations.delete()); }
文档 使用save方法保存或更新文档 可以根据定义的ES的实体类,我们new一个对象并设置好属性值,然后调用save方法进行保存
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 @Test void saveMethodTest () { Balance balance = new Balance(); balance.setBalance(14000 ); balance.setCity("Shen Zhen" ); balance.setAge(25 ); balance.setEmail("xxx@github.com" ); balance.setAddress("Shennan Street" ); balance.setEmployer("none" ); balance.setFirstname("bryant" ); balance.setGender("gender" ); balance.setState("UT" ); balance.setLastname("kobe" ); balance.setAccountNumber(8888 ); Balance save = elasticsearchTemplate.save(balance); }
更新是一样的,指定对应ID,调用save方法即为更新。
使用delete方法删除文档 可以像Mysql那样传入Query
对象,根据条件进行删除,也可以直接指定Id,根据id删除文档。Query
后面再讲,这里只说根据id删除,直接调用方法即可
1 2 3 4 5 6 7 @Test void documentDeleteTest () { String deleteId = elasticsearchTemplate.delete("8888" , Balance.class); Assertions.assertEquals(deleteId, "8888" ); Balance balance = elasticsearchTemplate.get("8888" , Balance.class); Assertions.assertNull(balance); }
使用ElasticsearchRepoistory
作为Spring Data的一份子,自然可以使用JPA那一套,看源码,ElasticsearchRepoistory
继承了支持curd和分页排序的接口
1 2 3 4 5 6 7 8 9 10 11 12 13 @NoRepositoryBean public interface ElasticsearchRepository <T , ID > extends PagingAndSortingRepository <T , ID >, CrudRepository <T , ID > { Page<T> searchSimilar (T entity, @Nullable String[] fields, Pageable pageable) ; }
因此,也可以定义自己的接口,只需继承ElasticsearchRepository
即可, 因为我们指定了accountNumber
作为我们的id,所以泛型指定Long
, 根据某个字段查询一般都是findByxxx,具体用法参考JPA
1 2 3 4 5 6 7 8 public interface BalanceRepository extends ElasticsearchRepository <Balance , Long > { List<Balance> findByAddressLike (String address) ; }
接下来我们就可以按照JPA的规定直接保存、删除、获取
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 @Test void saveByRepoTest () { Balance balance = new Balance(); balance.setBalance(19999 ); balance.setCity("Canton" ); balance.setAge(25 ); balance.setEmail("xxx@gmail.com" ); balance.setAddress("Lin He Xi" ); balance.setEmployer("none" ); balance.setFirstname("Ng" ); balance.setGender("gender" ); balance.setState("UT" ); balance.setLastname("Ron" ); balance.setAccountNumber(6666 ); Balance save = balanceRepository.save(balance); Assertions.assertEquals(save, balance); } @Test void findByIdTest () { Optional<Balance> optional = balanceRepository.findById(6666L ); Assertions.assertTrue(optional.isPresent()); Balance balance = optional.get(); System.out.println(balance); } @Test void findByAddressLikeTest () { List<Balance> veterans = balanceRepository.findByAddressLike("Veterans" ); veterans.forEach(System.out::println); }
Spring官网介绍了几种不同的查询方式,都是实现了Query
接口,可以实现各种复杂的查询操作。下篇再讲~