SpringBoot3.x入门到精通系列:3.3 整合 Elasticsearch 详解

🎯 Elasticsearch简介

Elasticsearch是一个基于Lucene的分布式搜索和分析引擎,能够快速地存储、搜索和分析大量数据。它提供了RESTful API,支持多种查询方式,广泛应用于全文搜索、日志分析、实时数据分析等场景。

核心概念

  • Index: 索引,类似于数据库中的数据库
  • Type: 类型,类似于数据库中的表(ES 7.x后已废弃)
  • Document: 文档,类似于数据库中的行记录
  • Field: 字段,类似于数据库中的列
  • Mapping: 映射,定义文档字段的数据类型和索引方式
  • Shard: 分片,索引的物理分割单元
  • Replica: 副本,分片的备份

🚀 快速开始

1. 添加依赖

xml 复制代码
<dependencies>
    <!-- SpringBoot Starter Web -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    
    <!-- SpringBoot Elasticsearch Starter -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
    <!-- JSON处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
    </dependency>
    
    <!-- 测试依赖 -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>
</dependencies>

2. Elasticsearch配置

yaml 复制代码
spring:
  # Elasticsearch配置
  elasticsearch:
    # Elasticsearch服务器地址
    uris: http://localhost:9200
    # 用户名(如果启用了安全认证)
    username: elastic
    # 密码(如果启用了安全认证)
    password: password
    # 连接超时时间
    connection-timeout: 10s
    # 读取超时时间
    socket-timeout: 30s
    
  # 数据源配置(用于对比)
  datasource:
    url: jdbc:mysql://localhost:3306/demo_db?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver

# 日志配置
logging:
  level:
    org.springframework.data.elasticsearch: DEBUG
    org.elasticsearch: DEBUG

🔧 Elasticsearch配置类

java 复制代码
package com.example.demo.config;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.client.ClientConfiguration;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchConfiguration;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

@Configuration
@EnableElasticsearchRepositories(basePackages = "com.example.demo.repository")
public class ElasticsearchConfig extends ElasticsearchConfiguration {
    
    @Value("${spring.elasticsearch.uris}")
    private String elasticsearchUrl;
    
    @Value("${spring.elasticsearch.username:}")
    private String username;
    
    @Value("${spring.elasticsearch.password:}")
    private String password;
    
    @Override
    public ClientConfiguration clientConfiguration() {
        ClientConfiguration.Builder builder = ClientConfiguration.builder()
                .connectedTo(elasticsearchUrl.replace("http://", ""))
                .withConnectTimeout(10000)
                .withSocketTimeout(30000);
        
        // 如果配置了用户名和密码
        if (!username.isEmpty() && !password.isEmpty()) {
            builder.withBasicAuth(username, password);
        }
        
        return builder.build();
    }
}

📊 文档实体类

1. 产品文档

java 复制代码
package com.example.demo.document;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

@Document(indexName = "products")
@Setting(numberOfShards = 1, numberOfReplicas = 0)
public class ProductDocument {
    
    @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.Keyword)
    private String category;
    
    @Field(type = FieldType.Keyword)
    private String brand;
    
    @Field(type = FieldType.Double)
    private BigDecimal price;
    
    @Field(type = FieldType.Integer)
    private Integer stock;
    
    @Field(type = FieldType.Keyword)
    private List<String> tags;
    
    @Field(type = FieldType.Boolean)
    private Boolean available;
    
    @Field(type = FieldType.Double)
    private Double rating;
    
    @Field(type = FieldType.Integer)
    private Integer salesCount;
    
    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 构造函数
    public ProductDocument() {}
    
    public ProductDocument(String name, String description, String category, String brand, BigDecimal price) {
        this.name = name;
        this.description = description;
        this.category = category;
        this.brand = brand;
        this.price = price;
        this.available = true;
        this.rating = 0.0;
        this.salesCount = 0;
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }
    
    // Getter和Setter方法
    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 String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    
    public String getBrand() { return brand; }
    public void setBrand(String brand) { this.brand = brand; }
    
    public BigDecimal getPrice() { return price; }
    public void setPrice(BigDecimal price) { this.price = price; }
    
    public Integer getStock() { return stock; }
    public void setStock(Integer stock) { this.stock = stock; }
    
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    
    public Boolean getAvailable() { return available; }
    public void setAvailable(Boolean available) { this.available = available; }
    
    public Double getRating() { return rating; }
    public void setRating(Double rating) { this.rating = rating; }
    
    public Integer getSalesCount() { return salesCount; }
    public void setSalesCount(Integer salesCount) { this.salesCount = salesCount; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
    
    @Override
    public String toString() {
        return "ProductDocument{" +
                "id='" + id + '\'' +
                ", name='" + name + '\'' +
                ", description='" + description + '\'' +
                ", category='" + category + '\'' +
                ", brand='" + brand + '\'' +
                ", price=" + price +
                ", stock=" + stock +
                ", available=" + available +
                ", rating=" + rating +
                ", salesCount=" + salesCount +
                '}';
    }
}

