Elasticsearch 8.1 Java API Client 客户端使用指南(索引、文档操作篇)

依赖配置

Maven 项目

pom.xml 文件中添加以下依赖:

xml 复制代码
    
    
        co.elastic.clients
        elasticsearch-java
        8.1.0
    
    
    
    
        com.fasterxml.jackson.core
        jackson-databind
        2.13.0
    
    
    
    
        org.apache.httpcomponents.client5
        httpclient5
        5.1.3
    
    
    
    
        org.elasticsearch.client
        elasticsearch-rest-client
        8.1.0
    

Gradle 项目

build.gradle 文件中添加以下依赖:

groovy 复制代码
dependencies {
    implementation 'co.elastic.clients:elasticsearch-java:8.1.0'
    implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
    implementation 'org.apache.httpcomponents.client5:httpclient5:5.1.3'
    implementation 'org.elasticsearch.client:elasticsearch-rest-client:8.1.0'
}

客户端初始化

基本客户端初始化

java 复制代码
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;

public class ElasticsearchClientUtil {
    
    /**
     * 创建 Elasticsearch 客户端(无认证)
     */
    public static ElasticsearchClient createClient() {
        // 创建 REST 客户端
        RestClient restClient = RestClient.builder(
            new HttpHost("localhost", 9200, "http")
        ).build();
        
        // 创建传输层
        RestClientTransport transport = new RestClientTransport(
            restClient, 
            new JacksonJsonpMapper()
        );
        
        // 创建 Elasticsearch 客户端
        return new ElasticsearchClient(transport);
    }
    
    /**
     * 创建 Elasticsearch 客户端(带认证)
     */
    public static ElasticsearchClient createClientWithAuth(
            String host, int port, String scheme, 
            String username, String password) {
        
        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials(username, password)
        );
        
        RestClientBuilder builder = RestClient.builder(
            new HttpHost(host, port, scheme)
        );
        
        builder.setHttpClientConfigCallback(httpClientBuilder -> 
            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider)
        );
        
        RestClient restClient = builder.build();
        RestClientTransport transport = new RestClientTransport(
            restClient, 
            new JacksonJsonpMapper()
        );
        
        return new ElasticsearchClient(transport);
    }
    
    /**
     * 关闭客户端
     */
    public static void closeClient(ElasticsearchClient client) throws IOException {
        if (client != null) {
            client._transport().close();
        }
    }
}

带 SSL/TLS 的客户端初始化

java 复制代码
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.ssl.SSLContextBuilder;

public class ElasticsearchClientUtil {
    
    /**
     * 创建带 SSL 的 Elasticsearch 客户端
     */
    public static ElasticsearchClient createClientWithSSL(
            String host, int port, String caCertPath) throws Exception {
        
        SSLContextBuilder sslBuilder = SSLContextBuilder.create()
            .loadTrustMaterial(new File(caCertPath), 
                new TrustSelfSignedStrategy());
        
        RestClientBuilder builder = RestClient.builder(
            new HttpHost(host, port, "https")
        );
        
        builder.setHttpClientConfigCallback(httpClientBuilder -> 
            httpClientBuilder.setSSLContext(sslBuilder.build())
        );
        
        RestClient restClient = builder.build();
        RestClientTransport transport = new RestClientTransport(
            restClient, 
            new JacksonJsonpMapper()
        );
        
        return new ElasticsearchClient(transport);
    }
}

索引操作 API

Elasticsearch 索引知识点

什么是索引(Index)?

在 Elasticsearch 中,索引(Index)类似于关系型数据库中的数据库(Database),是文档的集合。每个索引都有自己的映射(Mapping)和设置(Settings)。

关键概念:

  • 索引名称:必须小写,不能包含特殊字符
  • 索引别名(Alias):可以给索引起一个别名,方便索引切换
  • 索引模板(Template):可以定义索引模板,自动创建符合规则的索引

映射(Mapping)

映射(Mapping)定义了索引中文档的结构,类似于关系型数据库中的表结构(Schema)。映射包括:

  • 字段类型:text、keyword、long、integer、date 等
  • 分析器(Analyzer):用于索引时的文本分析
  • 搜索分析器(Search Analyzer):用于搜索时的文本分析

