Elasticsearch 7.x 和 8.x Java API 学习笔记与代码实现

1. Elasticsearch 基本概念

  • 索引(Index):类似数据库中的表,是文档的集合
  • 文档(Document):索引中的基本单位,类似表中的一行数据,使用JSON格式
  • 映射(Mapping):定义索引中字段的类型和属性,类似表结构
  • 分片(Shard):索引可以被分成多个分片,分布在不同的节点上
  • 副本(Replica):每个分片的副本,提供高可用性

2. Java客户端类型

  • Transport Client(已弃用):ES 7.x 中已标记为废弃,8.x 中完全移除
  • Rest High Level Client:ES 7.x 推荐使用,但8.x中也已弃用
  • Java API Client:ES 7.15+ 和 8.x 推荐使用,类型安全的新客户端

3. 依赖配置

  • ES 7.x:使用 rest-high-level-client
  • ES 8.x:使用 elasticsearch-java 客户端

代码实现

环境准备

Maven 依赖配置

ES 7.x 依赖:

<dependencies>
    <dependency>
        <groupId>org.elasticsearch.client</groupId>
        <artifactId>elasticsearch-rest-high-level-client</artifactId>
        <version>7.17.10</version>
    </dependency>
    <dependency>
        <groupId>org.elasticsearch</groupId>
        <artifactId>elasticsearch</artifactId>
        <version>7.17.10</version>
    </dependency>
</dependencies>

ES 8.x 依赖:

<dependencies>
    <dependency>
        <groupId>co.elastic.clients</groupId>
        <artifactId>elasticsearch-java</artifactId>
        <version>8.11.0</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.15.2</version>
    </dependency>
</dependencies>

ES 7.x 实现

1. 客户端初始化

import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;

public class ES7ClientUtil {
    private static RestHighLevelClient client;

    public static RestHighLevelClient getClient() {
        if (client == null) {
            RestClientBuilder build = RestClient.builder(HttpHost.create("http://192.168.101.104:9200"))
                    .setHttpClientConfigCallback(httpAsyncClientBuilder -> {
                        CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                        credentialsProvider.setCredentials(AuthScope.ANY, new UsernamePasswordCredentials("elastic", "e5nTeAjoHTTPg--WgM49"));
                        return httpAsyncClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
                    });
            client = new RestHighLevelClient(build);
        }
        return client;
    }
        

    public static void closeClient() throws IOException {
        if (client != null) {
            client.close();
        }
    }
}

2. 索引操作

import org.elasticsearch.action.admin.indices.create.CreateIndexRequest;
import org.elasticsearch.action.admin.indices.create.CreateIndexResponse;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;

public class ES7IndexOperations {

    // 创建索引
    public static boolean createIndex(String indexName) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        CreateIndexRequest request = new CreateIndexRequest(indexName);
        request.settings(Settings.builder()
            .put("index.number_of_shards", 3)
            .put("index.number_of_replicas", 2)
        );

        // 定义映射(也可以不定义,直接插入数据)
        String mapping = "{\n" +
            "  \"properties\": {\n" +
            "    \"title\": {\n" +
            "      \"type\": \"text\"\n" +
            "    },\n" +
            "    \"content\": {\n" +
            "      \"type\": \"text\"\n" +
            "    },\n" +
            "    \"createTime\": {\n" +
            "      \"type\": \"date\"\n" +
            "    },\n" +
            "    \"author\": {\n" +
            "      \"type\": \"keyword\"\n" +
            "    }\n" +
            "  }\n" +
            "}";

        request.mapping(mapping, XContentType.JSON);

        CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }

    // 删除索引
    public static boolean deleteIndex(String indexName) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        DeleteIndexRequest request = new DeleteIndexRequest(indexName);
        AcknowledgedResponse response = client.indices().delete(request, RequestOptions.DEFAULT);
        return response.isAcknowledged();
    }
}

3. 文档操作

import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;

public class ES7DocumentOperations {

    // 添加文档
    public static String addDocument(String indexName, String jsonDocument) throws IOException {
        return addDocument(indexName, null, jsonDocument);
    }

    public static String addDocument(String indexName, String id, String jsonDocument) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        IndexRequest request = new IndexRequest(indexName);
        if (id != null && !id.isEmpty()) {
            request.id(id);
        }
        request.source(jsonDocument, XContentType.JSON);