2. 文章文档

java 复制代码
package com.example.demo.document;

import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.*;

import java.time.LocalDateTime;
import java.util.List;

@Document(indexName = "articles")
@Setting(numberOfShards = 1, numberOfReplicas = 0)
public class ArticleDocument {
    
    @Id
    private String id;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String title;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String content;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String summary;
    
    @Field(type = FieldType.Keyword)
    private String author;
    
    @Field(type = FieldType.Keyword)
    private String category;
    
    @Field(type = FieldType.Keyword)
    private List<String> tags;
    
    @Field(type = FieldType.Integer)
    private Integer viewCount;
    
    @Field(type = FieldType.Integer)
    private Integer likeCount;
    
    @Field(type = FieldType.Boolean)
    private Boolean published;
    
    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    
    @Field(type = FieldType.Date, format = DateFormat.date_hour_minute_second)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    
    // 构造函数
    public ArticleDocument() {}
    
    public ArticleDocument(String title, String content, String author, String category) {
        this.title = title;
        this.content = content;
        this.author = author;
        this.category = category;
        this.published = false;
        this.viewCount = 0;
        this.likeCount = 0;
        this.createTime = LocalDateTime.now();
        this.updateTime = LocalDateTime.now();
    }
    
    // Getter和Setter方法
    public String getId() { return id; }
    public void setId(String id) { this.id = id; }
    
    public String getTitle() { return title; }
    public void setTitle(String title) { this.title = title; }
    
    public String getContent() { return content; }
    public void setContent(String content) { this.content = content; }
    
    public String getSummary() { return summary; }
    public void setSummary(String summary) { this.summary = summary; }
    
    public String getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }
    
    public String getCategory() { return category; }
    public void setCategory(String category) { this.category = category; }
    
    public List<String> getTags() { return tags; }
    public void setTags(List<String> tags) { this.tags = tags; }
    
    public Integer getViewCount() { return viewCount; }
    public void setViewCount(Integer viewCount) { this.viewCount = viewCount; }
    
    public Integer getLikeCount() { return likeCount; }
    public void setLikeCount(Integer likeCount) { this.likeCount = likeCount; }
    
    public Boolean getPublished() { return published; }
    public void setPublished(Boolean published) { this.published = published; }
    
    public LocalDateTime getCreateTime() { return createTime; }
    public void setCreateTime(LocalDateTime createTime) { this.createTime = createTime; }
    
    public LocalDateTime getUpdateTime() { return updateTime; }
    public void setUpdateTime(LocalDateTime updateTime) { this.updateTime = updateTime; }
}

🔍 Repository接口

1. 产品Repository

java 复制代码
package com.example.demo.repository;

import com.example.demo.document.ProductDocument;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import java.math.BigDecimal;
import java.util.List;

@Repository
public interface ProductRepository extends ElasticsearchRepository<ProductDocument, String> {
    
    // 根据名称查找产品
    List<ProductDocument> findByName(String name);
    
    // 根据名称模糊查找产品
    List<ProductDocument> findByNameContaining(String name);
    
    // 根据分类查找产品
    List<ProductDocument> findByCategory(String category);
    
    // 根据品牌查找产品
    List<ProductDocument> findByBrand(String brand);
    
    // 根据价格范围查找产品
    List<ProductDocument> findByPriceBetween(BigDecimal minPrice, BigDecimal maxPrice);
    
    // 根据可用性查找产品
    List<ProductDocument> findByAvailable(Boolean available);
    
