JAVA Spring Boot 如何集成 Elasticsearch 实现高性能全文搜索功能

JAVA Spring Boot 集成 Elasticsearch 实现高性能全文搜索

大家好,今天我们来聊聊如何在 Spring Boot 项目中集成 Elasticsearch,实现高性能的全文搜索功能。 Elasticsearch 是一个分布式的、基于 RESTful API 的搜索和分析引擎,它能够快速地存储、搜索和分析海量数据。 在 Spring Boot 项目中集成 Elasticsearch,可以让我们快速地构建强大的搜索功能,提高用户体验。

一、 Elasticsearch 简介

Elasticsearch 基于 Lucene 构建,提供了一个分布式的、多租户的全文搜索引擎。它通过 RESTful API 提供数据存储、搜索和分析能力。 Elasticsearch 的主要特点包括:

  • 高性能: Elasticsearch 采用倒排索引技术,能够快速地进行全文搜索。
  • 可扩展性: Elasticsearch 是一个分布式的系统,可以轻松地扩展到数百台服务器,处理 PB 级别的数据。
  • 易用性: Elasticsearch 提供了丰富的 API 和工具,方便用户进行数据管理和搜索。
  • 实时性: Elasticsearch 能够实时地索引和搜索数据。
  • 多语言支持: Elasticsearch 支持多种语言的分析器,能够处理不同语言的文本数据。

二、 Spring Boot 集成 Elasticsearch 的方式

Spring Boot 提供了多种集成 Elasticsearch 的方式,包括:

  • Spring Data Elasticsearch: 这是 Spring 官方提供的集成方案,它提供了 Repository 接口,可以像操作 JPA 一样操作 Elasticsearch。
  • Jest Client: Jest 是一个 RESTful Elasticsearch Java 客户端,它提供了一组易于使用的 API,可以与 Elasticsearch 进行交互。
  • Elasticsearch High Level REST Client: 这是 Elasticsearch 官方推荐的 Java 客户端,它提供了更高级别的 API,可以更方便地与 Elasticsearch 进行交互。

在实际项目中,我们通常选择 Spring Data Elasticsearch 或 Elasticsearch High Level REST Client。 Spring Data Elasticsearch 提供了更高级别的抽象,可以减少代码量,提高开发效率。 Elasticsearch High Level REST Client 提供了更多的灵活性,可以更好地控制 Elasticsearch 的行为。

三、 Spring Data Elasticsearch 集成示例

下面我们以 Spring Data Elasticsearch 为例,演示如何在 Spring Boot 项目中集成 Elasticsearch。

  1. 添加依赖:

首先,在 pom.xml 文件中添加 Spring Data Elasticsearch 的依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.17.14</version> <!-- 请替换为你的 Elasticsearch 版本 -->
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.17.14</version> <!-- 请替换为你的 Elasticsearch 版本 -->
</dependency>

请注意,Elasticsearch 客户端的版本需要与 Elasticsearch 服务器的版本保持一致。

  1. 配置 Elasticsearch 连接信息:

application.propertiesapplication.yml 文件中配置 Elasticsearch 的连接信息:

spring.data.elasticsearch.client.reactive.endpoints=localhost:9200

如果需要配置用户名和密码,可以添加以下配置:

spring.data.elasticsearch.client.reactive.endpoints=localhost:9200
spring.elasticsearch.username=elastic
spring.elasticsearch.password=your_password
  1. 创建实体类:

创建一个实体类,并使用 @Document 注解将其映射到 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 = "products")
public class Product {

    @Id
    private String id;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String name;

    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String description;

    @Field(type = FieldType.Double)
    private Double price;

    // Getters and setters
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }
}
  • @Document(indexName = "products"):指定该实体类对应的 Elasticsearch 索引为 "products"。
  • @Id:指定该字段为文档的 ID。
  • @Field:指定该字段的类型和分析器。
    • type = FieldType.Text:指定该字段为文本类型。
    • analyzer = "ik_max_word":指定该字段的索引分析器为 ik_max_word
    • searchAnalyzer = "ik_smart":指定该字段的搜索分析器为 ik_smart

这里使用了 ik_max_wordik_smart 作为分析器。 ik_max_word 会将文本拆分成尽可能多的词语,而 ik_smart 会进行更智能的拆分。 你需要安装 Elasticsearch 的 IK 分词器插件才能使用这两个分析器。

  1. 创建 Repository 接口:

创建一个 Repository 接口,继承 ElasticsearchRepository 接口,并指定实体类和 ID 的类型。

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {

    // 可以自定义查询方法
    List<Product> findByNameContaining(String name);
}

ElasticsearchRepository 接口提供了常用的 CRUD 操作方法,例如 savefindByIddeletefindAll 等。 你还可以自定义查询方法,例如 findByNameContaining,Spring Data Elasticsearch 会根据方法名自动生成查询语句。

  1. 使用 Repository 接口:

在 Service 层或 Controller 层注入 Repository 接口,并使用其提供的方法进行数据操作。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Optional;

@Service
public class ProductService {

    @Autowired
    private ProductRepository productRepository;

