Spring Boot 集成 Elasticsearch(含 ElasticsearchRestTemplate 示例)_springboot elasticsearch
Elasticsearch 是一个基于 Lucene 的分布式搜索服务器,具有高效的全文检索能力。在现代应用中,尤其是需要强大搜索功能的系统中,Elasticsearch 被广泛使用。
Spring Boot 提供了对 Elasticsearch 的集成支持,使得开发者可以轻松地将 Elasticsearch 集成到 Spring Boot 应用中,实现高效的搜索、分析等功能。本文将详细介绍如何在 Spring Boot 中集成 Elasticsearch,并展示一些基本的使用示例以及通过 ElasticsearchRestTemplate
实现的高级功能。
一、准备工作
1. 安装 Elasticsearch
你可以通过以下方式安装 Elasticsearch:
- 使用 Docker 安装:
docker run -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co/elasticsearch/elasticsearch:8.11.3
- 直接下载安装包:Elasticsearch 下载页面
确保 Elasticsearch 成功启动后,可以通过浏览器访问 http://localhost:9200
查看其状态信息。
二、创建 Spring Boot 项目
使用 Spring Initializr 创建一个 Spring Boot 项目,选择以下依赖:
- Spring Web
- Spring Data Elasticsearch
或者手动在 pom.xml
中添加如下依赖(适用于 Maven 项目):
<dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-elasticsearch</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <scope>provided</scope> </dependency></dependencies>
三、配置 Elasticsearch
在 application.yml
或 application.properties
中配置 Elasticsearch 连接信息:
spring: elasticsearch: rest: uris: http://localhost:9200
如果你使用的是较老版本的 Spring Boot,可能需要手动配置 RestHighLevelClient
,但在新版本中已默认使用 ElasticsearchRestTemplate
和 RestClient
。
四、定义实体类
我们先定义一个简单的实体类,并使用注解来映射 Elasticsearch 索引结构。
import org.springframework.data.annotation.Id;import org.springframework.data.elasticsearch.annotations.Document;import org.springframework.data.elasticsearch.annotations.Field;import org.springframework.data.elasticsearch.annotations.FieldType;@Document(indexName = \"blog-post\", shards = 1)public class BlogPost { @Id private String id; @Field(type = FieldType.Text, analyzer = \"ik_max_word\") private String title; @Field(type = FieldType.Text, analyzer = \"ik_max_word\") private String content; // 构造方法、getter/setter 省略}
注意:如果使用中文分词,建议使用
ik-analyzer
插件,在 Elasticsearch 中安装后指定analyzer
。
五、定义 Repository 接口
Spring Data 提供了 ElasticsearchRepository
接口,我们可以继承它来操作文档。
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;public interface BlogPostRepository extends ElasticsearchRepository<BlogPost, String> {}
六、编写 Service 层
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import java.util.List;import java.util.Optional;@Servicepublic class BlogPostService { @Autowired private BlogPostRepository blogPostRepository; public BlogPost save(BlogPost blogPost) { return blogPostRepository.save(blogPost); } public Optional<BlogPost> findById(String id) { return blogPostRepository.findById(id); } public Iterable<BlogPost> findAll() { return blogPostRepository.findAll(); } public void deleteById(String id) { blogPostRepository.deleteById(id); } public List<BlogPost> searchByTitle(String title) { return blogPostRepository.findByTitle(title); }}
七、编写 Controller 层
import org.springframework.beans.factory.annotation.Autowired;import org.springframework.web.bind.annotation.*;import java.util.List;@RestController@RequestMapping(\"/api/blog-posts\")public class BlogPostController { @Autowired private BlogPostService blogPostService; @PostMapping public BlogPost create(@RequestBody BlogPost blogPost) { return blogPostService.save(blogPost); } @GetMapping(\"/{id}\") public BlogPost get(@PathVariable String id) { return blogPostService.findById(id).orElse(null); } @GetMapping public Iterable<BlogPost> getAll() { return blogPostService.findAll(); } @DeleteMapping(\"/{id}\") public void delete(@PathVariable String id) { blogPostService.deleteById(id); } @GetMapping(\"/search\") public List<BlogPost> search(@RequestParam String title) { return blogPostService.searchByTitle(title); }}
八、补充内容:使用 ElasticsearchRestTemplate
除了使用 Repository,我们还可以通过 ElasticsearchRestTemplate
来执行更复杂的查询、聚合、高亮等操作。
1. 注入 ElasticsearchRestTemplate
@Autowiredprivate ElasticsearchRestTemplate elasticsearchRestTemplate;
2. 构建基本查询(Match 查询)
import org.springframework.data.elasticsearch.core.query.Criteria;import org.springframework.data.elasticsearch.core.query.CriteriaQuery;public List<BlogPost> searchByTitleWithTemplate(String keyword) { Criteria criteria = new Criteria(\"title\").is(keyword); CriteriaQuery query = new CriteriaQuery(criteria); SearchHits<BlogPost> hits = elasticsearchRestTemplate.search(query, BlogPost.class); return hits.stream() .map(SearchHit::getContent) .collect(Collectors.toList());}
3. 使用 NativeSearchQueryBuilder 构建复杂查询
import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.index.query.MatchQueryBuilder;import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;import org.springframework.data.elasticsearch.core.query.SearchQuery;public List<BlogPost> searchByContentWithMatchQuery(String keyword) { MatchQueryBuilder matchQueryBuilder = QueryBuilders.matchQuery(\"content\", keyword); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQueryBuilder) .build(); SearchHits<BlogPost> hits = elasticsearchRestTemplate.search(searchQuery, BlogPost.class); return hits.stream() .map(SearchHit::getContent) .collect(Collectors.toList());}
4. 聚合查询(Aggregation)
import org.elasticsearch.index.aggregation.AggregationBuilders;import org.elasticsearch.index.aggregation.bucket.terms.TermsAggregationBuilder;public void aggregateKeywordsInTitle() { TermsAggregationBuilder aggregation = AggregationBuilders.terms(\"keywords\") .field(\"title.keyword\") // 注意字段类型应为 keyword .size(10); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withAggregations(aggregation) .build(); SearchHits<BlogPost> hits = elasticsearchRestTemplate.search(searchQuery, BlogPost.class); Terms keywordsAgg = hits.getAggregations().get(\"keywords\"); for (Terms.Bucket entry : keywordsAgg.getBuckets()) { System.out.println(entry.getKey() + \":\" + entry.getDocCount()); }}
5. 高亮显示匹配内容
import org.elasticsearch.index.highlight.HighlightBuilder;import org.springframework.data.elasticsearch.core.query.HighlightQuery;public List<BlogPost> searchWithHighlight(String keyword) { HighlightBuilder highlightBuilder = new HighlightBuilder(); highlightBuilder.field(\"content\"); // 对 content 字段进行高亮 highlightBuilder.preTags(\"\").postTags(\"\"); MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(\"content\", keyword); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery) .withHighlightBuilder(highlightBuilder) .build(); SearchHits<BlogPost> hits = elasticsearchRestTemplate.search(searchQuery, BlogPost.class); return hits.stream().map(hit -> { Map<String, List<String>> highlightFields = hit.getHighlightFields(); if (highlightFields.containsKey(\"content\")) { String highlightedContent = String.join(\"...\", highlightFields.get(\"content\")); hit.getContent().setContent(highlightedContent); // 替换内容为高亮版本 } return hit.getContent(); }).collect(Collectors.toList());}
6. 分页查询
public List<BlogPost> searchWithPagination(String keyword, int page, int size) { MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(\"title\", keyword); SearchQuery searchQuery = new NativeSearchQueryBuilder() .withQuery(matchQuery) .withPageable(PageRequest.of(page, size)) .build(); SearchHits<BlogPost> hits = elasticsearchRestTemplate.search(searchQuery, BlogPost.class); return hits.stream().map(SearchHit::getContent).collect(Collectors.toList());}
九、测试 API
你可以使用 Postman 或 curl 测试以下接口:
POST /api/blog-posts
:创建一篇博客GET /api/blog-posts/{id}
:获取某篇博客GET /api/blog-posts
:获取所有博客DELETE /api/blog-posts/{id}
:删除博客GET /api/blog-posts/search?title=xxx
:按标题搜索博客- 更多通过
ElasticsearchRestTemplate
支持的高级查询也可以通过新增接口调用。
十、总结
本文详细介绍了如何在 Spring Boot 项目中集成 Elasticsearch,并实现了基本的增删改查操作。同时,通过 ElasticsearchRestTemplate
展示了构建复杂查询、聚合、高亮、分页等高级功能的方式。
通过 Spring Data Elasticsearch 提供的抽象,我们可以非常方便地进行数据持久化和检索。而 ElasticsearchRestTemplate
则为我们提供了更灵活的底层控制能力,非常适合用于构建企业级搜索功能。
参考资料
- Spring Data Elasticsearch 官方文档
- Elasticsearch 官网
- IK Analyzer GitHub