    // 根据评分范围查找产品
    List<ProductDocument> findByRatingGreaterThanEqual(Double rating);
    
    // 复合查询:根据分类和价格范围查找产品
    List<ProductDocument> findByCategoryAndPriceBetween(String category, BigDecimal minPrice, BigDecimal maxPrice);
    
    // 分页查询:根据分类查找产品
    Page<ProductDocument> findByCategory(String category, Pageable pageable);
    
    // 自定义查询:多字段搜索
    @Query("{\"multi_match\": {\"query\": \"?0\", \"fields\": [\"name^2\", \"description\", \"category\", \"brand\"]}}")
    List<ProductDocument> searchByMultiFields(String keyword);
    
    // 自定义查询:根据标签搜索
    @Query("{\"terms\": {\"tags\": [\"?0\"]}}")
    List<ProductDocument> findByTag(String tag);
    
    // 自定义查询:热门产品(根据销量和评分)
    @Query("{\"bool\": {\"must\": [{\"range\": {\"salesCount\": {\"gte\": ?0}}}, {\"range\": {\"rating\": {\"gte\": ?1}}}]}}")
    List<ProductDocument> findPopularProducts(Integer minSales, Double minRating);
}

2. 文章Repository

java 复制代码
package com.example.demo.repository;

import com.example.demo.document.ArticleDocument;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository
public interface ArticleRepository extends ElasticsearchRepository<ArticleDocument, String> {
    
    // 根据标题查找文章
    List<ArticleDocument> findByTitleContaining(String title);
    
    // 根据作者查找文章
    List<ArticleDocument> findByAuthor(String author);
    
    // 根据分类查找文章
    List<ArticleDocument> findByCategory(String category);
    
    // 根据发布状态查找文章
    List<ArticleDocument> findByPublished(Boolean published);
    
    // 根据作者和发布状态查找文章
    List<ArticleDocument> findByAuthorAndPublished(String author, Boolean published);
    
    // 分页查询:根据分类查找已发布文章
    Page<ArticleDocument> findByCategoryAndPublished(String category, Boolean published, Pageable pageable);
    
    // 自定义查询:全文搜索
    @Query("{\"multi_match\": {\"query\": \"?0\", \"fields\": [\"title^3\", \"content\", \"summary^2\"]}}")
    List<ArticleDocument> searchByContent(String keyword);
    
    // 自定义查询:根据标签搜索
    @Query("{\"terms\": {\"tags\": [\"?0\"]}}")
    List<ArticleDocument> findByTag(String tag);
    
    // 自定义查询:热门文章
    @Query("{\"bool\": {\"must\": [{\"term\": {\"published\": true}}, {\"range\": {\"viewCount\": {\"gte\": ?0}}}], \"should\": [{\"range\": {\"likeCount\": {\"gte\": ?1}}}]}}")
    List<ArticleDocument> findPopularArticles(Integer minViews, Integer minLikes);
}

🏗️ Service层实现

1. 产品搜索服务

java 复制代码
package com.example.demo.service;

import com.example.demo.document.ProductDocument;
import com.example.demo.repository.ProductRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.elasticsearch.index.query.QueryBuilders.*;

@Service
public class ProductSearchService {
    
    @Autowired
    private ProductRepository productRepository;
    
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;
    
    /**
     * 保存产品
     */
    public ProductDocument save(ProductDocument product) {
        return productRepository.save(product);
    }
    
    /**
     * 根据ID查找产品
     */
    public Optional<ProductDocument> findById(String id) {
        return productRepository.findById(id);
    }
    
    /**
     * 查找所有产品
     */
    public Iterable<ProductDocument> findAll() {
        return productRepository.findAll();
    }
    
    /**
     * 删除产品
     */
    public void deleteById(String id) {
        productRepository.deleteById(id);
    }
    
    /**
     * 根据名称搜索产品
     */
    public List<ProductDocument> searchByName(String name) {
        return productRepository.findByNameContaining(name);
    }
    
    /**
     * 根据分类搜索产品
     */
    public List<ProductDocument> searchByCategory(String category) {
        return productRepository.findByCategory(category);
    }
    
    /**
     * 根据价格范围搜索产品
     */
    public List<ProductDocument> searchByPriceRange(BigDecimal minPrice, BigDecimal maxPrice) {
        return productRepository.findByPriceBetween(minPrice, maxPrice);
    }
    
