10分钟上手Elasticsearch:芋道云平台全文检索实战指南

【免费下载链接】yudao-cloud ruoyi-vue-pro 全新 Cloud 版本,优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城、CRM、ERP、AI 大模型等功能。你的 ⭐️ Star ⭐️,是作者生发的动力! 【免费下载链接】yudao-cloud 项目地址: https://gitcode.com/gh_mirrors/yu/yudao-cloud

你是否还在为系统中的搜索功能发愁?用户抱怨找不到想要的内容,简单的数据库模糊查询效率低下且体验糟糕?本文将带你一文解决这些痛点,通过芋道云(yudao-cloud)平台的Elasticsearch集成方案,快速实现高效、精准的全文检索功能。

读完本文你将学到:

  • 如何在芋道云平台中快速集成Elasticsearch
  • 核心配置文件的修改方法
  • 索引创建与数据同步的实现步骤
  • 实战案例:商品搜索功能的完整实现

为什么选择Elasticsearch?

在传统的系统开发中,我们常常使用数据库的LIKE语句进行搜索,但这种方式存在明显的局限性:

  1. 性能问题:LIKE '%关键词%' 会导致全表扫描,数据量大时查询缓慢
  2. 功能有限:不支持分词、同义词、相关性排序等高级特性
  3. 用户体验差:无法实现搜索建议、拼写纠错等智能功能

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());
}

性能优化建议

  1. 合理设计索引:根据业务需求设计字段类型和分词器,避免过度索引
  2. 批量操作:使用Bulk API进行批量插入和更新,减少网络往返
  3. 异步处理:通过消息队列芋道 Spring Boot 消息队列 RabbitMQ 入门异步处理索引更新
  4. 缓存热门查询:使用Redis芋道 Spring Boot Redis 入门缓存热门搜索结果
  5. 索引分片与副本:根据数据量合理设置分片数量,通过副本提高查询性能和可用性

监控与维护

芋道云平台提供了完善的监控功能,可以通过芋道 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,你的支持是作者持续开发的动力!

【免费下载链接】yudao-cloud ruoyi-vue-pro 全新 Cloud 版本,优化重构所有功能。基于 Spring Cloud Alibaba + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城、CRM、ERP、AI 大模型等功能。你的 ⭐️ Star ⭐️,是作者生发的动力! 【免费下载链接】yudao-cloud 项目地址: https://gitcode.com/gh_mirrors/yu/yudao-cloud

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