> 技术文档 > Elasticsearch 超详细(包含简介、下载安装、使用示例等等)不收藏超级亏!!!

Elasticsearch 超详细(包含简介、下载安装、使用示例等等)不收藏超级亏!!!


1. 引言

1.1 Elasticsearch 简介

Elasticsearch 是一个基于 Lucene 的分布式搜索和分析引擎,提供实时数据搜索、聚合分析、分布式存储等功能。其设计目标是实现高可用、可扩展、易维护,广泛应用于日志分析、电商搜索、实时监控等场景。Java 作为企业级开发的主流语言,与 Elasticsearch 的集成非常成熟,官方提供了完善的 Java 客户端库。

1.2 Java 客户端优势

  • 兼容性强:支持主流 Java 版本(Java 8+),适配 Spring、Spring Boot 等框架。
  • 功能完整:涵盖文档操作、复杂查询、聚合分析、集群管理等全功能。
  • 性能高效:通过连接池、批量操作等优化,满足高并发场景需求。

2. 环境准备

2.1 安装 Elasticsearch

2.1.1 下载与启动

  • 从 Elasticsearch 官网 下载对应版本(本文以 8.9.0 为例)。
  • 解压后执行启动命令:
    • Linux/macOS:./bin/elasticsearch
    • Windows:.\\bin\\elasticsearch.bat
  • 验证启动:访问 http://localhost:9200,返回包含集群信息的 JSON 数据。

2.1.2 配置文件

  • config/elasticsearch.yml 可配置集群名称、节点名称、网络绑定地址、端口等。
cluster: name: my-elasticsearch-clusternode: name: node-1network: host: 0.0.0.0http: port: 9200

2.2 配置 Java 开发环境

2.2.1 引入依赖(Maven)

Elasticsearch 提供两种 Java 客户端:

  • Transport Client:基于 TCP 协议,已被弃用(6.x 版本后不再推荐,8.x 版本移除)。
  • REST Client:基于 HTTP 协议,推荐使用 高级 REST 客户端(RestHighLevelClient)

添加 Maven 依赖:

  org.elasticsearch.client elasticsearch-rest-high-level-client 8.9.0  org.elasticsearch elasticsearch 8.9.0  org.apache.httpcomponents.client5 httpclient5 5.3

2.2.2 开发工具

  • IDE:IntelliJ IDEA / Eclipse
  • JDK:Java 8+(推荐 Java 11+)

3. 核心概念与术语

3.1 基本概念

概念 描述 集群 (Cluster) 由一个或多个节点组成,共享相同的集群名称,协同工作处理数据。 节点 (Node) 集群中的单个服务器实例,可作为数据节点(存储数据)或协调节点(路由请求)。 索引 (Index) 逻辑上的数据集,类似关系型数据库中的 “数据库”,由多个分片组成。 文档 (Document) 索引中的基本数据单元,以 JSON 格式存储,类似关系型数据库中的 “行”。 类型 (Type) 旧版本用于区分文档类别(6.x 版本后弃用,默认使用 _doc 类型)。 映射 (Mapping) 定义索引中文档的字段类型、分词器、存储方式等元数据,类似表结构。 分片 (Shard) 索引的物理拆分单元,分为主分片(Primary Shard)和副本分片(Replica Shard),提高吞吐量和可用性。

3.2 数据模型

  • 文档以 JSON 格式存储,每个文档有唯一 ID(自动生成或自定义)。
  • 映射支持丰富的数据类型:字符串(text、keyword)、数值(integer、double)、日期(date)、数组、对象等。

4. Java 客户端初始化

4.1 创建 RestHighLevelClient 实例

