掘金 后端 ( ) • 2024-04-15 10:34

Elasticsearch 是一个基于 Apache Lucene 构建的开源搜索引擎,

优点:

  1. 全文搜索能力: Elasticsearch 提供了强大的全文搜索功能,支持多种语言,能够高效地执行复杂的文本查询。

  2. 分布式架构: Elasticsearch 本质上是分布式的,支持跨多个节点的数据分片(Sharding)和复制(Replication),这提高了系统的可扩展性和可靠性。

  3. 实时搜索: Elasticsearch 能够提供近乎实时的搜索体验,索引更新和搜索几乎可以同时进行。

  4. 高可用性和可扩展性: 通过简单地增加节点,Elasticsearch 可以水平扩展以处理更多的数据和查询负载,同时保持高可用性。

  5. 多样的客户端接口: Elasticsearch 提供了丰富的 RESTful API 接口,可以使用多种编程语言轻松集成和交互。

  6. 强大的分析能力: Elasticsearch 不仅仅是搜索引擎,还提供了强大的数据聚合功能,可以用于复杂的数据分析和可视化。

  7. 丰富的生态系统: Elasticsearch 是 Elastic Stack 的一部分,与 Logstash(数据处理工具)和 Kibana(数据可视化工具)紧密集成,为日志分析、监控、全文搜索等提供了完整的解决方案。

  8. 易于监控和管理: Elasticsearch 提供了多种监控和管理工具,如 Elastic Stack 的 X-Pack 插件,提供安全、监控、报告等高级功能。

  9. 灵活的数据模型: Elasticsearch 使用 JSON 作为文档格式,这使得它可以轻松地处理复杂的、多层次的数据结构。

  10. 强大的查询DSL: Elasticsearch 的查询DSL(Domain Specific Language)非常灵活和强大,支持从简单的文本查询到复杂的聚合和脚本查询。

  11. 社区支持: 作为一个受欢迎的开源项目,Elasticsearch 拥有一个活跃的社区,可以提供丰富的资源、插件和支持。

  12. 场景适用性广: Elasticsearch 被广泛应用于日志收集与分析、网站搜索、企业搜索、安全信息和事件管理(SIEM)、机器学习等多种场景。

这些优点使得Elasticsearch成为了许多公司和开发者选择的搜索引擎和数据分析工具。

实战:

要在 Spring Boot 应用程序中集成 Elasticsearch,你需要添加相关的依赖、配置 Elasticsearch 客户端,并创建对应的实体、仓库接口等。以下是一个简单的示例,展示了如何在 Spring Boot 应用程序中使用 Elasticsearch。 首先,添加 Spring Data Elasticsearch 的依赖到你的 pom.xml 文件中:

<dependencies>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
      <!-- Other dependencies -->
</dependencies>

配置 Elasticsearch 客户端。在 application.propertiesapplication.yml 中添加 Elasticsearch 的配置: properties:

# application.properties
spring.elasticsearch.rest.uris=http://localhost:9200
spring.elasticsearch.rest.username=root
spring.elasticsearch.rest.password=root

定义一个实体类,对应 Elasticsearch 中的文档:

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
​
@Document(indexName = "blog")
public class Blog {
    @Id
    private String id;
    private String title;
    private String content;
  private String category;
  private Double price;
    
    // Getters and setters
    // ...
}

创建一个仓库接口,继承 ElasticsearchRepository

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface BlogRepository extends ElasticsearchRepository<Blog, String> {
    // 可以添加自定义的搜索方法
}

可以在服务层中使用这个仓库接口

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
​
import java.util.Optional;
​
@Service
public class BlogService {
    
    private final BlogRepository blogRepository;
​
    @Autowired
    public BlogService(BlogRepository blogRepository) {
        this.blogRepository = blogRepository;
    }
​
    public Blog save(Blog blog) {
        return blogRepository.save(blog);
    }
​
    public Optional<Blog> findById(String id) {
        return blogRepository.findById(id);
    }
​
    // 其他业务方法...
}
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.metrics.Avg;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
​
@Service
public class AggregationService {
​
    private final ElasticsearchRestTemplate elasticsearchRestTemplate;
​
    @Autowired
    public AggregationService(ElasticsearchRestTemplate elasticsearchRestTemplate) {
        this.elasticsearchRestTemplate = elasticsearchRestTemplate;
    }
​
    public Double getAveragePriceForCategory(String category) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
                .withQuery(QueryBuilders.termQuery("category.keyword", category))
                .addAggregation(AggregationBuilders.avg("average_price").field("price"))
                .build();
​
        AggregatedPage<Blog> result = elasticsearchRestTemplate.queryForPage(searchQuery, Blog.class);
        Avg averagePrice = result.getAggregations().get("average_price");
        return averagePrice.getValue();
    }
}

最后,创建一个 REST 控制器来处理 HTTP 请求:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
​
import java.util.Optional;
​
@RestController
@RequestMapping("/api/blogs")
public class BlogController {
​
    private final BlogService blogService;
  
  @Autowired
  AggregationService aggregationService;
​
    @Autowired
    public BlogController(BlogService blogService) {
        this.blogService = blogService;
    }
​
    @PostMapping
    public Blog createBlog(@RequestBody Blog blog) {
        return blogService.save(blog);
    }
​
    @GetMapping("/{id}")
    public Blog getBlogById(@PathVariable String id) {
        Optional<Blog> blog = blogService.findById(id);
        return blog.orElse(null);
    }
  
  @GetMapping("/{category}")
    public Blog getBlogById(@PathVariable String category) {
        Optional<Blog> blog = aggregationService.getAveragePriceForCategory(category);
        return blog.orElse(null);
    }
​
    // 其他端点...
}

总结:

首先构建了一个 NativeSearchQuery,其中包含了一个筛选条件和一个聚合操作。筛选条件使用 QueryBuilders.termQuery 来匹配 category 字段的值。聚合操作使用 AggregationBuilders.avg 来计算 price 字段的平均值。

这个示例提供了一个简单的博客应用程序的基础结构,其中包含了 Elasticsearch 的集成。当然,实际应用中可能需要更多的配置和错误处理,以及复杂的查询方法。