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
自动填充文档更新时间。
注意事项
- 版本兼容性:确保客户端版本与Elasticsearch服务器版本匹配
- 异常处理:在实际应用中需要添加适当的异常处理逻辑
- 连接管理:生产环境中需要考虑连接池管理和超时设置
- 安全性:如果ES集群启用了安全认证,需要在客户端配置认证信息
- 性能优化:批量操作时适当控制批量大小,避免内存溢出
示例代码:https://gitee.com/little_lunatic/advance/tree/main/elasticsearch