常见字段类型:

  • text:全文搜索字段,会被分词
  • keyword:精确匹配字段,不分词
  • long/integer/short/byte:数值类型
  • date:日期类型
  • boolean:布尔类型
  • object:对象类型(嵌套文档)
  • nested:嵌套类型(数组对象)

索引设置(Settings)

索引设置控制索引的行为,包括:

  • 分片数(number_of_shards):索引的主分片数量,创建后不可修改
  • 副本数(number_of_replicas):每个主分片的副本数量,可以动态修改
  • 刷新间隔(refresh_interval):数据写入后多久可以被搜索到
  • 分析器配置:自定义分析器、分词器等

分片(Shard)和副本(Replica):

  • 主分片(Primary Shard):存储实际数据,分片数量决定索引的最大数据量
  • 副本分片(Replica Shard):主分片的副本,提供高可用性和读取性能
  • 分片数量建议:根据数据量和节点数量合理设置,通常每个分片 20-50GB

索引生命周期

索引可以有以下状态:

  • 打开(Open):正常状态,可以读写
  • 关闭(Close):索引关闭后不能读写,但数据仍然存在,可以节省资源
  • 只读(Read-only):只能读取,不能写入

1. 创建索引

1.1 创建简单索引

java 复制代码
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.ElasticsearchIndicesClient;
import java.io.IOException;

public class IndexOperations {
    
    /**
     * 创建简单索引(无映射)
     */
    public static boolean createIndex(ElasticsearchClient client, String indexName) 
            throws IOException {
        CreateIndexResponse response = client.indices().create(c -> c
            .index(indexName)
        );
        return response.acknowledged();
    }
}

1.2 创建带映射的索引

java 复制代码
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch._types.mapping.TypeMapping;
import co.elastic.clients.json.JsonData;

public class IndexOperations {
    
    /**
     * 创建带映射的索引
     */
    public static boolean createIndexWithMapping(
            ElasticsearchClient client, String indexName) throws IOException {
        
        CreateIndexResponse response = client.indices().create(c -> c
            .index(indexName)
            .mappings(m -> m
                .properties("id", p -> p.long_(l -> l))
                .properties("title", p -> p
                    .text(t -> t
                        .analyzer("ik_max_word")
                        .searchAnalyzer("ik_smart")
                    )
                )
                .properties("content", p -> p
                    .text(t -> t
                        .analyzer("ik_max_word")
                        .searchAnalyzer("ik_smart")
                    )
                )
                .properties("author", p -> p.keyword(k -> k))
                .properties("createTime", p -> p.date(d -> d.format("yyyy-MM-dd HH:mm:ss")))
                .properties("views", p -> p.integer(i -> i))
            )
        );
        
        return response.acknowledged();
    }
}

1.3 创建带设置的索引

java 复制代码
import co.elastic.clients.elasticsearch.indices.IndexSettings;

public class IndexOperations {
    
    /**
     * 创建带设置的索引(分片数、副本数等)
     */
    public static boolean createIndexWithSettings(
            ElasticsearchClient client, String indexName) throws IOException {
        
        CreateIndexResponse response = client.indices().create(c -> c
            .index(indexName)
            .settings(s -> s
                .numberOfShards("3")
                .numberOfReplicas("1")
                .analysis(a -> a
                    .analyzer("ik_max_word", an -> an
                        .custom(cu -> cu
                            .tokenizer("ik_max_word")
                        )
                    )
                )
            )
        );
        
        return response.acknowledged();
    }
}

2. 检查索引是否存在

java 复制代码
public class IndexOperations {
    
    /**
     * 检查索引是否存在
     */
    public static boolean indexExists(ElasticsearchClient client, String indexName) 
            throws IOException {
        return client.indices().exists(e -> e.index(indexName)).value();
    }
}

3. 获取索引信息

java 复制代码
import co.elastic.clients.elasticsearch.indices.GetIndexResponse;

public class IndexOperations {
    
    /**
     * 获取索引信息
     */
    public static GetIndexResponse getIndex(
            ElasticsearchClient client, String indexName) throws IOException {
        return client.indices().get(g -> g.index(indexName));
    }
}

