当前位置: 首页 > news >正文

Spring Boot集成Elasticsearch指南

Spring Boot集成Elasticsearch指南

1. 环境准备

1.1 依赖配置

pom.xml中添加Elasticsearch相关依赖:

<dependencies>
    <!-- Spring Data Elasticsearch -->
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
    </dependency>
    
    <!-- 如果需要使用RestHighLevelClient -->
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.17.4</version>
    </dependency>
</dependencies>

1.2 配置文件

application.yml中添加Elasticsearch配置:

spring:
  elasticsearch:
    rest:
      uris: http://localhost:9200
      username: elastic
      password: your-password
    data:
      elasticsearch:
        repositories:
          enabled: true

2. 基础配置

2.1 配置Elasticsearch客户端

@Configuration
public class ElasticsearchConfig {

    @Value("${spring.elasticsearch.rest.uris}")
    private String elasticsearchUrl;

    @Value("${spring.elasticsearch.rest.username}")
    private String username;

    @Value("${spring.elasticsearch.rest.password}")
    private String password;

    @Bean
    public RestHighLevelClient restHighLevelClient() {
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(AuthScope.ANY,
            new UsernamePasswordCredentials(username, password));

        RestClientBuilder builder = RestClient.builder(
                new HttpHost("localhost", 9200, "http"))
            .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder
                .setDefaultCredentialsProvider(credentialsProvider));

        return new RestHighLevelClient(builder);
    }
}

2.2 配置ElasticsearchTemplate

@Configuration
public class ElasticsearchConfig {

    @Bean
    public ElasticsearchOperations elasticsearchTemplate(RestHighLevelClient client) {
        return new ElasticsearchRestTemplate(client);
    }
}

3. 实体类映射

3.1 创建实体类

@Document(indexName = "products")
public class Product {
    @Id
    private String id;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String description;
    
    @Field(type = FieldType.Double)
    private Double price;
    
    @Field(type = FieldType.Keyword)
    private String category;
    
    @Field(type = FieldType.Date)
    private Date createTime;
    
    // getters and setters
}

3.2 创建Repository接口

@Repository
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
    
    // 自定义查询方法
    List<Product> findByName(String name);
    
    List<Product> findByPriceBetween(Double minPrice, Double maxPrice);
    
    List<Product> findByCategory(String category);
    
    // 使用@Query注解自定义查询
    @Query("{\"bool\": {\"must\": [{\"match\": {\"name\": \"?0\"}}]}}")
    List<Product> searchByName(String name);
}

4. 服务层实现

4.1 创建Service接口

public interface ProductService {
    Product save(Product product);
    void delete(String id);
    Product findById(String id);
    List<Product> search(String keyword);
    List<Product> findByCategory(String category);
    List<Product> findByPriceRange(Double minPrice, Double maxPrice);
}

4.2 实现Service

@Service
public class ProductServiceImpl implements ProductService {

    @Autowired
    private ProductRepository productRepository;
    
    @Autowired
    private ElasticsearchOperations elasticsearchOperations;

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

    @Override
    public void delete(String id) {
        productRepository.deleteById(id);
    }

    @Override
    public Product findById(String id) {
        return productRepository.findById(id).orElse(null);
    }

    @Override
    public List<Product> search(String keyword) {
        // 使用QueryBuilder构建查询
        QueryBuilder queryBuilder = QueryBuilders.multiMatchQuery(keyword, "name", "description")
            .analyzer("ik_max_word");
        
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(queryBuilder)
            .build();
        
        return elasticsearchOperations.search(searchQuery, Product.class)
            .stream()
            .map(SearchHit::getContent)
            .collect(Collectors.toList());
    }

    @Override
    public List<Product> findByCategory(String category) {
        return productRepository.findByCategory(category);
    }

    @Override
    public List<Product> findByPriceRange(Double minPrice, Double maxPrice) {
        return productRepository.findByPriceBetween(minPrice, maxPrice);
    }
}

5. 控制器实现

5.1 创建Controller

@RestController
@RequestMapping("/api/products")
public class ProductController {