        IndexResponse response = client.index(request, RequestOptions.DEFAULT);
        return response.getId();
    }

    // 获取文档
    public static String getDocument(String indexName, String id) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        GetRequest request = new GetRequest(indexName, id);
        GetResponse response = client.get(request, RequestOptions.DEFAULT);

        if (response.isExists()) {
            return response.getSourceAsString();
        } else {
            return null;
        }
    }

    // 更新文档
    public static boolean updateDocument(String indexName, String id, String jsonDocument) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        UpdateRequest request = new UpdateRequest(indexName, id);
        request.doc(jsonDocument, XContentType.JSON);

        UpdateResponse response = client.update(request, RequestOptions.DEFAULT);
        return response.getResult() == UpdateResponse.Result.UPDATED;
    }

    // 删除文档
    public static boolean deleteDocument(String indexName, String id) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        DeleteRequest request = new DeleteRequest(indexName, id);
        DeleteResponse response = client.delete(request, RequestOptions.DEFAULT);

        return response.getResult() == DeleteResponse.Result.DELETED;
    }
}

4. 批量操作

import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.common.xcontent.XContentType;

public class ES7BulkOperations {

    // 批量添加文档
    public static boolean bulkAddDocuments(String indexName, List<String> jsonDocuments) throws IOException {
        RestHighLevelClient client = ES7ClientUtil.getClient();

        BulkRequest request = new BulkRequest();

        for (String jsonDoc : jsonDocuments) {
            IndexRequest indexRequest = new IndexRequest(indexName);
            indexRequest.source(jsonDoc, XContentType.JSON);
            request.add(indexRequest);
        }

        BulkResponse response = client.bulk(request, RequestOptions.DEFAULT);
        return !response.hasFailures();
    }
}

ES 8.x 实现

1. 客户端初始化

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.ElasticsearchTransport;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;

public class ES8ClientUtil {
    private static ElasticsearchClient client;

    public static ElasticsearchClient getClient() {
        if (client == null) {
            // 创建低级客户端
            RestClient restClient = RestClient.builder(
                new HttpHost("localhost", 9200)
            ).build();

            // 使用Jackson映射器创建传输层
            ElasticsearchTransport transport = new RestClientTransport(
                restClient, new JacksonJsonpMapper()
            );

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

2. 索引操作

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.indices.CreateIndexRequest;
import co.elastic.clients.elasticsearch.indices.CreateIndexResponse;
import co.elastic.clients.elasticsearch.indices.DeleteIndexRequest;
import co.elastic.clients.elasticsearch.indices.DeleteIndexResponse;

public class ES8IndexOperations {

    // 创建索引
    public static boolean createIndex(String indexName) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        CreateIndexResponse response = client.indices().create(
            CreateIndexRequest.of(b -> b
                .index(indexName)
                .settings(s -> s
                    .numberOfShards("3")
                    .numberOfReplicas("2")
                )
                .mappings(m -> m
                    .properties("title", p -> p.text(t -> t))
                    .properties("content", p -> p.text(t -> t))
                    .properties("createTime", p -> p.date(d -> d))
                    .properties("author", p -> p.keyword(k -> k))
                )
            )
        );

        return response.acknowledged();
    }

    // 删除索引
    public static boolean deleteIndex(String indexName) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        DeleteIndexResponse response = client.indices().delete(
            DeleteIndexRequest.of(b -> b.index(indexName))
        );

        return response.acknowledged();
    }
}

3. 文档操作

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public class ES8DocumentOperations {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 添加文档
    public static String addDocument(String indexName, String jsonDocument) throws IOException {
        return addDocument(indexName, null, jsonDocument);
    }

    public static String addDocument(String indexName, String id, String jsonDocument) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        IndexRequest.Builder<JsonNode> requestBuilder = new IndexRequest.Builder<>();
        requestBuilder.index(indexName);
        if (id != null && !id.isEmpty()) {
            requestBuilder.id(id);
        }

        JsonNode jsonNode = objectMapper.readTree(jsonDocument);
        requestBuilder.document(jsonNode);

        IndexResponse response = client.index(requestBuilder.build());
        return response.id();
    }

    // 获取文档
    public static String getDocument(String indexName, String id) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        GetResponse<JsonNode> response = client.get(
            g -> g.index(indexName).id(id), JsonNode.class
        );

        if (response.found()) {
            return response.source().toString();
        } else {
            return null;
        }
    }

    // 更新文档
    public static boolean updateDocument(String indexName, String id, String jsonDocument) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        JsonNode jsonNode = objectMapper.readTree(jsonDocument);
        UpdateResponse<JsonNode> response = client.update(
            u -> u.index(indexName).id(id).doc(jsonNode), JsonNode.class
        );

        return response.result().name().equals("Updated");
    }

    // 删除文档
    public static boolean deleteDocument(String indexName, String id) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        DeleteResponse response = client.delete(
            d -> d.index(indexName).id(id)
        );

        return response.result().name().equals("Deleted");
    }
}