    /**
     * 多字段搜索
     */
    public List<ProductDocument> multiFieldSearch(String keyword) {
        return productRepository.searchByMultiFields(keyword);
    }
    
    /**
     * 分页搜索产品
     */
    public Page<ProductDocument> searchByCategory(String category, int page, int size) {
        Pageable pageable = PageRequest.of(page, size, Sort.by("createTime").descending());
        return productRepository.findByCategory(category, pageable);
    }
    
    /**
     * 复杂搜索:使用ElasticsearchOperations
     */
    public List<ProductDocument> complexSearch(String keyword, String category, BigDecimal minPrice, BigDecimal maxPrice) {
        NativeSearchQueryBuilder queryBuilder = new NativeSearchQueryBuilder();
        
        // 构建复合查询
        var boolQuery = boolQuery();
        
        // 关键词搜索
        if (keyword != null && !keyword.isEmpty()) {
            boolQuery.must(multiMatchQuery(keyword, "name", "description", "brand"));
        }
        
        // 分类过滤
        if (category != null && !category.isEmpty()) {
            boolQuery.filter(termQuery("category", category));
        }
        
        // 价格范围过滤
        if (minPrice != null && maxPrice != null) {
            boolQuery.filter(rangeQuery("price").gte(minPrice).lte(maxPrice));
        }
        
        // 只搜索可用产品
        boolQuery.filter(termQuery("available", true));
        
        NativeSearchQuery searchQuery = queryBuilder
                .withQuery(boolQuery)
                .withSort(Sort.by("salesCount").descending())
                .withSort(Sort.by("rating").descending())
                .build();
        
        SearchHits<ProductDocument> searchHits = elasticsearchOperations.search(searchQuery, ProductDocument.class);
        
        return searchHits.stream()
                .map(SearchHit::getContent)
                .collect(Collectors.toList());
    }
    
    /**
     * 搜索热门产品
     */
    public List<ProductDocument> searchPopularProducts(Integer minSales, Double minRating) {
        return productRepository.findPopularProducts(minSales, minRating);
    }
    
    /**
     * 根据标签搜索产品
     */
    public List<ProductDocument> searchByTag(String tag) {
        return productRepository.findByTag(tag);
    }
    
    /**
     * 聚合搜索:按分类统计产品数量
     */
    public void aggregateByCategory() {
        // 这里可以实现聚合查询的逻辑
        // 由于篇幅限制,这里只是一个示例方法
    }
}

🎮 Controller层

java 复制代码
package com.example.demo.controller;

import com.example.demo.document.ProductDocument;
import com.example.demo.service.ProductSearchService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

@RestController
@RequestMapping("/api/search")
@CrossOrigin(origins = "*")
public class SearchController {
    
    @Autowired
    private ProductSearchService productSearchService;
    
    /**
     * 创建产品
     */
    @PostMapping("/products")
    public ResponseEntity<ProductDocument> createProduct(@RequestBody ProductDocument product) {
        ProductDocument savedProduct = productSearchService.save(product);
        return ResponseEntity.ok(savedProduct);
    }
    
    /**
     * 根据ID获取产品
     */
    @GetMapping("/products/{id}")
    public ResponseEntity<ProductDocument> getProduct(@PathVariable String id) {
        Optional<ProductDocument> product = productSearchService.findById(id);
        return product.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
    }
    
    /**
     * 获取所有产品
     */
    @GetMapping("/products")
    public ResponseEntity<Iterable<ProductDocument>> getAllProducts() {
        Iterable<ProductDocument> products = productSearchService.findAll();
        return ResponseEntity.ok(products);
    }
    