    @Autowired
    private ProductService productService;

    @PostMapping
    public ResponseEntity<Product> createProduct(@RequestBody Product product) {
        return ResponseEntity.ok(productService.save(product));
    }

    @GetMapping("/{id}")
    public ResponseEntity<Product> getProduct(@PathVariable String id) {
        Product product = productService.findById(id);
        return product != null ? ResponseEntity.ok(product) : ResponseEntity.notFound().build();
    }

    @DeleteMapping("/{id}")
    public ResponseEntity<Void> deleteProduct(@PathVariable String id) {
        productService.delete(id);
        return ResponseEntity.ok().build();
    }

    @GetMapping("/search")
    public ResponseEntity<List<Product>> searchProducts(@RequestParam String keyword) {
        return ResponseEntity.ok(productService.search(keyword));
    }

    @GetMapping("/category/{category}")
    public ResponseEntity<List<Product>> getProductsByCategory(@PathVariable String category) {
        return ResponseEntity.ok(productService.findByCategory(category));
    }

    @GetMapping("/price-range")
    public ResponseEntity<List<Product>> getProductsByPriceRange(
            @RequestParam Double minPrice,
            @RequestParam Double maxPrice) {
        return ResponseEntity.ok(productService.findByPriceRange(minPrice, maxPrice));
    }
}

6. 高级功能实现

6.1 聚合查询

@Service
public class ProductServiceImpl implements ProductService {
    
    // ... 其他方法 ...

    public Map<String, Long> getProductCountByCategory() {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .addAggregation(AggregationBuilders.terms("category_count")
                .field("category.keyword")
                .size(10))
            .build();
        
        SearchHits<Product> searchHits = elasticsearchOperations.search(searchQuery, Product.class);
        TermsAggregation termsAggregation = searchHits.getAggregations().get("category_count");
        
        return termsAggregation.getBuckets().stream()
            .collect(Collectors.toMap(
                TermsAggregation.Bucket::getKeyAsString,
                TermsAggregation.Bucket::getDocCount
            ));
    }
}

6.2 高亮显示

@Service
public class ProductServiceImpl implements ProductService {
    
    // ... 其他方法 ...

    public List<Map<String, Object>> searchWithHighlight(String keyword) {
        NativeSearchQuery searchQuery = new NativeSearchQueryBuilder()
            .withQuery(QueryBuilders.multiMatchQuery(keyword, "name", "description"))
            .withHighlightFields(
                new HighlightBuilder.Field("name"),
                new HighlightBuilder.Field("description")
            )
            .build();
        
        SearchHits<Product> searchHits = elasticsearchOperations.search(searchQuery, Product.class);
        
        return searchHits.stream()
            .map(hit -> {
                Map<String, Object> result = new HashMap<>();
                result.put("product", hit.getContent());
                result.put("highlight", hit.getHighlightFields());
                return result;
            })
            .collect(Collectors.toList());
    }
}

7. 性能优化

7.1 批量操作

@Service
public class ProductServiceImpl implements ProductService {
    
    // ... 其他方法 ...

    public void bulkSave(List<Product> products) {
        List<IndexQuery> queries = products.stream()
            .map(product -> new IndexQueryBuilder()
                .withId(product.getId())
                .withObject(product)
                .build())
            .collect(Collectors.toList());
        
        elasticsearchOperations.bulkIndex(queries, Product.class);
    }
}

7.2 索引优化

@Configuration
public class ElasticsearchConfig {
    
    // ... 其他配置 ...

    @Bean
    public ElasticsearchOperations elasticsearchTemplate(RestHighLevelClient client) {
        ElasticsearchRestTemplate template = new ElasticsearchRestTemplate(client);
        
        // 配置索引设置
        Settings settings = Settings.builder()
            .put("index.number_of_shards", 3)
            .put("index.number_of_replicas", 1)
            .put("index.refresh_interval", "30s")
            .build();
        
        // 创建索引
        if (!template.indexOps(Product.class).exists()) {
            template.indexOps(Product.class).create(settings);
        }
        
        return template;
    }
}

8. 异常处理