4. 获取索引映射

java 复制代码
import co.elastic.clients.elasticsearch.indices.GetMappingResponse;

public class IndexOperations {
    
    /**
     * 获取索引映射
     */
    public static GetMappingResponse getIndexMapping(
            ElasticsearchClient client, String indexName) throws IOException {
        return client.indices().getMapping(g -> g.index(indexName));
    }
}

5. 更新索引映射

java 复制代码
import co.elastic.clients.elasticsearch.indices.PutMappingResponse;

public class IndexOperations {
    
    /**
     * 更新索引映射(添加新字段)
     */
    public static boolean updateIndexMapping(
            ElasticsearchClient client, String indexName) throws IOException {
        
        PutMappingResponse response = client.indices().putMapping(p -> p
            .index(indexName)
            .properties("newField", pr -> pr.keyword(k -> k))
        );
        
        return response.acknowledged();
    }
}

6. 更新索引设置

java 复制代码
import co.elastic.clients.elasticsearch.indices.UpdateIndicesSettingsResponse;

public class IndexOperations {
    
    /**
     * 更新索引设置
     */
    public static boolean updateIndexSettings(
            ElasticsearchClient client, String indexName) throws IOException {
        
        UpdateIndicesSettingsResponse response = client.indices().putSettings(p -> p
            .index(indexName)
            .settings(s -> s
                .numberOfReplicas("2")
            )
        );
        
        return response.acknowledged();
    }
}

7. 删除索引

java 复制代码
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;

public class IndexOperations {
    
    /**
     * 删除索引
     */
    public static boolean deleteIndex(ElasticsearchClient client, String indexName) 
            throws IOException {
        DeleteIndexResponse response = client.indices().delete(d -> d.index(indexName));
        return response.acknowledged();
    }
}

8. 批量删除索引

java 复制代码
public class IndexOperations {
    
    /**
     * 批量删除索引
     */
    public static boolean deleteIndices(
            ElasticsearchClient client, String... indexNames) throws IOException {
        DeleteIndexResponse response = client.indices().delete(d -> d
            .index(Arrays.asList(indexNames))
        );
        return response.acknowledged();
    }
}

9. 打开/关闭索引

java 复制代码
import co.elastic.clients.elasticsearch.indices.CloseIndexResponse;
import co.elastic.clients.elasticsearch.indices.OpenIndexResponse;

public class IndexOperations {
    
    /**
     * 关闭索引
     */
    public static boolean closeIndex(ElasticsearchClient client, String indexName) 
            throws IOException {
        CloseIndexResponse response = client.indices().close(c -> c.index(indexName));
        return response.acknowledged();
    }
    
    /**
     * 打开索引
     */
    public static boolean openIndex(ElasticsearchClient client, String indexName) 
            throws IOException {
        OpenIndexResponse response = client.indices().open(o -> o.index(indexName));
        return response.acknowledged();
    }
}

10. 刷新索引

java 复制代码
import co.elastic.clients.elasticsearch.indices.RefreshResponse;

public class IndexOperations {
    
    /**
     * 刷新索引(使数据立即可搜索)
     */
    public static boolean refreshIndex(ElasticsearchClient client, String indexName) 
            throws IOException {
        RefreshResponse response = client.indices().refresh(r -> r.index(indexName));
        return response.shards().total() > 0;
    }
}

为什么需要专门的索引刷新api? ES 基于 Lucene 构建,数据写入并非直接落盘并立即可查,而是先写入内存缓冲区,默认每隔 1 秒 Lucene 会将缓冲区数据刷入「分段文件(Segment)」,这个过程就是「Refresh」。 未刷新前:数据仅在内存缓冲区,执行 search 查询无法查到; 刷新后:数据进入分段文件,成为可查询的 "可见数据"(但此时数据尚未持久化到磁盘,仅在文件系统缓存,持久化靠 flush 操作)。 这是 ES 为了平衡写入性能和查询实时性的设计:如果每次写入都立即刷新,会产生大量小分段文件,严重影响性能;如果完全依赖 1 秒自动刷新,又无法满足 "写入后立即查询" 的场景(如秒杀、实时日志检索)。


文档操作 API

