Elasticsearch的高阶语法与分片策略:从概念到实战
作为后端开发者,我们对 Elasticsearch(后文简称 ES)绝不陌生。它是一个强大的分布式搜索引擎,我们常常用它来做日志分析、全文检索等。但很多时候,我们可能只是停留在"会用"的层面:创建索引、插入数据、用 match
查询。当数据量和服务规模上来后,各种问题便接踵而至:"为什么我的查询这么慢?"、"为什么集群CPU突然就满了?"、"分片数到底设多少合适?"
如果你也遇到过这些问题,那么这篇文章就是为你准备的。我们将深入探讨那些能让你的 ES 使用水平提升一个台阶的核心知识:高阶查询语法与分片策略。这不仅仅是"知其然",更是"知其所以然"的过程,帮助你从根源上理解并解决性能问题。
拒绝"慢查询":高阶语法精讲
ES 的查询 DSL (Domain Specific Language) 功能极其丰富,远不止 match
和 term
。掌握更高阶的语法,是写出高效、精准查询的第一步。
1. bool
查询:must
vs filter
的小剧场
我们都用过 bool
查询来组合多个条件,但 must
和 filter
的区别你真的清楚吗?
must
: 条件必须匹配,并且 会计算相关性得分_score
。它会问:"这个文档有多符合条件?"filter
: 条件必须匹配,但它处于"过滤器上下文(filter context)"中,不会计算得分,并且会利用缓存。它只回答:"是"或"不是"。
实战场景:假设我们在电商网站搜索"华为手机",要求必须是"5G"并且"8GB内存以上"的。
一个不够优化的查询可能是:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "华为手机" } },
{ "term": { "network_type": "5G" } },
{ "range": { "memory": { "gte": 8 } } }
]
}
}
}
这里,ES 不仅要找"5G"和"8GB内存"的手机,还要煞有介事地为"5G"和"8GB内存"这两个条件计算相关性得分,这完全是多余的计算。
更优的查询应该是:
{
"query": {
"bool": {
"must": [
{ "match": { "title": "华为手机" } }
],
"filter": [
{ "term": { "network_type": "5G" } },
{ "range": { "memory": { "gte": 8 } } }
]
}
}
}
【划重点】:将所有不需要计算相关性得分的精确匹配、范围查询等条件,统统放进 filter
子句。这能让 ES 大胆地使用缓存,性能提升非常显著。这是 ES 查询优化的第一黄金法则。
2. 聚合(Aggregations):不只是搜索,更是分析
很多人以为 ES 只是一个"搜索框",但它强大的聚合能力让它拥有了轻量级数据分析的能力。
实战场景:我们想知道网站上每个品牌的手机平均售价是多少。
{
"size": 0, // 我不关心搜索结果,只关心聚合数据
"aggs": {
"brands": { // 给这个聚合起个名字叫 "brands"
"terms": { "field": "brand.keyword" }, // 按品牌进行分组(桶聚合)
"aggs": {
"avg_price": { // 在每个品牌的分组下,再进行子聚合
"avg": { "field": "price" } // 计算价格的平均值(度量聚合)
}
}
}
}
}
这个查询会返回类似这样的结果:
"aggregations" : {
"brands" : {
"buckets" : [
{
"key" : "华为",
"doc_count" : 150,
"avg_price" : { "value" : 4999.50 }
},
{
"key" : "小米",
"doc_count" : 200,
"avg_price" : { "value" : 2999.00 }
}
]
}
}
你看,我们没有写一行后端代码,就完成了一个简单的统计分析。聚合是 ES 的精髓之一,善用它可以极大地减轻后端服务的压力。
集群的根基:分片策略
如果说查询语法是"术",那么分片策略就是"道"。错误的策略会给整个集群带来灾难性的、且难以挽回的后果。
1. 什么是分片和副本?
- 主分片 (Primary Shard): 每个索引被分成一个或多个"部分",这就是主分片。每个主分片都是一个功能完备的 Lucene 索引。一个索引的主分片数量在创建时设定,后续无法修改!
- 副本分片 (Replica Shard): 它是主分片的一个完整拷贝。它的作用有两个:
- 高可用:当主分片所在的节点宕机,副本分片可以被提升为新的主分片,保证数据不丢失。
- 提升读性能:搜索请求可以同时在主分片和副本分片上执行,提升并发查询能力。