Java与Elasticsearch集成详解,以及使用指南

Java与Elasticsearch集成详解

1. 环境配置

首先,你需要在Maven项目中添加Elasticsearch Java客户端依赖:

xml 复制代码
<dependencies>
    <!-- Elasticsearch Java Client -->
    <dependency>
        <groupId>co.elastic.clients</groupId>
        <artifactId>elasticsearch-java</artifactId>
        <version>8.10.0</version>
    </dependency>
    
    <!-- JSON 处理 -->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
    
    <!-- Jakarta JSON 处理 -->
    <dependency>
        <groupId>jakarta.json</groupId>
        <artifactId>jakarta.json-api</artifactId>
        <version>2.1.1</version>
    </dependency>
</dependencies>

2. 客户端初始化

Elasticsearch Java客户端有三层结构:

  • 低级客户端:处理HTTP请求
  • 传输层:处理序列化/反序列化
  • API客户端:提供类型安全的API
java 复制代码
// 创建低级客户端
RestClient restClient = RestClient.builder(
    new HttpHost("localhost", 9200)).build();

// 创建传输层
ElasticsearchTransport transport = new RestClientTransport(
    restClient, new JacksonJsonpMapper());

// 创建API客户端
ElasticsearchClient client = new ElasticsearchClient(transport);

3. 基础操作

创建索引
java 复制代码
// 创建索引并设置映射
CreateIndexRequest requestWithMapping = new CreateIndexRequest.Builder()
    .index("products")
    .mappings(m -> m
        .properties("name", p -> p.text(t -> t
            .analyzer("ik_max_word")
            .searchAnalyzer("ik_smart")))
        .properties("price", p -> p.float_())
        .properties("description", p -> p.text(t -> t
            .analyzer("ik_max_word")))
        .properties("createTime", p -> p.date())
    )
    .build();
    
client.indices().create(requestWithMapping);
添加文档
java 复制代码
// 定义产品实体类
public class Product {
    private String id;
    private String name;
    private float price;
    private String description;
    private Date createTime;
    
    // getters and setters
}

// 添加文档
Product product = new Product();
product.setId("1");
product.setName("iPhone 13");
product.setPrice(5999.00f);
product.setDescription("Apple iPhone 13 128GB");
product.setCreateTime(new Date());

IndexRequest<Product> indexRequest = new IndexRequest.Builder<Product>()
    .index("products")
    .id(product.getId())
    .document(product)
    .build();
    
IndexResponse response = client.index(indexRequest);
查询文档
java 复制代码
// 根据ID查询
GetRequest getRequest = new GetRequest.Builder()
    .index("products")
    .id("1")
    .build();
    
GetResponse<Product> getResponse = client.get(getRequest, Product.class);

// 条件查询
SearchRequest searchRequest = new SearchRequest.Builder()
    .index("products")
    .query(q -> q
        .match(m -> m
            .field("name")
            .query("iPhone")
        )
    )
    .build();
    
SearchResponse<Product> searchResponse = client.search(searchRequest, Product.class);

4. 高级搜索

布尔查询
java 复制代码
SearchRequest boolRequest = new SearchRequest.Builder()
    .index("products")
    .query(q -> q
        .bool(b -> b
            .must(m -> m
                .match(t -> t
                    .field("name")
                    .query("iPhone")
                )
            )
            .filter(f -> f
                .range(r -> r
                    .field("price")
                    .gte(JsonData.of(5000))
                    .lte(JsonData.of(10000))
                )
            )
            .should(s -> s
                .match(t -> t
                    .field("description")
                    .query("Pro")
                )
            )
            .minimumShouldMatch("1")
        )
    )
    .build();
聚合查询
java 复制代码
SearchRequest aggregationRequest = new SearchRequest.Builder()
    .index("products")
    .size(0)  // 不返回文档,只返回聚合结果
    .aggregations("price_stats", a -> a
        .stats(s -> s
            .field("price")
        )
    )
    .build();
高亮搜索结果
java 复制代码
SearchRequest highlightRequest = new SearchRequest.Builder()
    .index("products")
    .query(q -> q
        .match(m -> m
            .field("description")
            .query("iPhone")
        )
    )
    .highlight(h -> h
        .fields("description", f -> f
            .preTags("<em>")
            .postTags("</em>")
            .numberOfFragments(3)
        )
    )
    .build();

5. 批量操作

批量操作可以大幅提高性能,减少网络请求次数:

java 复制代码
// 准备批量数据
List<Product> products = new ArrayList<>();
for (int i = 1; i <= 100; i++) {
    Product product = new Product();
    product.setId(String.valueOf(i));
    product.setName("Product " + i);
    product.setPrice(1000 + i * 10.0f);
    product.setDescription("Description for product " + i);
    product.setCreateTime(new Date());
    products.add(product);
}

// 批量索引
BulkRequest.Builder br = new BulkRequest.Builder();