Elasticsearch 文档知识点

什么是文档(Document)?

在 Elasticsearch 中,文档(Document)是索引中的基本数据单元,类似于关系型数据库中的行(Row)。文档是 JSON 格式的,包含多个字段(Field)。

文档结构:

  • 索引(_index):文档所属的索引
  • 类型(_type):在 ES 7.x 之前有类型概念,8.x 中已废弃
  • ID(_id):文档的唯一标识符
  • 版本(_version):文档的版本号,用于乐观锁控制
  • 源数据(_source):文档的原始 JSON 数据

文档操作类型

Elasticsearch 支持以下文档操作:

  1. Index(索引):创建或更新文档(如果文档已存在则替换)
  2. Create(创建):仅创建文档(如果文档已存在则失败)
  3. Update(更新):部分更新文档
  4. Delete(删除):删除文档
  5. Get(获取):根据 ID 获取文档

版本控制(Versioning)

Elasticsearch 使用版本号来管理文档的并发更新:

  • 内部版本(_version):每次更新自动递增
  • 外部版本(external version):可以使用外部系统提供的版本号
  • 乐观锁:通过版本号实现乐观并发控制

文档路由(Routing)

文档会被路由到特定的分片,路由规则:

  • 默认使用文档 ID 的哈希值:shard_num = hash(_routing) % num_primary_shards
  • 可以自定义路由值,相同路由值的文档会存储在同一分片
  • 路由可以提高查询性能(减少查询的分片数量)

文档刷新(Refresh)

文档写入后不会立即可搜索,需要等待刷新:

  • 自动刷新:默认每 1 秒自动刷新一次
  • 手动刷新:调用 refresh API 立即刷新
  • 实时性 vs 性能:刷新间隔越短,实时性越好,但性能会下降

1. 索引文档(新增/更新)

1.1 使用自动生成的 ID

java 复制代码
import co.elastic.clients.elasticsearch.core.IndexResponse;

public class DocumentOperations {
    
    /**
     * 索引文档(自动生成 ID)
     */
    public static String indexDocument(
            ElasticsearchClient client, String indexName, Object document) 
            throws IOException {
        IndexResponse response = client.index(i -> i
            .index(indexName)
            .document(document)
        );
        return response.id();
    }
}

1.2 使用指定 ID

java 复制代码
public class DocumentOperations {
    
    /**
     * 索引文档(指定 ID)
     */
    public static String indexDocumentWithId(
            ElasticsearchClient client, String indexName, String id, Object document) 
            throws IOException {
        IndexResponse response = client.index(i -> i
            .index(indexName)
            .id(id)
            .document(document)
        );
        return response.id();
    }
}

1.3 使用 Map 作为文档

java 复制代码
import java.util.HashMap;
import java.util.Map;

public class DocumentOperations {
    
    /**
     * 使用 Map 索引文档
     */
    public static String indexDocumentFromMap(
            ElasticsearchClient client, String indexName, String id, 
            Map documentMap) throws IOException {
        IndexResponse response = client.index(i -> i
            .index(indexName)
            .id(id)
            .document(documentMap)
        );
        return response.id();
    }
}

1.4 使用 POJO 作为文档

java 复制代码
// 定义 POJO 类
public class Article {
    private String id;
    private String title;
    private String content;
    private String author;
    private Long views;
    private String createTime;
    
    // 构造函数、getter 和 setter
    public Article() {}
    
    public Article(String id, String title, String content, 
                   String author, Long views, String createTime) {
        this.id = id;
        this.title = title;
        this.content = content;
        this.author = author;
        this.views = views;
        this.createTime = createTime;
    }
    
    // Getters and Setters
    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 getAuthor() { return author; }
    public void setAuthor(String author) { this.author = author; }
    
    public Long getViews() { return views; }
    public void setViews(Long views) { this.views = views; }
    
    public String getCreateTime() { return createTime; }
    public void setCreateTime(String createTime) { this.createTime = createTime; }
}

public class DocumentOperations {
    
    /**
     * 使用 POJO 索引文档
     */
    public static String indexDocumentFromPOJO(
            ElasticsearchClient client, String indexName, Article article) 
            throws IOException {
        IndexResponse response = client.index(i -> i
            .index(indexName)
            .id(article.getId())
            .document(article)
        );
        return response.id();
    }
}