4. 批量操作

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.bulk.BulkOperation;
import co.elastic.clients.elasticsearch.core.bulk.IndexOperation;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.util.ArrayList;
import java.util.List;

public class ES8BulkOperations {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    // 批量添加文档
    public static boolean bulkAddDocuments(String indexName, List<String> jsonDocuments) throws IOException {
        ElasticsearchClient client = ES8ClientUtil.getClient();

        List<BulkOperation> operations = new ArrayList<>();

        for (String jsonDoc : jsonDocuments) {
            JsonNode jsonNode = objectMapper.readTree(jsonDoc);
            operations.add(BulkOperation.of(b -> b
                .index(IndexOperation.of(i -> i
                    .index(indexName)
                    .document(jsonNode)
                ))
            ));
        }

        BulkRequest request = BulkRequest.of(b -> b.operations(operations));
        BulkResponse response = client.bulk(request);

        return !response.errors();
    }
}

使用示例

public class ElasticsearchExample {
    public static void main(String[] args) {
        try {
            // ES 7.x 示例
            System.out.println("=== ES 7.x 示例 ===");

            // 创建索引
            boolean created = ES7IndexOperations.createIndex("blog");
            System.out.println("索引创建: " + (created ? "成功" : "失败"));

            // 添加文档
            String document = "{\"title\":\"Elasticsearch入门\",\"content\":\"这是一篇关于ES的入门文章\",\"createTime\":\"2023-01-01\",\"author\":\"张三\"}";
            String docId = ES7DocumentOperations.addDocument("blog", document);
            System.out.println("文档添加成功,ID: " + docId);

            // 获取文档
            String retrievedDoc = ES7DocumentOperations.getDocument("blog", docId);
            System.out.println("获取的文档: " + retrievedDoc);

            // ES 8.x 示例
            System.out.println("\n=== ES 8.x 示例 ===");

            // 创建索引
            created = ES8IndexOperations.createIndex("news");
            System.out.println("索引创建: " + (created ? "成功" : "失败"));

            // 添加文档
            String newsDoc = "{\"title\":\"Java新闻\",\"content\":\"关于Java的最新消息\",\"createTime\":\"2023-02-01\",\"author\":\"李四\"}";
            String newsId = ES8DocumentOperations.addDocument("news", newsDoc);
            System.out.println("文档添加成功,ID: " + newsId);

            // 获取文档
            String retrievedNews = ES8DocumentOperations.getDocument("news", newsId);
            System.out.println("获取的文档: " + retrievedNews);

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Spring Boot配置完成后,自动配置,直接注入RestHighLevelClient 使用

pom.xml

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-elasticsearch</artifactId>
<!--            <version>${elasticsearch.version}</version>-->
        </dependency>

        <dependency>
            <groupId>org.elasticsearch</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>transport</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.distribution.integ-test-zip</groupId>
            <artifactId>elasticsearch</artifactId>
            <version>${elasticsearch.version}</version>
            <type>zip</type>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.plugin</groupId>
            <artifactId>transport-netty4-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-client</artifactId>
            <version>${elasticsearch.version}</version>
            <exclusions>
                <exclusion>
                    <artifactId>commons-logging</artifactId>
                    <groupId>commons-logging</groupId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.elasticsearch.client</groupId>
            <artifactId>elasticsearch-rest-high-level-client</artifactId>
            <version>${elasticsearch.version}</version>
        </dependency>

application.yml

spring:
  elasticsearch:
    rest:
      uris: http://192.168.101.104:9200
      username: elastic
      password: 123456
      connection-timeout: 2s
  data:
    elasticsearch:
      repositories:
        enabled: true

实体类映射(POJO → ES 文档)​​

通过注解将 Java 对象映射为 ES 文档,关键注解包括:

@Document 标记类为 ES 文档,indexName 指定索引名,shards/replicas 分片配置。
@Id 标记主键字段(自动生成或手动指定)。
@Field 标记字段,type 指定 ES 数据类型(如 Text、Keyword、Date 等)。
@CreateDate 自动填充文档创建时间(需配合 @Field(type = Date))。
@UpdateDate 自动填充文档更新时间。

注意事项

  1. 版本兼容性:确保客户端版本与Elasticsearch服务器版本匹配
  2. 异常处理:在实际应用中需要添加适当的异常处理逻辑
  3. 连接管理:生产环境中需要考虑连接池管理和超时设置
  4. 安全性:如果ES集群启用了安全认证,需要在客户端配置认证信息
  5. 性能优化:批量操作时适当控制批量大小,避免内存溢出

示例代码:https://gitee.com/little_lunatic/advance/tree/main/elasticsearch

posted @ 2025-08-31 01:10  little_lunatic  阅读(2)  评论(0)    收藏  举报