import org.apache.http.HttpHost;import org.elasticsearch.client.RestClient;import org.elasticsearch.client.RestHighLevelClient;public class ElasticsearchClientDemo { private static RestHighLevelClient client; static { // 配置集群节点(支持单个或多个节点) RestClient.builder( new HttpHost(\"localhost\", 9200, \"http\"), new HttpHost(\"node2\", 9200, \"http\") ) // 配置连接池(可选,默认配置适用于大多数场景) .setRequestConfigCallback(requestConfigBuilder -> requestConfigBuilder.setConnectTimeout(5000) // 连接超时时间(ms)  .setSocketTimeout(30000) // 套接字超时时间(ms) ) .setHttpClientConfigCallback(httpClientBuilder -> httpClientBuilder.setMaxConnTotal(100) // 最大连接数 .setDefaultCookieStore(null) ); client = new RestHighLevelClient( RestClient.builder(new HttpHost(\"localhost\", 9200, \"http\")) ); } public static void closeClient() throws IOException { if (client != null) { client.close(); } }}

4.2 SSL 加密连接(HTTPS)

若 Elasticsearch 启用 HTTPS 访问,需配置证书:

import org.apache.http.ssl.SSLContexts;import org.elasticsearch.client.RestClient;import org.elasticsearch.client.RestHighLevelClient;import java.io.File;import java.security.KeyStore;public class HttpsClientDemo { public static void main(String[] args) throws Exception { // 加载 CA 证书 KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType()); trustStore.load(new File(\"path/to/ca.crt\"), \"password\".toCharArray()); RestClient.builder(new HttpHost(\"localhost\", 9243, \"https\")) .setHttpClientConfigCallback(httpClientBuilder -> {  httpClientBuilder.setSSLContext(SSLContexts.custom() .loadTrustMaterial(trustStore, null) .build());  return httpClientBuilder; }); RestHighLevelClient client = new RestHighLevelClient( RestClient.builder(new HttpHost(\"localhost\", 9243, \"https\")) ); }}

5. 数据操作:增删改查

5.1 索引文档(Create/Index)

5.1.1 自定义文档 ID

import org.elasticsearch.action.index.IndexRequest;import org.elasticsearch.action.index.IndexResponse;import org.elasticsearch.common.xcontent.XContentType;public class IndexDocument { public static void main(String[] args) throws IOException { // 创建文档数据(JSON 格式) String docJson = \"{\\n\" + \" \\\"id\\\": 1001,\\n\" + \" \\\"name\\\": \\\"Elasticsearch 实战\\\",\\n\" + \" \\\"price\\\": 99.9,\\n\" + \" \\\"tags\\\": [\\\"搜索\\\", \\\"大数据\\\"]\\n\" + \"}\"; // 构建 IndexRequest(指定索引名、文档类型(固定为 _doc)、文档 ID) IndexRequest request = new IndexRequest(\"products\", \"_doc\", \"1001\") .source(docJson, XContentType.JSON); // 执行索引操作 IndexResponse response = client.index(request, RequestOptions.DEFAULT); // 解析响应 System.out.println(\"索引名: \" + response.getIndex()); System.out.println(\"文档 ID: \" + response.getId()); System.out.println(\"版本: \" + response.getVersion()); System.out.println(\"结果: \" + response.getResult()); // CREATED 或 UPDATED }}

5.1.2 自动生成文档 ID

IndexRequest request = new IndexRequest(\"products\", \"_doc\") .source(docJson, XContentType.JSON);

5.2 查询文档(Get)

import org.elasticsearch.action.get.GetRequest;import org.elasticsearch.action.get.GetResponse;public class GetDocument { public static void main(String[] args) throws IOException { GetRequest request = new GetRequest(\"products\", \"_doc\", \"1001\"); // 可选:指定返回字段(避免返回全量数据) request.fetchSourceContext(new FetchSourceContext(false))  .storedFields(\"_none_\"); // 不返回任何字段,仅获取元数据 GetResponse response = client.get(request, RequestOptions.DEFAULT); if (response.isExists()) { String sourceAsString = response.getSourceAsString(); // JSON 字符串 Map sourceAsMap = response.getSourceAsMap(); // Map 结构 System.out.println(\"文档存在,内容:\" + sourceAsString); } else { System.out.println(\"文档不存在\"); } }}

5.3 更新文档(Update)

5.3.1 全量更新(替换文档)

直接使用 IndexRequest,若文档 ID 已存在则覆盖。

5.3.2 部分更新(推荐)

import org.elasticsearch.action.update.UpdateRequest;import org.elasticsearch.common.xcontent.XContentBuilder;import org.elasticsearch.common.xcontent.XContentFactory;public class UpdateDocument { public static void main(String[] args) throws IOException { UpdateRequest request = new UpdateRequest(\"products\", \"_doc\", \"1001\"); // 构建更新脚本(使用 JSON 或脚本语言,如 Painless) XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject()  .field(\"doc\")  .startObject()  .field(\"price\", 109.9)  .endObject()  .endObject(); request.doc(builder); client.update(request, RequestOptions.DEFAULT); }}

5.4 删除文档(Delete)

import org.elasticsearch.action.delete.DeleteRequest;import org.elasticsearch.action.delete.DeleteResponse;public class DeleteDocument { public static void main(String[] args) throws IOException { DeleteRequest request = new DeleteRequest(\"products\", \"_doc\", \"1001\"); DeleteResponse response = client.delete(request, RequestOptions.DEFAULT); System.out.println(\"结果: \" + response.getResult()); // DELETED 或 NOT_FOUND }}

6. 复杂查询:从简单到高级

6.1 查询构建器(Query Builders)

Elasticsearch 提供丰富的查询类型,通过 QueryBuilders 类构建。

6.1.1 术语查询(Term Query)

精确匹配单个字段(不分词):

import org.elasticsearch.index.query.TermQueryBuilder;TermQueryBuilder query = QueryBuilders.termQuery(\"tags\", \"搜索\");

6.1.2 布尔查询(Bool Query)

组合多个查询条件(must、filter、should、mustNot):

import org.elasticsearch.index.query.BoolQueryBuilder;BoolQueryBuilder boolQuery = QueryBuilders.boolQuery() .must(QueryBuilders.termQuery(\"category\", \"书籍\")) // 必须匹配 .filter(QueryBuilders.rangeQuery(\"price\").lte(200)) // 过滤(不计算相关性) .should(QueryBuilders.termQuery(\"author\", \"张三\")) // 可选匹配(提升分数) .mustNot(QueryBuilders.termQuery(\"status\", \"下架\")); // 必须不匹配

6.1.3 全文搜索(Match Query)

对文本字段进行分词后匹配:

import org.elasticsearch.index.query.MatchQueryBuilder;MatchQueryBuilder matchQuery = QueryBuilders.matchQuery(\"description\", \"分布式搜索\");

6.1.4 模糊查询(Fuzzy Query)

允许拼写错误的近似匹配:

import org.elasticsearch.index.query.FuzzyQueryBuilder;FuzzyQueryBuilder fuzzyQuery = QueryBuilders.fuzzyQuery(\"name\", \"Elastcsearch\") .fuzziness(Fuzziness.AUTO); // 自动计算编辑距离

6.2 执行搜索请求

import org.elasticsearch.action.search.SearchRequest;import org.elasticsearch.action.search.SearchResponse;import org.elasticsearch.client.RequestOptions;import org.elasticsearch.index.query.QueryBuilders;import org.elasticsearch.search.SearchHit;import org.elasticsearch.search.SearchHits;import org.elasticsearch.search.builder.SearchSourceBuilder;public class SearchDocuments { public static void main(String[] args) throws IOException { // 构建搜索请求 SearchRequest searchRequest = new SearchRequest(\"products\"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); // 设置查询条件 sourceBuilder.query(QueryBuilders.termQuery(\"tags\", \"大数据\")); // 设置返回字段(排除不需要的字段) sourceBuilder.fetchSource(new String[]{\"name\", \"price\"}, new String[]{\"tags\"}); // 设置分页(默认从第 0 页开始,每页 10 条) sourceBuilder.from(0); sourceBuilder.size(20); // 设置排序 sourceBuilder.sort(\"price\", SortOrder.DESC); searchRequest.source(sourceBuilder); // 执行搜索 SearchResponse searchResponse = client.search(searchRequest, RequestOptions.DEFAULT); // 解析结果 SearchHits hits = searchResponse.getHits(); System.out.println(\"总命中数: \" + hits.getTotalHits().value); for (SearchHit hit : hits) { String docId = hit.getId(); Map sourceAsMap = hit.getSourceAsMap(); System.out.println(\"文档 ID: \" + docId + \", 内容: \" + sourceAsMap); } }}

6.3 聚合分析(Aggregation)

6.3.1 术语聚合(Terms Aggregation):分组统计

import org.elasticsearch.search.aggregations.AggregationBuilders;import org.elasticsearch.search.aggregations.bucket.terms.Terms;SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();sourceBuilder.aggregation(AggregationBuilders.terms(\"tag_agg\") .field(\"tags\") .size(10) // 最多返回 10 个桶 .order(Terms.Order.count(false)) // 降序排列);SearchResponse response = client.search(new SearchRequest(\"products\").source(sourceBuilder), RequestOptions.DEFAULT);Terms tagAgg = response.getAggregations().get(\"tag_agg\");for (Terms.Bucket bucket : tagAgg.getBuckets()) { System.out.println(\"标签: \" + bucket.getKeyAsString() + \", 数量: \" + bucket.getDocCount());}

6.3.2 数值聚合(Max/Avg/Min):统计价格最大值

sourceBuilder.aggregation(AggregationBuilders.max(\"max_price\").field(\"price\"));Max maxPrice = response.getAggregations().get(\"max_price\");System.out.println(\"最高价格: \" + maxPrice.getValue());

7. 高级功能与最佳实践

7.1 批量操作(Bulk API)

批量处理大量文档(显著提升性能):

import org.elasticsearch.action.bulk.BulkRequest;import org.elasticsearch.action.bulk.BulkResponse;public class BulkOperations { public static void main(String[] args) throws IOException { BulkRequest bulkRequest = new BulkRequest(); // 添加多个索引/删除请求 for (int i = 1002; i  { if (item.getIndex() != null && item.getIndex().isFailed()) {  System.out.println(\"索引失败: \" + item.getIndex().getFailureMessage()); } }); } }}

7.2 滚动查询(Scroll Query)

处理超过分页限制的大量数据(单次查询最多返回 10000 条,滚动查询可突破限制):

import org.elasticsearch.search.Scroll;public class ScrollSearch { public static void main(String[] args) throws IOException { Scroll scroll = new Scroll(TimeValue.timeValueMinutes(1)); // 滚动保持时间 SearchRequest searchRequest = new SearchRequest(\"large_index\"); SearchSourceBuilder sourceBuilder = new SearchSourceBuilder() .query(QueryBuilders.matchAllQuery()) .size(1000); // 每页大小 searchRequest.source(sourceBuilder).scroll(scroll); SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT); String scrollId = response.getScrollId(); SearchHit[] hits = response.getHits().getHits(); while (hits != null && hits.length > 0) { // 处理当前页数据 for (SearchHit hit : hits) { // 业务逻辑 } // 滚动获取下一页 SearchScrollRequest scrollRequest = new SearchScrollRequest(scrollId); scrollRequest.scroll(scroll); response = client.scroll(scrollRequest, RequestOptions.DEFAULT); scrollId = response.getScrollId(); hits = response.getHits().getHits(); } // 清除滚动上下文(释放资源) ClearScrollRequest clearScrollRequest = new ClearScrollRequest(); clearScrollRequest.addScrollId(scrollId); client.clearScroll(clearScrollRequest, RequestOptions.DEFAULT); }}

7.3 映射管理

7.3.1 创建索引时定义映射

import org.elasticsearch.client.indices.CreateIndexRequest;import org.elasticsearch.client.indices.CreateIndexResponse;import org.elasticsearch.common.xcontent.XContentFactory;public class CreateIndexWithMapping { public static void main(String[] args) throws IOException { CreateIndexRequest request = new CreateIndexRequest(\"blogs\"); // 定义映射 String mapping = \"{\\n\" + \" \\\"mappings\\\": {\\n\" + \" \\\"properties\\\": {\\n\" + \" \\\"title\\\": {\\\"type\\\": \\\"text\\\", \\\"analyzer\\\": \\\"ik_max_word\\\"},\\n\" + // 中文分词器 \" \\\"author\\\": {\\\"type\\\": \\\"keyword\\\"},\\n\" + // 精确匹配 \" \\\"publish_date\\\": {\\\"type\\\": \\\"date\\\", \\\"format\\\": \\\"yyyy-MM-dd HH:mm:ss\\\"}\\n\" + \" }\\n\" + \" }\\n\" + \"}\"; request.mapping(mapping, XContentType.JSON); CreateIndexResponse response = client.indices().create(request, RequestOptions.DEFAULT); if (response.isAcknowledged()) { System.out.println(\"索引创建成功\"); } }}

7.3.2 更新映射(仅支持新增字段,不能修改已有字段类型)

import org.elasticsearch.client.indices.PutMappingRequest;PutMappingRequest request = new PutMappingRequest(\"blogs\") .type(\"_doc\") .source(\"{\\\"properties\\\": {\\\"new_field\\\": {\\\"type\\\": \\\"text\\\"}}}\", XContentType.JSON);client.indices().putMapping(request, RequestOptions.DEFAULT);

7.4 别名与模板

7.4.1 索引别名(Alias)

为索引创建别名,支持动态切换底层索引(如日志按天分索引时使用 logs-* 别名):

import org.elasticsearch.client.indices.AliasRequest;import org.elasticsearch.client.indices.PutAliasRequest;PutAliasRequest request = new PutAliasRequest(\"current_products\") .addAlias(new AliasRequest.Alias(\"current_products\").index(\"products_2025\"));client.indices().putAlias(request, RequestOptions.DEFAULT);

7.4.2 模板(Template)

预定义索引映射和设置,用于自动创建索引时应用规则(如日志索引模板):

import org.elasticsearch.client.indices.PutIndexTemplateRequest;String template = \"{\\n\" + \" \\\"index_patterns\\\": [\\\"logs-*\\\"],\\n\" + \" \\\"mappings\\\": {\\n\" + \" \\\"properties\\\": {\\n\" + \" \\\"message\\\": {\\\"type\\\": \\\"text\\\", \\\"analyzer\\\": \\\"logstash_analyzer\\\"}\\n\" + \" }\\n\" + \" }\\n\" + \"}\";PutIndexTemplateRequest request = new PutIndexTemplateRequest(\"log_template\") .source(template, XContentType.JSON);client.indices().putTemplate(request, RequestOptions.DEFAULT);

8. 集成 Spring Boot

8.1 添加依赖

  org.springframework.boot spring-boot-starter-data-elasticsearch    org.elasticsearch.client elasticsearch-rest-client 

8.2 配置文件(application.yml)

spring: data: elasticsearch: cluster-name: my-elasticsearch-cluster cluster-nodes: localhost:9300 # Transport Client 端口(旧版,8.x 不推荐) rest: uris: http://localhost:9200 # 推荐使用 REST 客户端配置

8.3 定义实体类

import org.springframework.data.elasticsearch.annotations.Document;import org.springframework.data.elasticsearch.annotations.Field;import org.springframework.data.elasticsearch.annotations.FieldType;@Document(indexName = \"products\", type = \"_doc\", shards = 2, replicas = 1)public class Product { @Id private String id; @Field(type = FieldType.Text, analyzer = \"ik_max_word\") private String name; @Field(type = FieldType.Keyword) private String category; // Getter/Setter}

8.4 定义 Repository

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;public interface ProductRepository extends ElasticsearchRepository { // 自定义查询方法(基于方法名解析) List findByNameContaining(String keyword); // 复杂查询使用 @Query 注解 @Query(\"{\\\"bool\\\": {\\\"must\\\": {\\\"term\\\": {\\\"category\\\": \\\"?0\\\"}}}}\") List findByCategory(String category);}

8.5 服务层使用

import org.springframework.beans.factory.annotation.Autowired;import org.springframework.data.domain.Page;import org.springframework.data.domain.PageRequest;import org.springframework.stereotype.Service;@Servicepublic class ProductService { @Autowired private ProductRepository repository; public Product save(Product product) { return repository.save(product); } public Page search(String keyword, int page, int size) { return repository.findByNameContaining(keyword, PageRequest.of(page, size)); }}

9. 性能优化

9.1 客户端配置优化

  • 连接池调优:根据并发量设置 maxConnTotal(建议 100-200)和 maxConnPerRoute(建议 50-100)。
  • 超时控制:合理设置 connectTimeout(连接超时)和 socketTimeout(响应超时),避免长耗时阻塞。

9.2 索引设计优化

  • 映射优化
    • 对不需要搜索的字段设置 index: false
    • 对精确匹配字段使用 keyword 类型,全文搜索字段使用 text 并指定分词器。
  • 分片规划
    • 主分片数在创建索引时确定,建议单个分片大小控制在 10-50GB。
    • 副本分片数根据集群节点数和可用性需求设置(如 1 个副本提高容灾能力)。

9.3 查询优化

  • 避免深分页:使用 from + size 分页时,深度分页(如 from=10000)性能低下,建议改用滚动查询或搜索后处理。
  • 合理使用过滤(Filter):对不计算相关性的查询(如范围查询)使用 filter 而非 must,利用缓存提升性能。
  • 批量操作:使用 Bulk API 处理批量写入,减少网络开销。

9.4 集群调优

  • 节点角色分离:将节点分为数据节点、协调节点、机器学习节点,避免混合部署影响性能。
  • JVM 内存配置:设置 ES_JAVA_OPTS=\"-Xms8g -Xmx8g\",内存大小不超过物理内存的 50%,且不超过 32GB(避免压缩指针失效)。

10. 错误处理与最佳实践

10.1 异常处理

Elasticsearch 客户端抛出 ElasticsearchException 及其子类,需捕获并处理:

try { // 客户端操作} catch (ElasticsearchStatusException e) { // 处理 HTTP 状态码异常(如 404、400) int statusCode = e.statusCode(); String errorMessage = e.getMessage(); // 业务逻辑处理} catch (IOException e) { // 处理网络连接异常 // 重试或记录日志}

10.2 日志管理

配置客户端日志输出(如使用 Logback),记录关键操作和异常:

10.3 版本兼容性

  • 确保客户端版本与 Elasticsearch 服务端版本完全一致(主版本号必须相同,次版本号建议兼容)。
  • 避免跨大版本升级(如 7.x 到 8.x),需参考官方升级指南。

10.4 安全配置

  • 认证授权:启用 Elasticsearch 的 X-Pack 安全模块,使用用户名密码或 API 密钥认证。
  • HTTPS 加密:客户端与服务端通信使用 HTTPS,防止数据泄露。

11. 总结

本文系统介绍了 Java 集成 Elasticsearch 的核心技术,包括环境搭建、客户端初始化、数据操作、复杂查询、高级功能、Spring Boot 集成、性能优化和最佳实践。Elasticsearch 的 Java 客户端提供了强大且灵活的接口,能够满足从简单搜索到复杂数据分析的各种需求。在实际开发中,需根据业务场景合理设计索引结构,优化查询性能,并结合集群管理确保高可用性。


附录:常用工具与资源

  • Elasticsearch 官方文档:Java REST Client [7.17] | Elastic

  • Java 客户端 API 文档:Java High Level REST Client | Java REST Client [7.17] | Elastic

  • 分词器工具:IK 分词器(中文)、Standard 分词器(英文)

  • 集群监控:Elasticsearch Head 插件、Kibana 监控面板