2. 获取文档

2.1 根据 ID 获取文档

java 复制代码
import co.elastic.clients.elasticsearch.core.GetResponse;

public class DocumentOperations {
    
    /**
     * 根据 ID 获取文档
     */
    public static  T getDocument(
            ElasticsearchClient client, String indexName, String id, Class clazz) 
            throws IOException {
        GetResponse response = client.get(g -> g
            .index(indexName)
            .id(id),
            clazz
        );
        
        if (response.found()) {
            return response.source();
        }
        return null;
    }
}

clazz参数的作用: 指定返回对象的类型:clazz 是一个 Class 类型的参数,表示调用者期望从 Elasticsearch 中获取文档并将其反序列化为哪种 Java 对象类型。

2.2 检查文档是否存在

java 复制代码
public class DocumentOperations {
    
    /**
     * 检查文档是否存在
     */
    public static boolean documentExists(
            ElasticsearchClient client, String indexName, String id) 
            throws IOException {
        return client.exists(e -> e
            .index(indexName)
            .id(id)
        ).value();
    }
}

3. 更新文档

知识点:文档更新

  • 更新方式
    1. Index API:完全替换文档(如果文档不存在则创建)
    2. Update API:部分更新文档(只更新指定字段)
  • Update API 优势
    • 只传输需要更新的字段,减少网络开销
    • 支持脚本更新(如:增加字段值)
    • 支持 upsert(如果文档不存在则创建)
  • 更新过程
    1. 获取原文档
    2. 合并更新字段
    3. 重新索引文档
    4. 版本号自动递增
  • 版本控制:更新时会检查版本号,防止并发冲突

3.1 使用 Update API 更新文档

java 复制代码
import co.elastic.clients.elasticsearch.core.UpdateResponse;
import co.elastic.clients.json.JsonData;

public class DocumentOperations {
    
    /**
     * 更新文档(部分字段)
     */
    public static String updateDocument(
            ElasticsearchClient client, String indexName, String id, 
            Map updateFields) throws IOException {
        
        UpdateResponse response = client.update(u -> u
            .index(indexName)
            .id(id)
            .doc(updateFields),
            Object.class
        );
        
        return response.id();
    }
    
    /**
     * 使用脚本更新文档
     */
    public static String updateDocumentWithScript(
            ElasticsearchClient client, String indexName, String id, 
            String script) throws IOException {
        
        UpdateResponse response = client.update(u -> u
            .index(indexName)
            .id(id)
            .script(s -> s
                .inline(i -> i.source(script))
            ),
            Object.class
        );
        
        return response.id();
    }
    