for (Product product : products) {
    br.operations(op -> op
        .index(idx -> idx
            .index("products")
            .id(product.getId())
            .document(product)
        )
    );
}

BulkRequest request = br.build();
BulkResponse response = client.bulk(request);

6. 最佳实践

客户端配置优化
java 复制代码
RestClientBuilder builder = RestClient.builder(
    new HttpHost("localhost", 9200))
    .setRequestConfigCallback(requestConfigBuilder -> {
        // 设置连接超时时间(默认1秒)
        requestConfigBuilder.setConnectTimeout(5000);
        // 设置套接字超时时间(默认30秒)
        requestConfigBuilder.setSocketTimeout(60000);
        return requestConfigBuilder;
    })
    .setHttpClientConfigCallback(httpClientBuilder -> {
        // 设置最大连接数
        httpClientBuilder.setMaxConnPerRoute(50);
        httpClientBuilder.setMaxConnTotal(200);
        return httpClientBuilder;
    });
异常处理
java 复制代码
try {
    SearchRequest searchRequest = new SearchRequest.Builder()
        .index("non_existent_index")
        .query(q -> q.matchAll(m -> m))
        .build();
        
    SearchResponse<Product> response = client.search(searchRequest, Product.class);
} catch (ElasticsearchException e) {
    if (e.status() == 404) {
        System.err.println("索引不存在: " + e.getMessage());
    } else if (e.status() == 400) {
        System.err.println("请求错误: " + e.getMessage());
    }
} catch (IOException e) {
    System.err.println("IO 异常: " + e.getMessage());
}
封装服务类
java 复制代码
@Service
public class ElasticsearchService<T> {
    
    private final ElasticsearchClient client;
    private final Class<T> entityClass;
    private final String indexName;
    
    // 构造函数、保存、查询、删除等方法...
    
    // 条件查询
    public List<T> search(Query query, int from, int size) throws IOException {
        SearchRequest request = new SearchRequest.Builder()
            .index(indexName)
            .query(query)
            .from(from)
            .size(size)
            .build();
            
        SearchResponse<T> response = client.search(request, entityClass);
        return response.hits().hits().stream()
            .map(Hit::source)
            .collect(Collectors.toList());
    }
}

7. Spring Data Elasticsearch

如果你使用Spring Boot,可以通过Spring Data Elasticsearch更简单地集成:

xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>

实体类定义:

java 复制代码
@Document(indexName = "products")
public class Product {
    
    @Id
    private String id;
    
    @Field(type = FieldType.Text, analyzer = "ik_max_word")
    private String name;
    
    @Field(type = FieldType.Float)
    private float price;
    
    // 其他字段...
}

Repository接口:

java 复制代码
public interface ProductRepository extends ElasticsearchRepository<Product, String> {
    
    // 根据名称查询
    List<Product> findByName(String name);
    
    // 根据价格范围查询
    List<Product> findByPriceBetween(float minPrice, float maxPrice);
    
    // 自定义查询
    @Query("{\"bool\": {\"must\": [{\"match\": {\"name\": \"?0\"}}]}}")
    Page<Product> findByNameCustomQuery(String name, Pageable pageable);
}

总结

本指南详细介绍了Java与Elasticsearch的集成方法,包括:

  1. 环境配置:添加依赖和初始化客户端
  2. 基础操作:索引创建、文档的增删改查
  3. 高级搜索:布尔查询、聚合、高亮等
  4. 批量操作:提高性能的批量处理
  5. 最佳实践:客户端优化、异常处理、服务封装
  6. Spring集成:使用Spring Data简化操作

通过这些内容,你应该能够在Java应用中有效地使用Elasticsearch,实现高性能的搜索和数据分析功能。

如果你有特定的使用场景或问题,可以参考官方文档或社区资源获取更多信息。

相关推荐
2401_884810749 分钟前
maven笔记
java·笔记·maven
霸王龙的小胳膊11 分钟前
SpringMVC-登录校验
java·mvc
字节源流11 分钟前
【SpringMVC】常用注解:@PathVariable
java·开发语言·servlet
小安同学iter17 分钟前
SpringMVC(五)拦截器
java·开发语言·spring boot·spring·java-ee
栀栀栀栀栀栀29 分钟前
JVM 2015/3/15
java·开发语言·jvm
极限实验室32 分钟前
使用 INFINI Gateway 保护 Elasticsearch 集群之修改查询不合理参数(一)
elasticsearch
羊思茗52036 分钟前
Spring Boot中@Valid 与 @Validated 注解的详解
java·spring boot·后端
老朋友此林1 小时前
Redisson 实现分布式锁源码浅析
java·redis·分布式
爱分享的淘金达人1 小时前
25年教师资格认定材料及认定详细流程‼
java·python·考研·小程序·tomcat
其实我就是个萌新1 小时前
使用spring data MongoDB对MongoDB进行简单CURD操作示例
java·mongodb·spring