8.1 全局异常处理

@ControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(ElasticsearchException.class)
    public ResponseEntity<ErrorResponse> handleElasticsearchException(ElasticsearchException ex) {
        ErrorResponse error = new ErrorResponse(
            "Elasticsearch操作失败",
            ex.getMessage(),
            HttpStatus.INTERNAL_SERVER_ERROR.value()
        );
        return new ResponseEntity<>(error, HttpStatus.INTERNAL_SERVER_ERROR);
    }
}

@Data
@AllArgsConstructor
class ErrorResponse {
    private String message;
    private String details;
    private int status;
}

9. 测试

9.1 单元测试

@SpringBootTest
class ProductServiceTest {

    @Autowired
    private ProductService productService;

    @Test
    void testSaveAndSearch() {
        // 创建测试数据
        Product product = new Product();
        product.setName("测试商品");
        product.setDescription("这是一个测试商品");
        product.setPrice(99.99);
        product.setCategory("测试分类");
        
        // 保存商品
        Product savedProduct = productService.save(product);
        assertNotNull(savedProduct.getId());
        
        // 搜索商品
        List<Product> results = productService.search("测试");
        assertFalse(results.isEmpty());
        assertEquals(savedProduct.getId(), results.get(0).getId());
    }
}

10. 部署注意事项

10.1 生产环境配置

spring:
  elasticsearch:
    rest:
      uris: ${ELASTICSEARCH_URL:http://localhost:9200}
      username: ${ELASTICSEARCH_USERNAME:elastic}
      password: ${ELASTICSEARCH_PASSWORD:your-password}
    data:
      elasticsearch:
        repositories:
          enabled: true
        client:
          reactive:
            use-ssl: true

10.2 健康检查

@Component
public class ElasticsearchHealthIndicator implements HealthIndicator {

    @Autowired
    private RestHighLevelClient client;

    @Override
    public Health health() {
        try {
            ClusterHealthResponse health = client.cluster().health(
                new ClusterHealthRequest(), RequestOptions.DEFAULT);
            
            if (health.getStatus() == ClusterHealthStatus.GREEN) {
                return Health.up().build();
            } else if (health.getStatus() == ClusterHealthStatus.YELLOW) {
                return Health.up().withDetail("status", "warning").build();
            } else {
                return Health.down().withDetail("status", "critical").build();
            }
        } catch (IOException e) {
            return Health.down(e).build();
        }
    }
}

11. 参考资料

  1. Spring Data Elasticsearch官方文档
  2. Elasticsearch官方文档
  3. Spring Boot官方文档

相关文章:

  • 宁波网站推广运营公司营销网络营销
  • 徐州做网站那家好百度站长中心
  • 网站图片展示源代码公司网站设计图
  • 永川区做网站网站为什么要seo?
  • 产品展示网站设计seo推广方法集合
  • 免费的企业网站cms在线生成个人网站源码
  • idea清除git密码
  • C++ STL:六大组件全解析
  • 大数据(4.1)Hive架构设计与企业级实战:从内核原理到性能巅峰优化,打造高效数据仓库
  • Qt基本框架(2)
  • 强化学习经典策略梯度算法REINFORCE
  • CMake Presets教程
  • 开发一个小程序需要多久时间?小程序软件开发周期
  • 【Flask开发】嘿马文学web完整flask项目第2篇:2.用户认证,Json Web Token(JWT)【附代码文档】
  • 物联网安全技术:守护智能世界的防线
  • 如何把已有的虚拟环境的python版本进行降级?
  • Java观察者模式详解
  • AI助理是如何助力企业的
  • git克隆数据失败
  • 优维HAO案例:香港联交所上市企业「智能运维平台」项目
  • 【学Rust写CAD】25 变量类(variable.rs)
  • 优雅~~Spring Boot 整合多数据源的姿势
  • 计算机硬件——CPU 主要参数
  • 图像处理:使用Numpy和OpenCV实现傅里叶和逆傅里叶变换
  • 裴蜀定理:整数解的奥秘
  • AI与玩具结合的可行性分析