Spring Data Elasticsearch 是 Spring Data 项目的一部分,该项目旨在为新数据存储提供熟悉且一致的基于 Spring 的编程模型,同时保留特定于存储的功能。Spring Data Elasticsearch 项目提供了与 Elasticsearch 搜索引擎的集成。 Spring Data Elasticsearch 的关键功能区域是一个以 POJO 为中心的模型,该模型用于与 Elastichsearch 文档进行交互并轻松编写存储库样式的数据访问层。 从 Elasticsearch 7 开始不推荐使用 TransportClient,并将在 Elasticsearch 8 中将其删除。Spring Data Elasticsearch 也支持 TransportClient,前提是使用的 Elasticsearch 中可用,Spring Data Elasticsearch 从 4.0 版本开始已弃用使用 TransportClient 的类。现在 High Level REST Client 是 Elasticsearch 的默认客户端,它在接受并返回完全相同的请求/响应对象时直接替代 TransportClient。
<properties>
<!-- Spring Boot 与自己使用的 ES 版本不一致时配置对应的版本 -->
<elasticsearch.version>7.10.2</elasticsearch.version>
</properties>
<dependencies>
<!-- Spring Boot ES 启动依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
</dependencies>
spring:
elasticsearch:
rest:
uris: 127.0.0.1:9200
# 如下配置也可
spring:
data:
elasticsearch:
client:
reactive:
endpoints: 127.0.0.1:9200
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc 数据实体类
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
@Document(indexName = "my_book")
public class Book {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_smart")
private String title;
@Field(type = FieldType.Keyword)
private String author;
@Field(type = FieldType.Text, analyzer = "ik_smart")
private String desc;
@Field(type = FieldType.Integer)
private Integer pageNum;
@Field(type = FieldType.Date)
private Date createDate;
}
注解 | 说明 |
---|---|
@Document | 作用在类,标记实体类为文档对象 indexName:对应索引库名称 type:对应在索引库中的类型,8.x 将删除 shards:分片数量,默认 5 replicas:副本数量,默认 1 |
@Id | 作用在成员变量,标记一个字段作为 id 主键 |
@Field | 作用在成员变量,标记为文档的字段,并指定字段映射属性: type:字段类型,是枚举:FieldType,可以是 text、long、short、date、integer、object 等 index:是否索引,布尔类型,默认是true store:是否存储,布尔类型,默认是 false analyzer:分词器名称 |
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc 演示
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void create() {
// 根据 @Document 注解创建索引
elasticsearchRestTemplate.createIndex(Book.class);
// 更具 @Field 注解创建 Mapping
elasticsearchRestTemplate.putMapping(Book.class);
}
@Test
public void delete() {
// 根据字节码删除
elasticsearchRestTemplate.deleteIndex(Book.class);
// 根据索引名删除
elasticsearchRestTemplate.deleteIndex("my_book");
}
}
ElasticsearchRestTemplate 是 Spring Data Elasticsearch 项目中的一个类,和其他 spring 项目中的 template 类似。在新版的 Spring Data Elasticsearch 中,ElasticsearchRestTemplate 代替了原来的 ElasticsearchTemplate。原因是 ElasticsearchTemplate 基于 TransportClient,TransportClient 即将在 8.x 以后的版本中移除。ElasticsearchRestTemplate 基于 RestHighLevelClient,如果不手动配置 ElasticsearchRestTemplate 将使用默认配置的 RestHighLevelClientbaen,此时 ES 服务器应当使用默认 9200 端口。
在上一节的演示中我们使用了 template 的创建、删除索引等操作,其实这些操作已经不被推荐使用,若下图所示,已经加上删除线了。这些操作其实是 ElasticsearchTemplate 的过度,在 ElasticsearchRestTemplate 中不需要我们自己去创建索引,首次创建 ElasticsearchRestTemplate 时会帮我们自动根据实体类来创建索引。
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc ElasticsearchRestTemplate 添加文档
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void save() {
// 准备数据,id 相同即为修改
Book book = new Book(Long.parseLong("1"), "民法典", "人大", "666666", 100, new Date());
elasticsearchRestTemplate.save(book);
}
}
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc ElasticsearchRestTemplate 删除文档
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void delete() {
// 准备数据
Book book = new Book(Long.parseLong("1"), "民法典", "人大", "666", 100, new Date());
// 根据对象删除数据
elasticsearchRestTemplate.delete(book);
// 根据 id + Class 删除数据
elasticsearchRestTemplate.delete("1", Book.class);
}
}
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc ElasticsearchRestTemplate 条件查询
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;
@Test
public void search() {
/*
* 设置 bool 查询
* ① 设置查询 BoolQueryBuilder
* ② 关键词 must(AND), mustNot(NOT), should(OR)
* ③ 查询条件 MatchQueryBuilder 分词查询, TermQueryBuilder 不分词查询
*/
BoolQueryBuilder boolQueryBuilder = new BoolQueryBuilder().must(new MatchQueryBuilder("title", "民法典"));
/*
* 设置总查询
* ① 设置查询 NativeSearchQueryBuilder
* ② 设置查询条件 withQuery(BoolQueryBuilder boolQueryBuilder)
* ③ 设置高亮 withHighlightFields(new HighlightBuilder.Field("name").preTags(preTag).postTags(postTag))
*/
NativeSearchQuery nativeSearchQuery = new NativeSearchQueryBuilder().withQuery(boolQueryBuilder).build();
// 查询
SearchHits<Book> searchHits = elasticsearchRestTemplate.search(nativeSearchQuery, Book.class);
// 遍历查询结果
for (SearchHit<Book> searchHit : searchHits) {
Book book = searchHit.getContent();
System.out.println(book);
}
}
}
前文讲了 ElasticsearchRestTemplate 的简单操作,但是我更喜欢使用 ElasticsearchRepository 它的用法与 SringDataJpa 十分类似。我们只需要写一个 repository 接口继承它就可以使用以下方法去操作 ES。
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc //TODO
*/
@Repository
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
}
与 ElasticsearchRestTemplate 一样,不需要我们自己去创建索引。调用 save 方法,id 重复则为修改,id 不同则为新增。调用 deleteById 方法根据 id 删除文档。调用 existsById 方法根据 id 判断文档是否存在。调用 findAll 方法查询所有文档。
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc BookRepository
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private BookRepository bookRepository;
@Test
public void save() {
Book book = new Book(Long.parseLong("1"), "斗破苍穹", "天蚕土豆", "斗气的世界", 100, new Date());
bookRepository.save(book);
}
@Test
public void exist() {
System.out.println(bookRepository.existsById(Long.parseLong("4")));
}
@Test
public void delete() {
bookRepository.deleteById(Long.parseLong("4"));
}
@Test
public void findAll() {
Iterable<Book> books = bookRepository.findAll();
for (Book book : books) {
System.out.println(book);
}
}
}
关键字 | 使用示例 | ES 查询 |
---|---|---|
And | findByNameAndPrice | { “bool” : { “must” : [ { “field” : { “name” : “?” }}, { “field” : { “price” : “?” }} ] }} |
Or | findByNameOrPrice | { “bool” : { “should” : [ { “field” : { “name” : “?” }}, { “field” : { “price” : “?” }} ] }} |
Is | findByName | { “bool” : { “must” : [ { “field” : { “name” : “?” }} ] }} |
Not | findByNameNot | { “bool” : { “must_not” : [ { “field” : { “name” : “?” }} ] }} |
Between | findByPriceBetween | { “bool” : { “must” : { “range” : { “price” : {“from” : ?,“to” : ?,“include_lower” : true,“include_upper” : true} } } }} |
LessThanEqual | findByPriceLessThan | { “bool” : { “must” : { “range” : { “price” : {“from” : null,“to” : ?,“include_lower” : true,“include_upper” : true} } } }} |
GreaterThanEqual | findByPriceGreaterThan | { “bool” : { “must” : { “range” : { “price” : {“from” : ?,“to” : null,“include_lower” : true,“include_upper” : true} } } }} |
Before | findByPriceBefore | { “bool” : { “must” : { “range” : { “price” : {“from” : null,“to” : ?,“include_lower” : true,“include_upper” : true} } } }} |
After | findByPriceAfter | { “bool” : { “must” : { “range” : { “price” : {“from” : ?,“to” : null,“include_lower” : true,“include_upper” : true} } } }} |
Like | findByNameLike | { “bool” : { “must” : { “field” : {“name” : {“query” : “?*”,“analyze_wildcard” : true} } } }} |
StartingWith | findByNameStartingWith | { “bool” : { “must” : { “field” : {“name” : {“query” : “?*”,“analyze_wildcard” : true} } } }} |
EndingWith | findByNameEndingWith | { “bool” : { “must” : { “field” : {“name” : {“query” : “*?”,“analyze_wildcard” : true} } } }} |
Contains/Containing | findByNameContaining | { “bool” : { “must” : { “field” : {“name” : {“query” : “?”,“analyze_wildcard” : true} } } }} |
In | findByNameIn(Collectionnames) | { “bool” : { “must” : { “bool” : { “should” : [ {“field” : {“name” : “?”}}, {“field” : {“name” : “?”}} ] } } }} |
NotIn | findByNameNotIn(Collectionnames) | { “bool” : {“must_not” : {“bool” : {“should” : {“field” : {“name” : “?”}}}}}}{ “bool” : { “must_not” : { “bool” : { “should” : [ {“field” : {“name” : “?”}}, {“field” : {“name” : “?”}} ] } } }} |
True | findByAvailableTrue | { “bool” : { “must” : { “field” : {“available” : true} } }} |
False | findByAvailableFalse | { “bool” : { “must” : { “field” : {“available” : false} } } |
OrderBy | findByAvailableTrueOrderByNameDesc | { “sort” : [ { “name” : {“order” : “desc”} } ], “bool” : { “must” : { “field” : {“available” : true} } }} |
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc //TODO
*/
@Repository
public interface BookRepository extends ElasticsearchRepository<Book, Long> {
List<Book> findByTitle(String title);
}
/**
* @author Demo_Null
* @version 1.0
* @date 2021/2/4
* @desc 扩展查询示例
*/
@SpringBootTest
public class SpringDataEsTest {
@Autowired
private BookRepository bookRepository;
@Test
public void find() {
List<Book> books = bookRepository.findByTitle("斗");
for (Book book : books) {
System.out.println(book);
}
}
}
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有