Elasticsearch是一个基于Lucene的分布式RESTful搜索引擎,提供实时全文检索、结构化查询和数据分析能力。Elasticsearch使用Java开发,并作为Apache许可条款下的开放源码发布,是当前流行的企业级搜索引擎。
Hyplus目录
1 Elasticsearch概述
Elasticsearch具有如下优点:
- 分布式与扩展性:通过分片和副本实现水平扩展,支持PB级数据存储与高可用。
- 近实时检索:文档写入后1秒内可查,支持复杂全文检索与聚合分析。
- 灵活数据模型:原生支持JSON,动态或显式映射定义字段类型,简化数据管理。
- 生态与易用性:集成ELK栈,提供多语言客户端,配合Kibana实现可视化运维。
- 高性能优化:基于Lucene索引,支持批量操作与缓存机制,结合SSD提升查询效率。
通过合理设计索引、优化查询和集群配置,可充分发挥Elasticsearch的高性能和高可用性。实际应用中需结合业务场景,利用Kibana等工具进行监控和调优,以满足复杂搜索与分析需求。
2 核心概念
- 分布式架构
- 集群(Cluster):由一个或多个节点组成的集合,共同存储数据并提供服务。集群名称唯一标识,默认名称为
elasticsearch
。 - 节点(Node):集群中的服务器实例,分为主节点(负责集群管理)、数据节点(存储数据)和协调节点(处理请求分发)。
- 分片(Shard):索引被划分为多个分片,每个分片是独立的Lucene索引,支持水平扩展和并行操作。
- 副本(Replica):分片的拷贝,用于高可用性和负载均衡。主分片与副本不能位于同一节点。默认每个索引5个主分片和1个副本。
- 集群(Cluster):由一个或多个节点组成的集合,共同存储数据并提供服务。集群名称唯一标识,默认名称为
- 数据模型
- 索引(Index):文档的逻辑集合,类似数据库表。名称需小写且唯一。
- 文档(Document):存储的基本单位,以JSON格式表示,类似表中的行。7.0+版本后类型(Type)被弃用,文档直接隶属于索引。
- 字段(Field):文档中的数据项,类似表中的列。字段类型在映射(Mapping)中定义,支持动态映射和显式定义。
- 近实时(Near Real-Time,NRT):文档写入后约1秒内可被搜索,通过
refresh
API控制可见性。
3 基本操作(Java)
使用Elasticsearch Java High-Level REST Client(7.x版本)进行交互,需引入依赖:
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>elasticsearch-rest-high-level-client</artifactId>
<version>7.17.7</version>
</dependency>
3.1 客户端初始化
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.RestClient;
RestHighLevelClient client = new RestHighLevelClient(
RestClient.builder(new HttpHost("localhost", 9200, "http"))
);
3.2 创建索引
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.CreateIndexResponse;
CreateIndexRequest request = new CreateIndexRequest("products");
CreateIndexResponse response = client.indices().create(request);
boolean acknowledged = response.isAcknowledged(); // 确认索引创建
3.3 插入文档
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
String jsonString = "{\"name\":\"iPhone 14\",\"price\":999,\"category\":\"electronics\"}";
IndexRequest request = new IndexRequest("products")
.id("1")
.source(jsonString, XContentType.JSON);
IndexResponse response = client.index(request);
3.4 查询文档
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
GetRequest request = new GetRequest("products", "1");
GetResponse response = client.get(request);
String sourceAsString = response.getSourceAsString(); // 获取JSON内容
3.5 搜索文档
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
SearchRequest searchRequest = new SearchRequest("products");
SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
sourceBuilder.query(QueryBuilders.matchQuery("category", "electronics"));
sourceBuilder.from(0).size(10); // 分页
searchRequest.source(sourceBuilder);
SearchResponse response = client.search(searchRequest);
3.6 更新文档
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
String jsonString = "{\"price\":1099}";
UpdateRequest request = new UpdateRequest("products", "1")
.doc(jsonString, XContentType.JSON);
UpdateResponse response = client.update(request);
3.7 删除文档
import org.elasticsearch.action.delete.DeleteRequest;
import org.elasticsearch.action.delete.DeleteResponse;
DeleteRequest request = new DeleteRequest("products", "1");
DeleteResponse response = client.delete(request);
4 查询与聚合
4.1 Query DSL
Elasticsearch通过JSON格式的DSL(Domain Specific Language)定义查询逻辑,分为查询上下文(影响相关性评分)和过滤上下文(不影响评分且可缓存)。可选择如下4种查询方式:
- 全文搜索:
match
查询对文本字段分词后匹配,match_phrase
精确匹配短语。 - 精确查询:
term
匹配单个词项,terms
匹配多个词项。 - 组合查询:
bool
查询组合must
(必须匹配)、filter
(过滤)、must_not
(必须不匹配)等条件。 - 范围查询:
range
查询数值或日期范围。
【例】布尔查询:
BoolQueryBuilder boolQuery = QueryBuilders.boolQuery()
.must(QueryBuilders.matchQuery("name", "iPhone"))
.filter(QueryBuilders.rangeQuery("price").gte(900));
4.2 聚合分析
聚合用于分组统计或计算指标,如terms
桶聚合和avg
指标聚合。
【例】按分类统计平均价格:
AggregationBuilder aggregation = AggregationBuilders.terms("category_agg")
.field("category")
.subAggregation(AggregationBuilders.avg("price_avg").field("price"));
sourceBuilder.aggregation(aggregation);
SearchResponse response = client.search(searchRequest);
Terms categoryAgg = response.getAggregations().get("category_agg");
for (Terms.Bucket bucket : categoryAgg.getBuckets()) {
String category = bucket.getKeyAsString();
double avgPrice = bucket.getAggregations().get("price_avg").getAvg();
}
5 映射与分析
映射(Mapping):定义索引字段的数据类型、分词规则等。动态映射自动检测字段类型,显式映射可自定义配置,如下例所示——
CreateIndexRequest request = new CreateIndexRequest("products");
request.mapping("{\n" +
" \"properties\": {\n" +
" \"name\": {\n" +
" \"type\": \"text\",\n" +
" \"analyzer\": \"ik_max_word\"\n" +
" },\n" +
" \"price\": {\n" +
" \"type\": \"scaled_float\",\n" +
" \"scaling_factor\": 100\n" +
" }\n" +
" }\n" +
"}", XContentType.JSON);
分析器(Analyzer):由字符过滤器、分词器和标记过滤器组成,用于文本分词和标准化。内置分析器如standard
、keyword
,也可自定义,如下例所示——
request.settings("{\n" +
" \"analysis\": {\n" +
" \"analyzer\": {\n" +
" \"custom_analyzer\": {\n" +
" \"type\": \"custom\",\n" +
" \"tokenizer\": \"standard\",\n" +
" \"filter\": [\"lowercase\", \"stop\"]\n" +
" }\n" +
" }\n" +
" }\n" +
"}", XContentType.JSON);
6 分布式原理与优化
分布式搜索流程:
- 查询阶段(Query Phase):协调节点将请求广播到所有相关分片,分片返回文档ID和排序信息。
- 取回阶段(Fetch Phase):协调节点根据ID从分片拉取完整文档,合并后返回客户端。
性能优化策略:
- 索引设计:合理设置分片数(建议单个分片不超过30GB),使用时间序列索引管理日志数据。
- 查询优化:优先使用过滤上下文(
filter
),避免wildcard
和regexp
等高成本查询,限制返回字段(_source
)。 - 硬件与JVM:分配足够内存(堆内存不超过32GB),使用SSD提升I/O性能,选择G1垃圾回收器。
- 批量操作:使用
BulkRequest
批量插入或更新,减少网络开销。
【例】批量插入:
BulkRequest bulkRequest = new BulkRequest();
for (Product product : products) {
IndexRequest request = new IndexRequest("products")
.id(product.getId())
.source(objectMapper.writeValueAsString(product), XContentType.JSON);
bulkRequest.add(request);
}
BulkResponse bulkResponse = client.bulk(bulkRequest);
7 集群管理与维护
集群健康检查:通过/_cluster/health
接口查看集群状态,green
表示所有分片可用,yellow
表示部分副本未分配,red
表示主分片丢失。
分片与副本调整:
- 动态调整副本数:
UpdateSettingsRequest request = new UpdateSettingsRequest();
request.settings(Settings.builder().put("index.number_of_replicas", 2));
client.indices().updateSettings(request, RequestOptions.DEFAULT);
- 分片分配控制:通过
cluster.routing.allocation
参数控制分片在节点间的分布。
故障转移与恢复:主分片所在节点宕机时,副本分片自动提升为主分片。需配置discovery.zen.minimum_master_nodes
防止脑裂。