    public Product saveProduct(Product product) {
        return productRepository.save(product);
    }

    public Optional<Product> findProductById(String id) {
        return productRepository.findById(id);
    }

    public List<Product> findProductsByName(String name) {
        return productRepository.findByNameContaining(name);
    }

    public void deleteProduct(String id) {
        productRepository.deleteById(id);
    }

    public Iterable<Product> findAllProducts() {
        return productRepository.findAll();
    }
}

四、 Elasticsearch High Level REST Client 集成示例

下面我们以 Elasticsearch High Level REST Client 为例,演示如何在 Spring Boot 项目中集成 Elasticsearch。

  1. 添加依赖:

首先,在 pom.xml 文件中添加 Elasticsearch High Level REST Client 的依赖:

<dependency>
    <groupId>org.elasticsearch.client</groupId>
    <artifactId>elasticsearch-rest-high-level-client</artifactId>
    <version>7.17.14</version> <!-- 请替换为你的 Elasticsearch 版本 -->
</dependency>

<dependency>
    <groupId>org.elasticsearch</groupId>
    <artifactId>elasticsearch</artifactId>
    <version>7.17.14</version> <!-- 请替换为你的 Elasticsearch 版本 -->
</dependency>
  1. 配置 Elasticsearch 连接信息:

创建一个配置类,用于创建 Elasticsearch High Level REST Client。

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ElasticsearchConfig {

    @Value("${elasticsearch.host}")
    private String host;

    @Value("${elasticsearch.port}")
    private int port;

    @Bean(destroyMethod = "close")
    public RestHighLevelClient restHighLevelClient() {
        return new RestHighLevelClient(
                RestClient.builder(
                        new HttpHost(host, port, "http")));
    }
}

application.propertiesapplication.yml 文件中配置 Elasticsearch 的连接信息:

elasticsearch.host=localhost
elasticsearch.port=9200
  1. 使用 Elasticsearch High Level REST Client:

在 Service 层或 Controller 层注入 RestHighLevelClient,并使用其提供的方法进行数据操作。

import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class ProductService {

    @Autowired
    private RestHighLevelClient restHighLevelClient;

    public String saveProduct(Product product) throws IOException {
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("name", product.getName());
        dataMap.put("description", product.getDescription());
        dataMap.put("price", product.getPrice());

        IndexRequest indexRequest = new IndexRequest("products")
                .id(product.getId())
                .source(dataMap, XContentType.JSON);

        IndexResponse indexResponse = restHighLevelClient.index(indexRequest, RequestOptions.DEFAULT);
        return indexResponse.getId();
    }

    public List<Product> searchProductsByName(String name) throws IOException {
        SearchRequest searchRequest = new SearchRequest("products");
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
        searchSourceBuilder.query(QueryBuilders.matchQuery("name", name));
        searchRequest.source(searchSourceBuilder);

        SearchResponse searchResponse = restHighLevelClient.search(searchRequest, RequestOptions.DEFAULT);

        List<Product> products = new ArrayList<>();
        for (SearchHit hit : searchResponse.getHits().getHits()) {
            Map<String, Object> sourceAsMap = hit.getSourceAsMap();
            Product product = new Product();
            product.setId(hit.getId());
            product.setName((String) sourceAsMap.get("name"));
            product.setDescription((String) sourceAsMap.get("description"));
            product.setPrice((Double) sourceAsMap.get("price"));
            products.add(product);
        }

        return products;
    }
}

五、 Elasticsearch 优化

为了提高 Elasticsearch 的性能,可以采取以下措施:

  • 选择合适的硬件: Elasticsearch 需要大量的内存和 CPU 资源,建议选择高性能的服务器。
  • 合理配置 Elasticsearch: 根据实际情况调整 Elasticsearch 的配置参数,例如堆内存大小、分片数量等。
  • 使用合适的分析器: 选择合适的分析器可以提高搜索的准确性和效率。 例如中文可以使用 IK 分词器。
  • 优化查询语句: 避免使用复杂的查询语句,尽量使用简单的查询语句。
  • 使用缓存: 可以使用 Elasticsearch 的缓存机制来提高查询速度。
  • 定期维护索引: 定期对索引进行优化和清理,可以提高搜索效率。
  • 监控 Elasticsearch 集群: 使用 Elasticsearch 的监控工具,可以及时发现和解决问题。

六、 总结

通过 Spring Boot 集成 Elasticsearch,可以快速地构建高性能的全文搜索功能。 Spring Data Elasticsearch 提供了更高级别的抽象,可以减少代码量,提高开发效率。 Elasticsearch High Level REST Client 提供了更多的灵活性,可以更好地控制 Elasticsearch 的行为。 在实际项目中,需要根据实际情况选择合适的集成方案,并采取相应的优化措施,以提高 Elasticsearch 的性能。

七、选择合适的方案,保证高效的搜索

Spring Data Elasticsearch 和 Elasticsearch High Level REST Client 都有各自的优点和适用场景。 选择合适的方案,可以更好地满足项目的需求,并提高开发效率。 优化 Elasticsearch 的配置和查询语句,可以显著提高搜索性能,从而提升用户体验。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注