Java开发原创文章搜索引擎:Spring Boot集成Elasticsearch的完整流程

1. 引言

Elasticsearch作为分布式搜索引擎,为全文检索提供毫秒级响应。结合Spring Boot的自动化配置能力,可快速构建高性能文章搜索引擎。核心优势包括:

  • 近实时搜索(NRT)
  • RESTful API设计
  • 分布式横向扩展能力
  • 支持中文分词(如IK Analyzer)

2. 环境准备
组件 推荐版本 备注
JDK 11+ LTS版本
Spring Boot 2.7.x 兼容Spring Data Elasticsearch
Elasticsearch 7.17.x 与Spring Boot版本匹配

3. 项目初始化
3.1 创建Spring Boot项目

使用Spring Initializr生成项目,勾选:

  • Spring Web
  • Spring Data Elasticsearch
3.2 添加Maven依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    <!-- IK中文分词插件 -->
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.12.0</version>
    </dependency>
</dependencies>


4. 核心配置
4.1 配置文件application.yml
spring:
  elasticsearch:
    uris: http://localhost:9200  # ES地址
    connection-timeout: 5s        # 连接超时
    socket-timeout: 30s           # 读写超时

# 自定义索引配置
article:
  index:
    name: article_index
    shards: 3
    replicas: 1

4.2 中文分词配置

创建IKAnalyzerConfig.java

@Configuration
public class IKAnalyzerConfig {
    @Bean
    public ElasticsearchCustomizer customizer() {
        return client -> {
            Settings settings = Settings.builder()
                .put("index.analysis.analyzer.ik.type", "ik_max_word")
                .build();
            client.putTemplate("ik_template", settings);
        };
    }
}


5. 数据模型设计
5.1 实体类映射
@Document(indexName = "#{@environment.getProperty('article.index.name')}")
public class Article {
    @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;
    
    @Field(type = FieldType.Date)
    private Date publishTime;
    
    // Getters & Setters
}

注解说明:

  • @Document:定义ES索引名称(动态读取配置)
  • @Field(analyzer="ik_max_word"):启用中文分词

6. 数据访问层
6.1 Repository接口
public interface ArticleRepository extends ElasticsearchRepository<Article, String> {
    
    // 标题关键词搜索
    Page<Article> findByTitle(String keyword, Pageable pageable);
    
    // 组合查询:标题+内容
    @Query("{\"bool\": {\"must\": [{\"match\": {\"title\": \"?0\"}}, {\"match\": {\"content\": \"?1\"}}]}}")
    List<Article> complexSearch(String titleKeyword, String contentKeyword);
}

6.2 自定义Repository实现
public class ArticleCustomRepositoryImpl implements ArticleCustomRepository {
    
    @Autowired
    private ElasticsearchOperations operations;
    
    @Override
    public List<Article> searchByPhrase(String phrase) {
        NativeSearchQuery query = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.matchPhraseQuery("content", phrase))
            .build();
        return operations.search(query, Article.class).get().map(SearchHit::getContent).collect(Collectors.toList());
    }
}


7. 业务逻辑层
7.1 索引管理服务
@Service
public class IndexService {
    @Autowired
    private ElasticsearchOperations operations;
    
    public void createIndex() {
        operations.indexOps(Article.class).create();
        operations.indexOps(Article.class).putMapping();
    }
}

7.2 文章搜索服务
@Service
public class SearchService {
    @Autowired
    private ArticleRepository repository;
    
    public Page<Article> searchArticles(String keyword, int page, int size) {
        return repository.findByTitle(keyword, PageRequest.of(page, size, Sort.by("publishTime").descending()));
    }
}


8. RESTful API设计
@RestController
@RequestMapping("/api/articles")
public class ArticleController {
    
    @Autowired
    private SearchService searchService;
    
    @GetMapping("/search")
    public ResponseEntity<Page<Article>> search(
        @RequestParam String keyword,
        @RequestParam(defaultValue = "0") int page,
        @RequestParam(defaultValue = "10") int size) {
        return ResponseEntity.ok(searchService.searchArticles(keyword, page, size));
    }
}


9. 高级功能实现
9.1 相关性排序公式

在搜索中按相关性得分排序: $$ score = \frac{\text{TF} \times \text{IDF}}{\text{fieldLength}} $$ 其中:

  • TF:词频(Term Frequency)
  • IDF:逆文档频率(Inverse Document Frequency)
9.2 高亮显示
SearchHits<Article> hits = operations.search(query, Article.class);
hits.forEach(hit -> {
    Map<String, List<String>> highlights = hit.getHighlightFields();
    hit.getContent().setTitle(highlights.get("title").get(0)); 
});


10. 性能优化建议
  1. 索引设计
    • 冷热数据分离
    • 使用_routing优化分片路由
  2. 查询优化
    • 避免深度分页(使用search_after
    • 启用查询缓存
  3. 集群管理
    # 监控API示例
    curl -X GET "localhost:9200/_cluster/health?pretty"
    


11. 完整测试流程
  1. 启动ES集群:
    docker run -d -p 9200:9200 -e "discovery.type=single-node" elasticsearch:7.17.10
    

  2. 测试API:
    GET /api/articles/search?keyword=Spring&page=0&size=5
    

  3. 验证响应:
    {
      "content": [
        {
          "id": "1",
          "title": "Spring Boot集成指南",
          "content": "详细教程...",
          "publishTime": "2023-01-15"
        }
      ],
      "pageable": { /* 分页信息 */ }
    }
    


结语

通过Spring Boot与Elasticsearch的深度集成,可快速构建支持中文分词、高亮显示、相关性排序的原创文章搜索引擎。后续可扩展:

  • 实时索引更新(使用RabbitMQ消息队列)
  • 多维度聚合分析
  • 个性化推荐算法集成

提示:生产环境建议使用Elastic Cloud托管服务,简化集群运维管理。

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