10分钟上手Elasticsearch:芋道云平台全文检索实战指南
你是否还在为系统中的搜索功能发愁?用户抱怨找不到想要的内容,简单的数据库模糊查询效率低下且体验糟糕?本文将带你一文解决这些痛点,通过芋道云(yudao-cloud)平台的Elasticsearch集成方案,快速实现高效、精准的全文检索功能。读完本文你将学到:- 如何在芋道云平台中快速集成Elasticsearch- 核心配置文件的修改方法- 索引创建与数据同步的实现步骤- 实战案例:商...
10分钟上手Elasticsearch:芋道云平台全文检索实战指南
你是否还在为系统中的搜索功能发愁?用户抱怨找不到想要的内容,简单的数据库模糊查询效率低下且体验糟糕?本文将带你一文解决这些痛点,通过芋道云(yudao-cloud)平台的Elasticsearch集成方案,快速实现高效、精准的全文检索功能。
读完本文你将学到:
- 如何在芋道云平台中快速集成Elasticsearch
- 核心配置文件的修改方法
- 索引创建与数据同步的实现步骤
- 实战案例:商品搜索功能的完整实现
为什么选择Elasticsearch?
在传统的系统开发中,我们常常使用数据库的LIKE语句进行搜索,但这种方式存在明显的局限性:
- 性能问题:LIKE '%关键词%' 会导致全表扫描,数据量大时查询缓慢
- 功能有限:不支持分词、同义词、相关性排序等高级特性
- 用户体验差:无法实现搜索建议、拼写纠错等智能功能
Elasticsearch(简称ES)是一个分布式、RESTful风格的搜索和数据分析引擎,它能够解决上述所有问题,为你的系统提供企业级的全文检索能力。
芋道云平台已经内置了对Elasticsearch的支持,你只需简单配置即可使用这一强大功能。
快速集成步骤
1. 添加依赖
首先需要在项目中添加Elasticsearch相关依赖。芋道云平台将依赖管理集中在yudao-dependencies/pom.xml文件中,确保其中包含以下配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
然后在需要使用Elasticsearch的模块(如商品模块)的pom.xml中添加依赖:
<dependency>
<groupId>cn.iocoder.yudao</groupId>
<artifactId>yudao-spring-boot-starter-elasticsearch</artifactId>
</dependency>
2. 配置Elasticsearch连接
在配置文件中添加Elasticsearch连接信息,以商品模块为例,修改yudao-module-product-server/src/main/resources/application.yml:
spring:
elasticsearch:
uris: http://localhost:9200
username: elastic
password: changeme
connection-timeout: 5000
socket-timeout: 3000
3. 创建实体类与Repository
创建需要索引的实体类,例如商品信息:
@Data
@Document(indexName = "product")
public class ProductDocument {
@Id
private Long id;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String name;
@Field(type = FieldType.Keyword)
private String category;
@Field(type = FieldType.Double)
private BigDecimal price;
@Field(type = FieldType.Text, analyzer = "ik_max_word")
private String description;
@Field(type = FieldType.Date)
private LocalDateTime createTime;
}
创建Repository接口:
@Repository
public interface ProductRepository extends ElasticsearchRepository<ProductDocument, Long> {
// 自定义查询方法
Page<ProductDocument> findByNameContainingOrDescriptionContaining(String name, String description, Pageable pageable);
}
4. 实现数据同步
创建服务类,实现数据库数据到Elasticsearch的同步:
@Service
@RequiredArgsConstructor
public class ProductSearchService {
private final ProductRepository productRepository;
private final ProductMapper productMapper;
// 同步单个商品
public void syncProduct(Long productId) {
ProductDO product = productMapper.selectById(productId);
if (product != null) {
productRepository.save(convert(product));
}
}
// 批量同步商品
@Transactional(rollbackFor = Exception.class)
public void syncAllProducts() {
List<ProductDO> products = productMapper.selectList();
productRepository.saveAll(products.stream().map(this::convert).collect(Collectors.toList()));
}
// DO转Document
private ProductDocument convert(ProductDO product) {
// 转换逻辑
}
}
实现全文检索功能
1. 基础搜索实现
在服务层添加搜索方法:
public Page<ProductDocument> searchProducts(String keyword, Integer pageNum, Integer pageSize) {
Pageable pageable = PageRequest.of(pageNum - 1, pageSize, Sort.by("createTime").descending());
// 构建查询条件
NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder()
.withQuery(QueryBuilders.multiMatchQuery(keyword, "name", "description")
.type(MultiMatchQueryBuilder.Type.BEST_FIELDS)
.fuzziness(Fuzziness.AUTO))
.withHighlightFields(
new HighlightBuilder.Field("name").preTags("<em>").postTags("</em>"),
new HighlightBuilder.Field("description").preTags("<em>").postTags("</em>")
)
.withPageable(pageable);
SearchHits<ProductDocument> searchHits = elasticsearchRestTemplate.search(
queryBuilder.build(), ProductDocument.class);
// 处理高亮结果并返回
List<ProductDocument> products = searchHits.stream().map(hit -> {
ProductDocument product = hit.getContent();
// 设置高亮字段
if (hit.getHighlightFields().containsKey("name")) {
product.setName(hit.getHighlightFields().get("name").get(0));
}
if (hit.getHighlightFields().containsKey("description")) {
product.setDescription(hit.getHighlightFields().get("description").get(0));
}
return product;
}).collect(Collectors.toList());
return new PageImpl<>(products, pageable, searchHits.getTotalHits());
}
2. 控制器层实现
@RestController
@RequestMapping("/api/product/search")
@RequiredArgsConstructor
public class ProductSearchController {
private final ProductSearchService productSearchService;
@GetMapping
public CommonResult<Page<ProductDocument>> search(
@RequestParam String keyword,
@RequestParam(defaultValue = "1") Integer pageNum,
@RequestParam(defaultValue = "10") Integer pageSize) {
return CommonResult.success(productSearchService.searchProducts(keyword, pageNum, pageSize));
}
}
高级功能实现
1. 搜索建议功能
实现搜索框的自动补全功能:
public List<String> getSearchSuggestions(String prefix) {
CompletionSuggestionBuilder suggestionBuilder = SuggestBuilders
.completionSuggestion("name.suggest")
.prefix(prefix)
.size(10);
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.suggest(new SuggestBuilder().addSuggestion("product_suggest", suggestionBuilder));
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withSourceBuilder(sourceBuilder)
.build();
SearchHits<ProductDocument> searchHits = elasticsearchRestTemplate.search(query, ProductDocument.class);
// 处理建议结果
Suggest suggest = searchHits.getSuggest();
CompletionSuggestion completionSuggestion = suggest.getSuggestion("product_suggest");
return completionSuggestion.getOptions().stream()
.map(CompletionSuggestion.Entry.Option::getText)
.map(Text::string)
.collect(Collectors.toList());
}
2. 搜索结果过滤与排序
public Page<ProductDocument> advancedSearch(ProductSearchDTO searchDTO) {
Pageable pageable = PageRequest.of(
searchDTO.getPageNum() - 1,
searchDTO.getPageSize(),
Sort.by(searchDTO.getSortField()).direction(searchDTO.getSortDirection())
);
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.multiMatchQuery(searchDTO.getKeyword(), "name", "description"));
// 添加过滤条件
if (searchDTO.getMinPrice() != null) {
boolQuery.filter(QueryBuilders.rangeQuery("price").gte(searchDTO.getMinPrice()));
}
if (searchDTO.getMaxPrice() != null) {
boolQuery.filter(QueryBuilders.rangeQuery("price").lte(searchDTO.getMaxPrice()));
}
if (CollectionUtils.isNotEmpty(searchDTO.getCategories())) {
boolQuery.filter(QueryBuilders.termsQuery("category", searchDTO.getCategories()));
}
NativeSearchQuery query = new NativeSearchQueryBuilder()
.withQuery(boolQuery)
.withPageable(pageable)
.build();
SearchHits<ProductDocument> searchHits = elasticsearchRestTemplate.search(query, ProductDocument.class);
return new PageImpl<>(searchHits.getContent(), pageable, searchHits.getTotalHits());
}
性能优化建议
- 合理设计索引:根据业务需求设计字段类型和分词器,避免过度索引
- 批量操作:使用Bulk API进行批量插入和更新,减少网络往返
- 异步处理:通过消息队列芋道 Spring Boot 消息队列 RabbitMQ 入门异步处理索引更新
- 缓存热门查询:使用Redis芋道 Spring Boot Redis 入门缓存热门搜索结果
- 索引分片与副本:根据数据量合理设置分片数量,通过副本提高查询性能和可用性
监控与维护
芋道云平台提供了完善的监控功能,可以通过芋道 Spring Boot 监控端点 Actuator 入门监控Elasticsearch的连接状态和性能指标。
同时,可以使用Elasticsearch的内置工具进行索引管理和优化:
@Service
public class ElasticsearchIndexService {
private final ElasticsearchRestTemplate elasticsearchRestTemplate;
// 重建索引
public boolean rebuildIndex(String indexName) {
// 实现索引重建逻辑
}
// 优化索引
public void optimizeIndex(String indexName) {
// 实现索引优化逻辑
}
// 获取索引统计信息
public Map<String, Object> getIndexStats(String indexName) {
// 获取并返回索引统计信息
}
}
总结
通过本文的介绍,你已经了解了如何在芋道云平台中集成Elasticsearch并实现全文检索功能。从基础配置到高级功能,再到性能优化和监控维护,我们覆盖了Elasticsearch集成的各个方面。
Elasticsearch作为一款强大的搜索引擎,能够显著提升系统的搜索体验和性能。芋道云平台的模块化设计使得集成过程变得简单高效,你可以根据业务需求快速实现各种搜索功能。
如果你想深入了解更多Elasticsearch的高级特性,可以参考官方文档或查看芋道云平台的AI功能源码,其中包含了更复杂的搜索和分析场景实现。
最后,不要忘记给项目点个Star,你的支持是作者持续开发的动力!
更多推荐
所有评论(0)