    /**
     * 增加字段值(例如:增加浏览次数)
     */
    public static String incrementField(
            ElasticsearchClient client, String indexName, String id, 
            String fieldName, int increment) throws IOException {
        
        String script = "ctx._source." + fieldName + " += params.increment";
        Map params = new HashMap<>();
        params.put(&#34;increment&#34;, JsonData.of(increment));
        
        UpdateResponse response = client.update(u -> u
            .index(indexName)
            .id(id)
            .script(s -> s
                .inline(i -> i
                    .source(script)
                    .params(params)
                )
            ),
            Object.class
        );
        
        return response.id();
    }
}
拓展知识:es8.x中的update脚本知识:

ES 8.x 中 update 脚本的核心规则: 脚本语言默认是 painless,无需额外指定; 通过 ctx._source 操作文档的字段(ctx 是上下文对象,_source 对应文档原始数据); 支持新增字段、修改字段、删除字段、数值运算、条件判断等逻辑。 示例 1:新增 / 修改单个字段 脚本内容(字符串形式)

java 复制代码
运行
String script1 = &#34;ctx._source.new_field = '新增的字符串值'; ctx._source.old_field = '修改后的旧字段值'&#34;;
调用方式

运行 // 调用方法更新文档 String docId = updateDocumentWithScript(client, "my_index", "1001", script1); 效果 若文档无 new_field,则新增该字段并赋值; 若已有 old_field,则覆盖其值;若无则新增。 示例 2:数值字段自增 / 自减 脚本内容

java 复制代码
运行
// 订单金额加10,库存减1
String script2 = &#34;ctx._source.amount += 10; ctx._source.stock -= 1&#34;;

效果 适用于计数、库存、金额等数值型字段的增量更新; 注意:若字段不存在,会抛出 NullPointerException,可加判空(见示例 4)。

示例 3:删除字段 脚本内容

java 复制代码
运行
// 删除无用字段
String script3 = &#34;ctx._source.remove('useless_field')&#34;;

效果 从文档 _source 中移除指定字段,更新后查询将不再返回该字段。

示例 4:条件更新(满足条件才修改) 脚本内容

java 复制代码
运行
// 仅当状态为待支付时,更新支付时间和状态
String script4 = &#34;&#34;&#34;
    if (ctx._source.status == 'PENDING') {
        ctx._source.status = 'PAID';
        ctx._source.pay_time = new Date().getTime(); // 赋值当前时间戳
    }
    &#34;&#34;&#34;;

注意 多行脚本建议用 Java 文本块("""),避免拼接转义符; new Date().getTime() 是 Painless 支持的时间操作,也可传入外部参数(见示例 5)。 示例 5:带参数的脚本(推荐,避免硬编码) 优化点 直接在脚本中写死值易维护性差,ES 支持通过 params 传入参数,更灵活且避免脚本注入风险。 改造方法(需微调原方法,兼容参数传递) 先修改原方法以支持参数:

java 复制代码
运行
/**
 * 支持参数的脚本更新(更通用)
 */
public static String updateDocumentWithScript(
        ElasticsearchClient client, String indexName, String id, 
        String script, Map params) throws IOException {
    
    UpdateResponse response = client.update(u -> u
        .index(indexName)
        .id(id)
        .script(s -> s
            .inline(i -> i
                .source(script)
                .params(params) // 传入参数
            )
        ),
        Object.class
    );
    
    return response.id();
}

脚本 + 参数调用

java 复制代码
运行
// 脚本(使用参数占位符)
String script5 = &#34;ctx._source.discount = params.discount; ctx._source.price = ctx._source.original_price * (1 - params.discount)&#34;;
// 参数映射
Map params = new HashMap<>();
params.put(&#34;discount&#34;, 0.2); // 20% 折扣
// 调用更新
String docId = updateDocumentWithScript(client, &#34;my_index&#34;, &#34;1001&#34;, script5, params);

效果 动态传入折扣率,计算最终价格; 脚本逻辑与数据分离,复用性更高。 示例 6:数组字段操作 脚本内容

java 复制代码
运行
// 向数组添加元素(去重)+ 删除指定元素
String script6 = &#34;&#34;&#34;
    // 确保数组存在,不存在则初始化
    if (!ctx._source.containsKey('tags')) {
        ctx._source.tags = [];
    }
    // 去重添加
    if (!ctx._source.tags.contains('es')) {
        ctx._source.tags.add('es');
    }
    // 删除元素
    ctx._source.tags.removeIf(tag -> tag == 'old_tag');
    &#34;&#34;&#34;;

效果 处理标签、关键词等数组类型字段,避免重复添加; 支持数组元素的增删改查。

4. 删除文档

java 复制代码
import co.elastic.clients.elasticsearch.core.DeleteResponse;

public class DocumentOperations {
    
    /**
     * 根据 ID 删除文档
     */
    public static boolean deleteDocument(
            ElasticsearchClient client, String indexName, String id) 
            throws IOException {
        DeleteResponse response = client.delete(d -> d
            .index(indexName)
            .id(id)
        );
        return response.result().name().equals(&#34;Deleted&#34;);
    }
}

5. 批量操作

5.1 批量索引文档

java 复制代码
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;

public class DocumentOperations {
    
    /**
     * 批量索引文档
     */
    public static BulkResponse bulkIndexDocuments(
            ElasticsearchClient client, String indexName, List documents) 
            throws IOException {
        
        BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
        
        for (Object doc : documents) {
            bulkBuilder.operations(op -> op
                .index(idx -> idx
                    .index(indexName)
                    .document(doc)
                )
            );
        }
        
        BulkResponse response = client.bulk(bulkBuilder.build());
        return response;
    }
    
    /**
     * 批量索引文档(带 ID)
     */
    public static BulkResponse bulkIndexDocumentsWithIds(
            ElasticsearchClient client, String indexName, 
            Map documents) throws IOException {
        
        BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
        
        for (Map.Entry entry : documents.entrySet()) {
            bulkBuilder.operations(op -> op
                .index(idx -> idx
                    .index(indexName)
                    .id(entry.getKey())
                    .document(entry.getValue())
                )
            );
        }
        
        BulkResponse response = client.bulk(bulkBuilder.build());
        return response;
    }
}

5.2 批量更新文档

java 复制代码
public class DocumentOperations {
    
    /**
     * 批量更新文档
     */
    public static BulkResponse bulkUpdateDocuments(
            ElasticsearchClient client, String indexName, 
            Map> updateMap) throws IOException {
        
        BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
        
        for (Map.Entry> entry : updateMap.entrySet()) {
            bulkBuilder.operations(op -> op
                .update(up -> up
                    .index(indexName)
                    .id(entry.getKey())
                    .document(entry.getValue())
                )
            );
        }
        
        BulkResponse response = client.bulk(bulkBuilder.build());
        return response;
    }
}

5.3 批量删除文档

java 复制代码
public class DocumentOperations {
    
    /**
     * 批量删除文档
     */
    public static BulkResponse bulkDeleteDocuments(
            ElasticsearchClient client, String indexName, List ids) 
            throws IOException {
        
        BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
        
        for (String id : ids) {
            bulkBuilder.operations(op -> op
                .delete(d -> d
                    .index(indexName)
                    .id(id)
                )
            );
        }
        
        BulkResponse response = client.bulk(bulkBuilder.build());
        return response;
    }
}

5.4 混合批量操作

java 复制代码
public class DocumentOperations {
    
    /**
     * 混合批量操作(索引、更新、删除)
     */
    public static BulkResponse bulkMixedOperations(
            ElasticsearchClient client, String indexName,
            List documentsToIndex,
            Map> documentsToUpdate,
            List idsToDelete) throws IOException {
        
        BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
        
        // 批量索引
        for (Object doc : documentsToIndex) {
            bulkBuilder.operations(op -> op
                .index(idx -> idx
                    .index(indexName)
                    .document(doc)
                )
            );
        }
        
        // 批量更新
        for (Map.Entry> entry : documentsToUpdate.entrySet()) {
            bulkBuilder.operations(op -> op
                .update(up -> up
                    .index(indexName)
                    .id(entry.getKey())
                    .document(entry.getValue())
                )
            );
        }
        
        // 批量删除
        for (String id : idsToDelete) {
            bulkBuilder.operations(op -> op
                .delete(d -> d
                    .index(indexName)
                    .id(id)
                )
            );
        }
        
        BulkResponse response = client.bulk(bulkBuilder.build());
        
        // 检查错误
        if (response.errors()) {
            response.items().forEach(item -> {
                if (item.error() != null) {
                    System.err.println(&#34;错误: &#34; + item.error().reason());
                }
            });
        }
        
        return response;
    }
}
相关推荐
洋亦3 小时前
GoF23种设计模式 简介
java
Javatutouhouduan3 小时前
Java面试常问Redis核心知识点整理!
java·数据库·redis·java面试·后端开发·java架构师·java程序员
AAA简单玩转程序设计3 小时前
谁说Java枚举只是“常量装盒”?它藏着这些骚操作
java·前端
枯基Evan3 小时前
applicationTaskExecutor Spring 内置线程池失效
java·数据库·spring
优爱蛋白3 小时前
IL-21:后Th1/Th2时代的免疫新星
java·服务器·前端·人工智能·健康医疗
温宇飞3 小时前
SQL 语法基础指南
后端
Dolphin_Home3 小时前
【实用工具类】NullSafeUtils:一站式解决Java空值安全与通用操作(附完整源码)
java·网络·spring boot·后端·spring
高山上有一只小老虎3 小时前
判断是否为数独数组
java·算法
郡杰3 小时前
Spring(3-AOP)
后端