    /**
     * 根据名称搜索产品
     */
    @GetMapping("/products/search/name")
    public ResponseEntity<List<ProductDocument>> searchByName(@RequestParam String name) {
        List<ProductDocument> products = productSearchService.searchByName(name);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 根据分类搜索产品
     */
    @GetMapping("/products/search/category")
    public ResponseEntity<List<ProductDocument>> searchByCategory(@RequestParam String category) {
        List<ProductDocument> products = productSearchService.searchByCategory(category);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 根据价格范围搜索产品
     */
    @GetMapping("/products/search/price")
    public ResponseEntity<List<ProductDocument>> searchByPriceRange(
            @RequestParam BigDecimal minPrice,
            @RequestParam BigDecimal maxPrice) {
        List<ProductDocument> products = productSearchService.searchByPriceRange(minPrice, maxPrice);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 多字段搜索
     */
    @GetMapping("/products/search/multi")
    public ResponseEntity<List<ProductDocument>> multiFieldSearch(@RequestParam String keyword) {
        List<ProductDocument> products = productSearchService.multiFieldSearch(keyword);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 分页搜索
     */
    @GetMapping("/products/search/page")
    public ResponseEntity<Page<ProductDocument>> searchByPage(
            @RequestParam String category,
            @RequestParam(defaultValue = "0") int page,
            @RequestParam(defaultValue = "10") int size) {
        Page<ProductDocument> products = productSearchService.searchByCategory(category, page, size);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 复杂搜索
     */
    @GetMapping("/products/search/complex")
    public ResponseEntity<List<ProductDocument>> complexSearch(
            @RequestParam(required = false) String keyword,
            @RequestParam(required = false) String category,
            @RequestParam(required = false) BigDecimal minPrice,
            @RequestParam(required = false) BigDecimal maxPrice) {
        
        List<ProductDocument> products = productSearchService.complexSearch(keyword, category, minPrice, maxPrice);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 搜索热门产品
     */
    @GetMapping("/products/search/popular")
    public ResponseEntity<List<ProductDocument>> searchPopularProducts(
            @RequestParam(defaultValue = "100") Integer minSales,
            @RequestParam(defaultValue = "4.0") Double minRating) {
        
        List<ProductDocument> products = productSearchService.searchPopularProducts(minSales, minRating);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 根据标签搜索产品
     */
    @GetMapping("/products/search/tag")
    public ResponseEntity<List<ProductDocument>> searchByTag(@RequestParam String tag) {
        List<ProductDocument> products = productSearchService.searchByTag(tag);
        return ResponseEntity.ok(products);
    }
    
    /**
     * 删除产品
     */
    @DeleteMapping("/products/{id}")
    public ResponseEntity<Map<String, String>> deleteProduct(@PathVariable String id) {
        productSearchService.deleteById(id);
        
        Map<String, String> response = new HashMap<>();
        response.put("status", "success");
        response.put("message", "产品删除成功");
        return ResponseEntity.ok(response);
    }
}

📊 最佳实践

1. 索引设计

  • 合理设置分片和副本数量
  • 选择合适的字段类型
  • 使用合适的分析器
  • 定期优化索引

2. 查询优化

  • 使用过滤器而非查询进行精确匹配
  • 合理使用聚合查询
  • 避免深度分页
  • 使用缓存提高性能

3. 数据同步

  • 实现数据库与ES的同步机制
  • 处理数据一致性问题
  • 监控同步状态
  • 实现故障恢复

本文关键词: Elasticsearch, 全文搜索, 分布式搜索, 数据分析, 实时搜索, Lucene

相关推荐
SelectDB10 小时前
森马服饰从 Elasticsearch 到阿里云 SelectDB 的架构演进之路
大数据·数据库·数据分析
Hello.Reader10 小时前
Elasticsearch 混合检索一句 `retriever.rrf`,把语义召回与关键词召回融合到极致
大数据·elasticsearch·搜索引擎
Freed&10 小时前
倒排索引:Elasticsearch 搜索背后的底层原理
大数据·elasticsearch·搜索引擎·lucene
bemyrunningdog11 小时前
IntelliJIDEA上传GitHub全攻略
大数据·elasticsearch·搜索引擎
悟能不能悟12 小时前
TransportClient详细说一说
运维·jenkins
不念霉运12 小时前
DevOps平台大比拼:Gitee、Jenkins与CircleCI如何选型?
gitee·jenkins·devops
TDengine (老段)15 小时前
TDengine 中 TDgp 中添加算法模型(异常检测)
java·大数据·数据库·算法·时序数据库·tdengine·涛思数据
2501_9247482415 小时前
高密度客流识别精度↑32%!陌讯多模态融合算法在智慧交通的实战解析
大数据·人工智能·算法·目标检测·计算机视觉
腾讯云qcloud075516 小时前
不办理腾讯地图商业授权有什么影响?
大数据