什么是RestClient
RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。
RestClient 主要特点
轻量级:只负责 HTTP 通信,不包含高级功能
兼容性好:支持所有 Elasticsearch 版本
灵活性强:可以自定义请求和响应处理
线程安全:可以被多线程共享使用
性能优秀:内置连接池和失败重试机制
ES中支持两种地理坐标数据类型: geo_point:由纬度(latitude)和经度(longitude)确定的一个点。
例如:"32.8752345,120.2981576 geo_shape:有多个geo_point组成的复杂几何图形。例如一条直线 "LINESTRING(-77.03653 38.897676,-77.009051 38.889939)
字段拷贝可以使用copy_to属性将当前字段拷贝到指定字段。用来解决多个搜索字段共同搜索时的效率问题示例:
"all":{ "type":"text", "analyzer":"ik_max_word" }, "brand":{ "type":"keyword", "copy_to":"all" }
初始化RestClient
创建
ElasticsearchUtil.java
工具类:import org.apache.http.HttpHost; import org.elasticsearch.client.RestClient; import org.elasticsearch.client.RestClientBuilder; import org.elasticsearch.client.RestHighLevelClient; public class ElasticsearchUtil { private static RestHighLevelClient client; public static void init() { // 配置ES集群地址,可以配置多个 RestClientBuilder builder = RestClient.builder( new HttpHost("localhost", 9200, "http") // 可以添加更多节点 // new HttpHost("localhost", 9201, "http") ); // 可选:配置连接超时、认证等 builder.setRequestConfigCallback(requestConfigBuilder -> { return requestConfigBuilder .setConnectTimeout(5000) // 连接超时时间 .setSocketTimeout(60000); // 套接字超时时间 }); client = new RestHighLevelClient(builder); } public static RestHighLevelClient getClient() { if (client == null) { init(); } return client; } public static void close() { if (client != null) { try { client.close(); } catch (Exception e) { e.printStackTrace(); } } } }
创建索引的操作
import org.elasticsearch.action.admin.indices.create.CreateIndexRequest; import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest; import org.elasticsearch.action.admin.indices.get.GetIndexRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; public class IndexOperations { private static final String INDEX_NAME = "products"; public static void main(String[] args) throws IOException { RestHighLevelClient client = ElasticsearchUtil.getClient(); // 创建索引 createIndex(client); // 检查索引是否存在 boolean exists = checkIndexExists(client); System.out.println("索引是否存在: " + exists); // 删除索引 // deleteIndex(client); ElasticsearchUtil.close(); } public static void createIndex(RestHighLevelClient client) throws IOException { CreateIndexRequest request = new CreateIndexRequest(INDEX_NAME); // 索引设置 request.settings(Settings.builder() .put("index.number_of_shards", 3) .put("index.number_of_replicas", 1) ); // 映射定义 String mapping = "{\n" + " \"properties\": {\n" + " \"id\": {\"type\": \"keyword\"},\n" + " \"name\": {\n" + " \"type\": \"text\",\n" + " \"analyzer\": \"ik_max_word\",\n" + " \"fields\": {\"keyword\": {\"type\": \"keyword\"}}\n" + " },\n" + " \"price\": {\"type\": \"double\"},\n" + " \"stock\": {\"type\": \"integer\"},\n" + " \"create_time\": {\"type\": \"date\"}\n" + " }\n" + "}"; request.mapping("_doc", mapping, XContentType.JSON); client.indices().create(request, RequestOptions.DEFAULT); System.out.println("索引创建成功"); } public static boolean checkIndexExists(RestHighLevelClient client) throws IOException { GetIndexRequest request = new GetIndexRequest(); request.indices(INDEX_NAME); return client.indices().exists(request, RequestOptions.DEFAULT); } public static void deleteIndex(RestHighLevelClient client) throws IOException { DeleteIndexRequest request = new DeleteIndexRequest(INDEX_NAME); client.indices().delete(request, RequestOptions.DEFAULT); System.out.println("索引删除成功"); } }
文档CRUD操作
import org.elasticsearch.action.DocWriteResponse; 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.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; import java.util.Date; import java.util.HashMap; import java.util.Map; public class DocumentOperations { private static final String INDEX_NAME = "products"; private static final ObjectMapper mapper = new ObjectMapper(); public static void main(String[] args) throws IOException { RestHighLevelClient client = ElasticsearchUtil.getClient(); // 添加文档 String docId = createDocument(client); // 查询文档 getDocument(client, docId); // 更新文档 updateDocument(client, docId); // 删除文档 // deleteDocument(client, docId); ElasticsearchUtil.close(); } public static String createDocument(RestHighLevelClient client) throws IOException { // 准备文档数据 Map<String, Object> document = new HashMap<>(); document.put("id", "1001"); document.put("name", "华为手机 P40"); document.put("price", 4999.00); document.put("stock", 100); document.put("create_time", new Date()); // 创建索引请求 IndexRequest request = new IndexRequest(INDEX_NAME) .id(document.get("id").toString()) // 文档ID .source(mapper.writeValueAsString(document), XContentType.JSON); // 执行请求 IndexResponse response = client.index(request, RequestOptions.DEFAULT); if (response.getResult() == DocWriteResponse.Result.CREATED) { System.out.println("文档创建成功, ID: " + response.getId()); } else if (response.getResult() == DocWriteResponse.Result.UPDATED) { System.out.println("文档更新成功, ID: " + response.getId()); } return response.getId(); } public static void getDocument(RestHighLevelClient client, String docId) throws IOException { GetRequest request = new GetRequest(INDEX_NAME, docId); GetResponse response = client.get(request, RequestOptions.DEFAULT); if (response.isExists()) { System.out.println("获取文档成功: " + response.getSourceAsString()); } else { System.out.println("文档不存在"); } } public static void updateDocument(RestHighLevelClient client, String docId) throws IOException { // 准备更新内容 Map<String, Object> updateFields = new HashMap<>(); updateFields.put("price", 4599.00); updateFields.put("stock", 80); UpdateRequest request = new UpdateRequest(INDEX_NAME, docId) .doc(mapper.writeValueAsString(updateFields), XContentType.JSON); UpdateResponse response = client.update(request, RequestOptions.DEFAULT); System.out.println("文档更新成功, 版本号: " + response.getVersion()); } public static void deleteDocument(RestHighLevelClient client, String docId) throws IOException { DeleteRequest request = new DeleteRequest(INDEX_NAME, docId); DeleteResponse response = client.delete(request, RequestOptions.DEFAULT); if (response.getResult() == DocWriteResponse.Result.DELETED) { System.out.println("文档删除成功"); } else if (response.getResult() == DocWriteResponse.Result.NOT_FOUND) { System.out.println("文档不存在"); } } }
搜索操作:重点在于如何构建查询的条件
import org.elasticsearch.action.search.SearchRequest; import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.builder.SearchSourceBuilder; import java.io.IOException; public class SearchOperations { private static final String INDEX_NAME = "products"; public static void main(String[] args) throws IOException { RestHighLevelClient client = ElasticsearchUtil.getClient(); // 简单匹配查询 searchByMatch(client); // 范围查询 // searchByRange(client); ElasticsearchUtil.close(); } public static void searchByMatch(RestHighLevelClient client) throws IOException { SearchRequest request = new SearchRequest(INDEX_NAME); // 构建查询条件 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.matchQuery("name", "华为手机")); // 设置分页 sourceBuilder.from(0); sourceBuilder.size(10); request.source(sourceBuilder); // 执行查询 SearchResponse response = client.search(request, RequestOptions.DEFAULT); System.out.println("命中总数: " + response.getHits().getTotalHits().value); System.out.println("查询耗时(ms): " + response.getTook().getMillis()); for (SearchHit hit : response.getHits().getHits()) { System.out.println("文档ID: " + hit.getId() + ", 内容: " + hit.getSourceAsString()); } } public static void searchByRange(RestHighLevelClient client) throws IOException { SearchRequest request = new SearchRequest(INDEX_NAME); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(QueryBuilders.rangeQuery("price").gte(4000).lte(5000)); request.source(sourceBuilder); SearchResponse response = client.search(request, RequestOptions.DEFAULT); System.out.println("价格在4000-5000之间的商品:"); for (SearchHit hit : response.getHits().getHits()) { System.out.println(hit.getSourceAsString()); } } }
批量进行操作
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.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentType; import java.io.IOException; import java.util.Arrays; import java.util.List; public class BulkOperations { private static final String INDEX_NAME = "products"; public static void main(String[] args) throws IOException { RestHighLevelClient client = ElasticsearchUtil.getClient(); // 准备批量数据 List<String> products = Arrays.asList( "{\"id\":\"1002\",\"name\":\"小米手机10\",\"price\":3999.00,\"stock\":50}", "{\"id\":\"1003\",\"name\":\"iPhone 12\",\"price\":6299.00,\"stock\":30}", "{\"id\":\"1004\",\"name\":\"OPPO Find X2\",\"price\":4999.00,\"stock\":40}" ); BulkRequest request = new BulkRequest(); // 添加多个操作到批量请求 for (String product : products) { String id = extractId(product); // 从JSON中提取ID request.add(new IndexRequest(INDEX_NAME) .id(id) .source(product, XContentType.JSON)); } // 执行批量操作 BulkResponse response = client.bulk(request, RequestOptions.DEFAULT); if (response.hasFailures()) { System.out.println("批量操作有部分失败: " + response.buildFailureMessage()); } else { System.out.println("批量操作全部成功"); } ElasticsearchUtil.close(); } private static String extractId(String json) { // 简单实现,实际应用中应该使用JSON解析 return json.split("\"id\":\"")[1].split("\"")[0]; } }
RestClient 提供了灵活而强大的方式来与 Elasticsearch 交互,虽然需要编写更多代码,但也提供了更精细的控制能力。对于大多数 Java 应用程序来说,这是与 Elasticsearch 集成的可靠选择。