谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他
INFINI Labs 小助手 发表了文章 • 0 个评论 • 136 次浏览 • 17 小时前

这是 ES 7.10 相较于 ES 6.8 新增内容的最后一篇,主要涉及算分方法和同义词加载的部分。
自定义算分:script_score 2.0
Elasticsearch 7.0 引入了新一代的函数分数功能,称为 script_score
查询。这一新功能提供了一种更简单、更灵活的方式来为每条记录生成排名分数。script_score
查询由一组函数构成,包括算术函数和距离函数,用户可以根据需要混合和匹配这些函数,以构建任意的分数计算逻辑。这种模块化的结构使得使用更加简便,同时也为更多用户提供了这一重要功能的访问权限。通过 script_score
,用户可以根据复杂的业务逻辑自定义评分,而不仅仅依赖于传统的 TF-IDF 或 BM25 算法。例如,可以根据文档的地理位置、时间戳、或其他自定义字段的值来调整评分,从而更精确地控制搜索结果的排序。
script_score 是 ES 对 function score 功能的一个迭代替换。
常用函数
基本函数
用于对字段值或评分进行基本的数学运算。
doc[<field>].value
获取文档中某个字段的值。
<br /> "script": {<br /> "source": "doc['price'].value * 1.2"<br /> }<br />
算术运算
支持加 (+
)、减 (-
)、乘 (*
)、除 (/
)、取模 (%
) 等操作。
<br /> "script": {<br /> "source": "doc['price'].value + (doc['discount'].value * 0.5)"<br /> }<br />
Saturation 函数
saturation
函数用于对字段值进行饱和处理,限制字段值对评分的影响范围。
<br /> "script": {<br /> "source": "saturation(doc['<field_name>'].value, <pivot>)"<br /> }<br />
<field_name>
: 需要处理的字段。<pivot>
: 饱和点(pivot),当字段值达到该值时,评分增益趋于饱和。
<br /> //在这个示例中,`likes` 字段的值在达到 `100` 后,对评分的影响会趋于饱和。<br /> {<br /> "query": {<br /> "script_score": {<br /> "query": {<br /> "match_all": {}<br /> },<br /> "script": {<br /> "source": "saturation(doc['likes'].value, 100)"<br /> }<br /> }<br /> }<br /> }<br />
Sigmoid 函数
sigmoid
函数用于对字段值进行 S 形曲线变换,平滑地调整字段值对评分的影响。
<br /> "script": {<br /> "source": "sigmoid(doc['<field_name>'].value, <pivot>, <exponent>)"<br /> }<br />
-
需要处理的字段。
-
中心点(pivot),S 形曲线的中点。
-
指数,控制曲线的陡峭程度。
```
//在这个示例中,`likes` 字段的值在 `50` 附近对评分的影响最为显著,而随着值远离 `50`,影响会逐渐平滑。
{
"query": {
"script_score": {
"query": {
"match_all": {}
},
"script": {
"source": "sigmoid(doc['likes'].value, 50, 0.5)"
}
}
}
}
```
#### 距离衰减函数
用于衰减计算地理位置的函数。
```
//相关函数
double decayGeoLinear(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
double decayGeoExp(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
double decayGeoGauss(String originStr, String scaleStr, String offsetStr, double decay, GeoPoint docValue)
"script" : {
"source" : "decayGeoExp(params.origin, params.scale, params.offset, params.decay, doc['location'].value)",
"params": {
"origin": "40, -70.12",
"scale": "200km",
"offset": "0km",
"decay" : 0.2
}
}
```
#### 数值衰减函数
用于衰减计算数值的函数。
```
//相关函数
double decayNumericLinear(double origin, double scale, double offset, double decay, double docValue)
double decayNumericExp(double origin, double scale, double offset, double decay, double docValue)
double decayNumericGauss(double origin, double scale, double offset, double decay, double docValue)
"script" : {
"source" : "decayNumericLinear(params.origin, params.scale, params.offset, params.decay, doc['dval'].value)",
"params": {
"origin": 20,
"scale": 10,
"decay" : 0.5,
"offset" : 0
}
}
```
#### 日期衰减函数
用于衰减计算日期的函数。
```
//相关函数
double decayDateLinear(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
double decayDateExp(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
double decayDateGauss(String originStr, String scaleStr, String offsetStr, double decay, JodaCompatibleZonedDateTime docValueDate)
"script" : {
"source" : "decayDateGauss(params.origin, params.scale, params.offset, params.decay, doc['date'].value)",
"params": {
"origin": "2008-01-01T01:00:00Z",
"scale": "1h",
"offset" : "0",
"decay" : 0.5
}
}
```
#### 随机函数
用于生成随机评分。
_randomNotReproducible`_ 生成一个随机评分。
```
"script" : {
"source" : "randomNotReproducible()"
}
```
_randomReproducible_ 使用种子值生成可重复的随机评分。
```
"script" : {
"source" : "randomReproducible(Long.toString(doc['_seq_no'].value), 100)"
}
```
#### 字段值因子
用于根据字段值调整评分。
_field_value_factor`_ 根据字段值调整评分。
```
"script" : {
"source" : "Math.log10(doc['field'].value * params.factor)",
params" : {
"factor" : 5
}
}
```
#### 其他实用函数
- Math.log:计算对数,
Math.log(doc['price'].value)
- Math.sqrt:计算平方根,
Math.sqrt(doc['popularity'].value)
- Math.pow:计算幂次,
Math.pow(doc['score'].value, 2)
同义词字段重加载
Elasticsearch 7.3 引入了同义词字段重加载功能,允许用户在更新同义词文件后,无需重新索引即可使更改生效。
这一功能极大地简化了同义词管理的流程,尤其是在需要频繁更新同义词的场景下。通过_reload_search_analyzers
API,用户可以重新加载指定索引的分词器,从而使新的同义词规则立即生效。
注意,虽然同义词词典能被热加载,但是已经生成的索引数据不会被修改。
测试代码
<br /> PUT /my_index<br /> {<br /> "settings": {<br /> "index" : {<br /> "analysis" : {<br /> "analyzer" : {<br /> "my_synonyms" : {<br /> "tokenizer" : "whitespace",<br /> "filter" : ["synonym"]<br /> }<br /> },<br /> "filter" : {<br /> "synonym" : {<br /> "type" : "synonym_graph",<br /> "synonyms_path" : "analysis/synonym.txt",<br /> "updateable" : true<br /> }<br /> }<br /> }<br /> }<br /> },<br /> "mappings": {<br /> "properties": {<br /> "text": {<br /> "type": "text",<br /> "analyzer" : "standard",<br /> "search_analyzer": "my_synonyms"<br /> }<br /> }<br /> }<br /> }<br /> <br /> POST /my_index/_reload_search_analyzers<br />
执行上述请求后,Elasticsearch 会重新加载my_index
索引的分析器,使最新的同义词规则生效。
case insensitive 参数
case_insensitive
参数允许用户在执行精确匹配查询时忽略大小写。
这一功能特别适用于需要处理大小写不敏感数据的场景,例如用户名、标签或分类代码等。通过设置case_insensitive
为true
,用户可以在不修改数据的情况下,实现对大小写不敏感的查询,从而简化查询逻辑并提高搜索的准确性。
测试代码
<br /> //在这个示例中,`term` 查询会匹配 `user` 字段值为 `JohnDoe`、`johndoe` 或 `JOHNDOE` 的文档,而忽略大小写差异。<br /> {<br /> "query": {<br /> "term": {<br /> "user": {<br /> "value": "JohnDoe",<br /> "case_insensitive": true<br /> }<br /> }<br /> }<br /> }<br />
小结
Elasticsearch 作为一款强大的开源搜索和分析引擎,其版本的不断迭代带来了诸多显著的改进与优化。对比 Elasticsearch 6.8,Elasticsearch 7.10 在多个方面展现出了新的功能和特性,极大地提升了用户体验和系统性能。这系列文章简短的介绍了各个方面的新功能和优化,希望能给大家一定的帮助。
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
- [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
- [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
- [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)
关于极限科技(INFINI Labs)

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。
极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。
官网:<https://infinilabs.cn>
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/202 ... rt-6/
谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理
INFINI Labs 小助手 发表了文章 • 0 个评论 • 136 次浏览 • 17 小时前

这一篇我们继续了解 ES 7.10 相较于 ES 6.8 调优的集群管理和任务管理的方法,主要有断联查询的主动取消、投票节点角色、异步查询和可搜索快照四个功能。
Query 自动取消
对于一个完善的产品来说,当一个任务发起链接主动断联的时候,服务端与之相关的任务应该也都被回收。但是这个特性到了 elasticsearch 7.4 版本才有了明确的声明。
Elasticsearch now automatically terminates queries sent through the _search endpoint when the initiating connection is closed.
相关的 PR 和 issue 在这里,对源码有兴趣的同学可以挖掘一下。
PR:https://github.com/elastic/ela ... 43332
issue:https://github.com/elastic/ela ... 43105
简单来说,ES 接受在某个查询的 http 链接断掉的时候,与其相关的父子任务的自动取消。原来的场景下可能需要手工一个个关闭。
实际测试
利用 painless 模拟复杂查询,下面这个查询在测试集群上能维持 5s 左右
<br /> GET /_search?max_concurrent_shard_requests=1<br /> {<br /> "query": {<br /> "bool": {<br /> "must": [<br /> {<br /> "script": {<br /> "script": {<br /> "lang": "painless",<br /> "source": """<br /> long sum = 0;<br /> for (int i = 0; i < 100000; i++) {<br /> sum += i;<br /> }<br /> return true;<br /> """<br /> }<br /> }<br /> },<br /> {<br /> "script": {<br /> "script": {<br /> "lang": "painless",<br /> "source": """<br /> long product = 1;<br /> for (int i = 1; i < 100000; i++) {<br /> product *= i;<br /> }<br /> return true;<br /> """<br /> }<br /> }<br /> },<br /> {<br /> "script": {<br /> "script": {<br /> "lang": "painless",<br /> "source": """<br /> long factorial = 1;<br /> for (int i = 1; i < 100000; i++) {<br /> factorial *= i;<br /> }<br /> long squareSum = 0;<br /> for (int j = 0; j < 100000; j++) {<br /> squareSum += j * j;<br /> }<br /> return true;<br /> """<br /> }<br /> }<br /> },<br /> {<br /> "script": {<br /> "script": {<br /> "lang": "painless",<br /> "source": """<br /> long fib1 = 0;<br /> long fib2 = 1;<br /> long next;<br /> for (int i = 0; i < 100000; i++) {<br /> next = fib1 + fib2;<br /> fib1 = fib2;<br /> fib2 = next;<br /> }<br /> return true;<br /> """<br /> }<br /> }<br /> }<br /> ]<br /> }<br /> }<br /> }<br />
查看任务被终止的状态
<br /> GET /_tasks?detailed=true&actions=*search*<br />
测试脚本,判断上面该查询被取消后是否还可以查到任务
```python
import requests
import multiprocessing
import time
from requests.exceptions import RequestException
from datetime import datetime
Elasticsearch 地址
ES_URL = "<a href="http://localhost:9210"" rel="nofollow" target="_blank">http://localhost:9210" # 6.8版本地址
ES_URL = "<a href="http://localhost:9201"" rel="nofollow" target="_blank">http://localhost:9201"
耗时查询的 DSL
LONG_RUNNING_QUERY = {"size":0,
"query": {
"bool": {
"must": [
{
"script": {
"script": {
"lang": "painless",
"source": """
long sum = 0;
for (int i = 0; i < 100000; i++) {
sum += i;
}
return true;
"""
}
}
},
{
"script": {
"script": {
"lang": "painless",
"source": """
long product = 1;
for (int i = 1; i < 100000; i++) {
product = i;
}
return true;
"""
}
}
},
{
"script": {
"script": {
"lang": "painless",
"source": """
long factorial = 1;
for (int i = 1; i < 100000; i++) {
factorial = i;
}
long squareSum = 0;
for (int j = 0; j < 100000; j++) {
squareSum += j * j;
}
return true;
"""
}
}
},
{
"script": {
"script": {
"lang": "painless",
"source": """
long fib1 = 0;
long fib2 = 1;
long next;
for (int i = 0; i < 100000; i++) {
next = fib1 + fib2;
fib1 = fib2;
fib2 = next;
}
return true;
"""
}
}
}
]
}
}
}
用于同步的事件对象
query_finished = multiprocessing.Event()
新增:进程终止标志位
process_terminated = multiprocessing.Event()
定义一个函数用于添加时间戳到日志
def log_with_timestamp(message,*message1):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] {message}+{message1}")
发起查询的函数
def run_query():
try:
log_with_timestamp("发起查询...")
session = requests.Session()
response = session.post(
f"{ES_URL}/_search",
json=LONG_RUNNING_QUERY,
stream=True # 启用流式请求,允许后续中断
)
try:尝试读取响应内容(如果连接未被中断)
if response.status_code == 200:
log_with_timestamp("查询完成,结果:", response.json())
else:
log_with_timestamp("查询失败,错误信息:", response.text)
except RequestException as e:
log_with_timestamp("请求被中断:", e)
finally:标记查询完成
query_finished.set()
中断连接的信号函数
def interrupt_signal():
time.sleep(1) # 等待 1 秒
log_with_timestamp("发出中断查询信号...")标记可以中断查询了
query_finished.set()
检测任务是否存在的函数
def check_task_exists():
等待进程终止标志位
process_terminated.wait()
max_retries = 3
retries = 0
time.sleep(1) #1s后检查
while retries < max_retries:
log_with_timestamp("检查任务是否存在...")
tasks_url = f"{ES_URL}/_tasks?detailed=true&actions=search"
try:
tasks_response = requests.get(tasks_url)
if tasks_response.status_code == 200:
tasks = tasks_response.json().get("nodes")
if tasks:
log_with_timestamp("任务仍存在:", tasks)
else:
log_with_timestamp("任务已消失")
break
else:
log_with_timestamp("获取任务列表失败,错误信息:", tasks_response.text)
except RequestException as e:
log_with_timestamp(f"检测任务失败(第 {retries + 1} 次重试): {e}")
retries += 1
time.sleep(1) # 等待 1 秒后重试
if retries == max_retries:
log_with_timestamp("达到最大重试次数,无法检测任务状态。")
主函数
def main():
启动查询进程
query_process = multiprocessing.Process(target=run_query)
query_process.start()
启动中断信号进程
interrupt_process = multiprocessing.Process(target=interrupt_signal)
interrupt_process.start()
等待中断信号
query_finished.wait()
检查查询进程是否还存活并终止它
if query_process.is_alive():
log_with_timestamp("尝试中断查询进程...")
query_process.terminate()
log_with_timestamp("查询进程已终止")新增:设置进程终止标志位
process_terminated.set()
启动任务检测进程
check_process = multiprocessing.Process(target=check_task_exists)
check_process.start()
等待所有进程完成
query_process.join()
interrupt_process.join()
check_process.join()
if name == "main":
main()
<br /> <br /> 实际测试结果:<br /> <br />
shell6.8 版本
[2025-02-08 15:17:21] 发起查询...+()
[2025-02-08 15:17:22] 发出中断查询信号...+()
[2025-02-08 15:17:22] 尝试中断查询进程...+()
[2025-02-08 15:17:22] 查询进程已终止+()
[2025-02-08 15:17:23] 检查任务是否存在...+()
[2025-02-08 15:17:23] 任务仍存在:+({'fYMNv_KxQGCGzhgfMxPXuA': {......}},)
<br /> <br /> 可以看到在查询任务被终止后 1s 再去检查,任务仍然存在<br /> <br />
shell7.10 版本
[2025-02-08 15:18:16] 发起查询...+()
[2025-02-08 15:18:17] 发出中断查询信号...+()
[2025-02-08 15:18:17] 尝试中断查询进程...+()
[2025-02-08 15:18:17] 查询进程已终止+()
[2025-02-08 15:18:18] 检查任务是否存在...+()
[2025-02-08 15:18:18] 任务已消失+()
```
这里可以看到任务已经检测不到了。
关于 timeout 配置
这里展开讨论下,timeout 配置。超时回收处理是一个‘best effort’行为。
(Optional, time units) Specifies the period of time to wait for a response. If no response is received before the timeout expires, the request fails and returns an error. Defaults to no timeout.
the search request is more of a best effort and does not guarantee that the request will never last longer than the specified amount of time.
异步搜索
使用方法
可以让用户进行异步的搜索,可以通过相关参数进行检查维护该搜索的状态和结果。比较合适查询量较大但对延迟要求较低的查询,进行精细化的管理控制。
注意:这里的参数基本都是添加到 url 上的,并不是添加到 request body 上的。
<br /> POST test_index/_async_search?keep_on_completion=true<br /> {<br /> "query": {<br /> "match_all": {}<br /> }<br /> }<br />
注:这里为了产生查询结果 id 使用了 keep_on_completion 参数,这个参数的使用见下面解释。
返回结果,和一般的查询结果不同的是,添加了结果 id 和查询的一些状态数据。
json<br /> {<br /> "id": "Fmk2b0VjM2FEVE9Dbk9TemVyOTlkMncbOFlwRGU2OWZTa2kxNEpoT0Q2bVZrZzozODIz",//结果id,可以用于后续的复查<br /> "is_partial": false,//是否为部分完成结果<br /> "is_running": false,//是否还在查询<br /> "start_time_in_millis": 1738978637287,//查询产生时间戳<br /> "expiration_time_in_millis": 1739410637287,//查询结果过期时间戳<br /> "response": {<br /> "took": 1,<br /> "timed_out": false,<br /> "_shards": {<br /> "total": 1,<br /> "successful": 1,<br /> "skipped": 0,<br /> "failed": 0<br /> },<br /> "hits": {<br /> "total": {<br /> "value": 3,<br /> "relation": "eq"<br /> },<br /> "max_score": 1,<br /> "hits": [······]<br /> }<br /> }<br /> }<br />
管理查询结果
<br /> //查询结果和第一次返回的内容一致<br /> GET /_async_search/Fmk2b0VjM2FEVE9Dbk9TemVyOTlkMncbOFlwRGU2OWZTa2kxNEpoT0Q2bVZrZzozODIz<br /> <br /> //主动删除查询结果<br /> DELETE /_async_search/Fmk2b0VjM2FEVE9Dbk9TemVyOTlkMncbOFlwRGU2OWZTa2kxNEpoT0Q2bVZrZzozODIz<br /> <br />
关键参数
- wait_for_completion_timeout:参数(默认为 1 秒),这个参数用来设置异步查询的等待时间。当异步搜索在此时间内完成时,响应将不包括 ID,结果也不会存储在集群中。
- keep_on_completion:参数(默认为 false)可以设置为 true,可以强制存储查询结果,即便在 wait_for_completion_timeout 设置时间内完成搜索,该结果也能被查询到。
- keep_alive:指定异步搜索结果可以被保存多长时间,默认为 5d(5 天)。在此期间之后,正在进行的异步搜索和任何保存的搜索结果将被删除。
- batched_reduce_size:是 Elasticsearch 中的一个配置参数,默认值为 5。它的作用是控制分片结果的部分归并频率,具体来说,它决定了协调节点(coordinating node)在接收到多少个分片的响应后,会执行一次部分结果归并(partial reduction)。
- pre_filter_shard_size:是 Elasticsearch 中与查询执行相关的一个参数,它的默认值为 1,并且不可更改。这个参数的作用是强制 Elasticsearch 在执行查询之前,先进行一轮预过滤(pre-filter),以确定哪些分片(shard)可能包含与查询匹配的文档,从而跳过那些肯定不包含匹配文档的分片。
查询结果存储位置
异步查询的结果部分存储在.async-search
中,但是进行了程序加密,内容对使用者不可见。
<br /> GET .async-search/_search<br /> // 返回的结果<br /> ···<br /> "hits": [<br /> {<br /> "_index": ".async-search",<br /> "_type": "_doc",<br /> "_id": "bPNotcTCTV-gSIiZLuK0IA",<br /> "_score": 1,<br /> "_source": {<br /> "result": "i6+xAwFERm1KUVRtOTBZMVJEVkZZdFoxTkphVnBNZFVzd1NVRWJPRmx3UkdVMk9XWlRhMmt4TkVwb1QwUTJiVlpyWnpvek1EWTEAAQEDAD+AAAADP4AAAAAAABR0Sm9yNDVRQlQ3bzBsZTdsYmp0TgAAAARfZG9jAP//////////AwALeyJhIjoxMTExfQoAAAAAAAAAAQEAAAAWOFlwRGU2OWZTa2kxNEpoT0Q2bVZrZwp0ZXN0X2luZGV4Fk5fYmphNXM1UWtpcnU4RXdleVlGSUEAAAA/gAAAAAAAFHRab3I0NVFCVDdvMGxlN2xlVHNrAAAABF9kb2MA//////////8DAAt7ImEiOjExMTJ9CgAAAAAAAAABAQAAABY4WXBEZTY5ZlNraTE0SmhPRDZtVmtnCnRlc3RfaW5kZXgWTl9iamE1czVRa2lydThFd2V5WUZJQQAAAD+AAAAAAAAUdHBvcjQ1UUJUN28wbGU3bGZqc28AAAAEX2RvYwD//////////wMAC3siYSI6MTExM30KAAAAAAAAAAEBAAAAFjhZcERlNjlmU2tpMTRKaE9ENm1Wa2cKdGVzdF9pbmRleBZOX2JqYTVzNVFraXJ1OEV3ZXlZRklBAAAAAAAAAAAAAgABAQEAAAAAAAsAAAAAAAABlOMuvCQAAAGU/O6IJA==",<br /> "headers": {},<br /> "expiration_time": 1739410278436,<br /> "response_headers": {}<br /> }<br /> },<br /> ···<br />
只投票候选节点
这是一个主候选节点角色的优化,能相对固定 master 节点的位置,减少了选举候选节点过多的问题。
作用
Voting - only master - eligible node(仅参与投票的具备主节点资格的节点)在 Elasticsearch 集群中有以下作用:
- 参与主节点选举:该节点参与主节点选举过程,但本身不会成为集群选出的主节点,主要作为选举中的决胜因素(打破平局)。
- 保障高可用性:在高可用性(HA)集群中,至少需要三个具备主节点资格的节点,其中至少两个不能是仅参与投票的节点,这样即使有一个节点故障,集群仍能选出主节点。
- 分担选举及状态发布任务:和普通具备主节点资格的节点一样,在集群状态发布期间承担特定任务。
- 灵活承担其他角色:可以同时承担集群中的其他角色,如数据节点;也可以作为专用节点,不承担其他角色。
配置
三个节点的集群:可以配置两个普通主节点资格节点和一个仅参与投票的节点。这样在一个普通主节点故障时,剩下的普通主节点和仅参与投票的节点一起可以完成主节点选举,保证集群的正常运行。
理论上,主候选节点数量能满足不同区域间的主备切换要求即可,其余可以都是投票节点。
可搜索快照
注意:这是一个收费功能
实现机制
可搜索快照让你能够通过使用快照来保障数据恢复能力,而非在集群内维护副本分片,从而降低运营成本。
当你将快照中的索引挂载为可搜索快照时,Elasticsearch 会将索引分片复制到集群内的本地存储中。这能确保搜索性能与搜索其他任何索引相当,并尽量减少对访问快照存储库的需求。如果某个节点发生故障,可搜索快照索引的分片会自动从快照存储库中恢复。
搜索可搜索快照索引与搜索其他任何索引的方式相同。搜索性能与常规索引相当,因为在挂载可搜索快照时,分片数据会被复制到集群中的节点上。
如果某个节点发生故障,且需要从快照中恢复可搜索快照分片,在 Elasticsearch 将分片分配到其他节点的短暂时间内,集群健康状态将不会显示为绿色。在这些分片重新分配完成之前,对这些分片的搜索将会失败或返回部分结果。
对于搜索频率较低的数据,这能显著节省成本。使用可搜索快照,不再需要额外的索引分片副本以避免数据丢失,这有可能将搜索该数据所需的节点本地存储容量减少一半。同时可搜索快照依赖于备份使用的快照,也不需要额外的空间。
使用建议
- 从含多索引的快照挂载单个索引时,建议进行使用分隔,创建仅含目标索引的快照副本并挂载,方便独立管理备份与可搜索快照生命周期。
- 挂载为可搜索快照索引前,建议将索引强制合并为每分片一个段,减少从存储库读取数据的操作和成本。
实际测试
基础配置
前提条件:需要一个镜像使用存储,这里使用 minIO 作为测试
- 安装 S3 插件,并注册快照库信息
```
在线安装插件
elasticsearch-plugin install repository-s3
设置访问minio的信息,elasticsearch的bin目录下,使用minIO中设置的用户名密码
./elasticsearch-keystore add s3.client.default.access_key
./elasticsearch-keystore add s3.client.default.secret_key
重载安全设置,然后重启节点
POST _nodes/reload_secure_settings
注册快照库
PUT _snapshot/my-minio-repository
{
"type": "s3",
"settings": {
"bucket": "es-bucket",
"endpoint": "<a href="http://127.0.0.1:9002"" rel="nofollow" target="_blank">http://127.0.0.1:9002",
"compress": true
}
}
```
- 挂载需要的快照索引
<br /> POST /_snapshot/my-minio-repository/snapshot_es_prp_cmain_20240829/_mount?wait_for_completion=true<br /> {<br /> "index": "es_prp_cmain_insured_itemkind_detail_formal_20240829",<br /> "renamed_index": "test_searchable_snapshot",//挂载时对索引进行重命名<br /> "index_settings": {<br /> "index.number_of_replicas": 0<br /> },<br /> "ignore_index_settings": [ "index.refresh_interval" ]<br /> }<br />
- 检查空间占用
<br /> GET _cat/indices/test_searchable_snapshot?v<br /> health status index uuid pri rep docs.count docs.deleted store.size pri.store.size<br /> green open test_searchable_snapshot qROj2flcRdiGOZaejeAmQQ 1 0 10000 0 21.3mb 21.3mb<br />
在系统上也看到了对应 uuid 的文件目录
<br /> [root@hcss-ecs 0]# ls<br /> _state snapshot_cache translog<br /> [root@hcss-ecs 0]# pwd<br /> /data/elasticsearch-7.10.2/data/nodes/0/indices/qROj2flcRdiGOZaejeAmQQ/0<br />
小结
这篇的内容讲解测试的相对较细,对于查询的自动取消和异步查询增加了 ES 查询任务的灵活性;只投票节点也是加强了主节点选举的稳定性;可搜索快照是成本和功能的均衡方法,对于日志场景的使用是一个不错的选择。
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
- [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
- [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
- [谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他](https://infinilabs.cn/blog/202 ... part-6)
关于极限科技(INFINI Labs)

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。
极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。
官网:<https://infinilabs.cn>
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/202 ... rt-5/
INFINI Console 纳管 Elasticsearch 9(二):日志监控
INFINI Labs 小助手 发表了文章 • 0 个评论 • 431 次浏览 • 2 天前
前面介绍过 INFINI Console 纳管 Elasticsearch 9(一),进行指标监控、数据管理、DSL 语句执行,但日志监控功能需要结合 [Agent](https://docs.infinilabs.com/agent/main/zh/) 才能使用。现在来实现一下:
Agent 需要和 ES 部署到同一机器上,这里是在我本地电脑上进行安装。
安装 Elastisearch
bash<br /> curl -O <a href="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-9.0.0-darwin-x86_64.tar.gz" rel="nofollow" target="_blank">https://artifacts.elastic.co/d ... ar.gz</a><br /> curl <a href="https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-9.0.0-darwin-x86_64.tar.gz.sha512" rel="nofollow" target="_blank">https://artifacts.elastic.co/d ... ha512</a> | shasum -a 512 -c -<br /> tar -xzf elasticsearch-9.0.0-darwin-x86_64.tar.gz<br /> cd elasticsearch-9.0.0/<br /> ./bin/elasticsearch<br />

将 ES 注册到 Console 中。


安装 Agent
bash<br /> curl -O <a href="https://release.infinilabs.com/agent/stable/agent-1.29.2-2008-mac-amd64.zip" rel="nofollow" target="_blank">https://release.infinilabs.com ... 4.zip</a><br /> mkdir agent<br /> unzip agent-1.29.2-2008-mac-amd64.zip -d agent/<br /> cd agent<br />
修改配置文件 agent.yml,填写正确的 Console 地址。

启动 Agent,成功注册到 Console,获取到相关配置,但连接 Console 系统集群出现异常,这是因为 Console 系统集群是 Docker 部署的(172.17.0.2 是 Docker 内部 IP)。

通过 Console 修改 Agent 配置。


注:Console 系统集群地址需调整为 Agent 可以访问的地址;配置版本号需要增大。
Agent 运行无异常。

Agent 注册 Console 成功后,在 Console 页面“资源管理”-“探针管理”中可以看到注册的 Agent 实例。

关联操作
Agent 关联到需要采集数据的 ES 集群。




调整监控模式
关联成功后,将 ES 集群的监控模式改为 Agent。

可在监控报表中,查看采集状态。

查看日志

至此日志功能已可以使用。
关于 INFINI Console

INFINI Console 是一款开源的非常轻量级的多集群、跨版本的搜索基础设施统一管控平台。通过对流行的搜索引擎基础设施进行跨版本、多集群的集中纳管,企业可以快速方便的统一管理企业内部的不同版本的多套搜索集群。INFINI Console 还可以对集群内的索引及数据进行操作管理,可以配置灵活的告警规则,可以指定统一的安全策略,可以查看各个维度的日志和审计信息,真正实现企业级的搜索服务平台化建设和运营。
官网文档:<https://docs.infinilabs.com/console>
开源地址:<https://github.com/infinilabs/console>
原文:https://infinilabs.cn/blog/202 ... arch/
谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇
INFINI Labs 小助手 发表了文章 • 0 个评论 • 410 次浏览 • 2 天前
这一篇我们继续了解 ES 7.10 相较于 ES 6.8 新增的聚合方法。
Rare Terms 聚合
功能说明
用于聚合查询出字段中的稀有项。ES 常见的统计方法是使用 term 查询的正向排序,但是在大数据量和高基数的数据分布场景下会出现 unbounded 错误。Rare 聚合弥补了这个场景的查询方法。注意的是,这个聚合计算出来的是一个近似值。
注意事项
使用限制
- 只能用于 keyword、numeric、ip 或 boolean 类型字段
- max_doc_count 参数限制文档数量(默认为 1)
- precision_threshold 参数控制精度(默认为 3000)
性能考虑
- 在高基数(数据集中不同值的数量非常多)字段上性能较好
- 内存消耗相对较大
- 聚合是在 shard 层做的统计,建议使用合适的 shard 大小
精度控制
- 结果是近似值,具体说明[见此](https://www.elastic.co/guide/e ... cision)
- 可以通过 precision_threshold 调整精度,精度越高,内存消耗越大
Cumulative Cardinality 聚合
功能说明
一个管道聚合,计算 histogram(或 date_histogram)聚合中的累积基数。
Cumulative_cardinality 聚合对于查找几个时间段内的"新项目"很有用,比如每天网站的新访客数量。常规 Cardinaity 聚合会告诉你每天有多少独立访客,但不会区分"新"或"重复"访客。Cumulative_cardinality 聚合可以用来确定每天有多少独立访问者是"新"的。
可以通过 precision_threshold 参数调整精度,内存消耗随精度增加而增加。建议根据实际需求调整精度,避免不必要的高精度设置。
使用要求
- 需要一个 date_histogram 或 histogram 聚合
- 需要一个 cardinality 度量聚合
- buckets_path 必须指向一个有效的 cardinality 聚合
代码样例
<br /> GET /user_hits/_search<br /> {<br /> "size": 0,<br /> "aggs": {<br /> "users_per_day": {<br /> "date_histogram": {<br /> "field": "timestamp",<br /> "calendar_interval": "day"<br /> },<br /> "aggs": {<br /> "distinct_users": {<br /> "cardinality": {<br /> "field": "user_id"<br /> }<br /> },<br /> "total_new_users": {<br /> "cumulative_cardinality": {<br /> "buckets_path": "distinct_users"<br /> }<br /> }<br /> }<br /> }<br /> }<br /> }<br />
Geotile Grid 聚合
功能说明
基于 geo_point 字段的地理位置多桶聚合。将地理空间数据按照网格划分,便于可视化和分析。
注意要点
- 网格设置: precision 参数控制网格精度(0-29),精度越高,网格越小,桶数越多。
- 高精度会产生大量桶,内存消耗随精度增加而增加。
- 只支持 geo_point 类型字段。
代码样例
json<br /> POST /museums/_search?size=0<br /> {<br /> "aggregations": {<br /> "tiles-in-bounds": {<br /> "geotile_grid": {<br /> "field": "location",<br /> "precision": 22,<br /> "bounds": {<br /> "top_left": "52.4, 4.9",<br /> "bottom_right": "52.3, 5.0"<br /> }<br /> }<br /> }<br /> }<br /> }<br /> <br />
T-test 聚合
功能说明
T_test 是一种统计假设检验,用于判断测试统计量在零假设下是否服从学生 t 分布(Student’s t-distribution)。它适用于从聚合文档中提取的数值或通过提供的脚本生成的数值。
该聚合将会返回该检验的 p 值(概率值)。它是在零假设正确的情况下(这意味着总体均值之间没有差异),获得至少与聚合所处理结果一样极端结果的概率。p 值越小,意味着零假设越有可能不正确,总体均值实际上是存在差异的。
关于 Student’s t-distribution
Student's t - distribution(学生 t - 分布),简称 t - 分布,是一种概率分布。它在统计学中具有重要地位,特别是在样本量较小且总体标准差未知的情况下用于对总体均值进行估计和假设检验。
它的形状类似于正态分布,呈钟形曲线,但比正态分布的 “尾部” 更厚。也就是说,t - 分布在均值两侧的极端值出现的概率比正态分布更高。
测试代码
json<br /> GET node_upgrade/_search<br /> {<br /> "size": 0,<br /> "aggs": {<br /> "startup_time_ttest": {<br /> "t_test": {<br /> "a": { "field": "startup_time_before" },<br /> "b": { "field": "startup_time_after" },<br /> "type": "paired"<br /> }<br /> }<br /> }<br /> }<br /> <br />
Variable Width Histogram 可变直方图聚合
功能说明
类似于 histogram 的多桶聚合。但与 histogram 不同,每个桶的宽度不是预先指定的,而是根据目标桶数量动态确定间隔。
参数设置
- 网格设置: precision 参数控制网格精度(0-29),精度越高,网格越小,桶数越多。
- field 必须是数值类型
- buckets 参数指定目标桶数
- 实际桶数可能少于指定值
性能考虑
- 比固定宽度直方图更耗资源,大数据集上可能较慢
- 建议限制目标桶数量
使用场景
- 数据分布不均匀时特别有用
- 适合探索性数据分析
- 可以避免空桶或过密桶
Normalize 归一化聚合
功能说明
一个管道聚合,用于计算特定桶值的归一化或重新缩放后的值。
方法选择
可以归一化处理的方法有:
- rescale_0_1:0 到 1 重缩放,这种方法对数据进行重新缩放,使得最小值变为 0,最大值变为 1,其余数值则在两者之间进行线性归一化。
- rescale_0_100:0 到 100 重缩放,该方法对数据进行重新缩放,让最小值变为 0,最大值变为 100,其余数值在它们之间按线性方式进行归一化。
- percent_of_sum:占总和的百分比,此方法对每个值进行归一化,使其表示为占总值的百分比。
- mean:均值归一化,这种方法进行归一化时,每个值依据其与平均值的差异程度来进行归一化。
- zscore:Z 分数归一化,该方法进行归一化时,每个值表示的是其相对于标准差偏离均值的程度。
- softmax:软最大化归一化,这种方法进行归一化时,先对每个值取指数,然后相对于原始值指数之和来进行归一化。
参数配置
- method 参数指定归一化方法
- buckets_path 指定数据来源
- 可以设置缺失值处理
Moving Percentiles 聚合
功能介绍
一个管道聚合,对于一组有序的百分位数,移动百分位数聚合(Moving Percentile Aggregation)会在这些百分位数上滑动一个窗口,并计算累积百分位数。
关于 shift 偏移参数
默认情况下(偏移量 shift = 0 时),用于计算的窗口是除当前桶之外的最后 n 个值。将偏移量增加 1 会使起始窗口位置向右移动 1 个单位。
- 若要将当前桶包含在窗口内,请使用 shift = 1。
- 对于居中对齐(当前桶前后各有 n / 2 个值),使用 shift = window / 2。
- 对于右对齐(当前桶之后有 n 个值),使用 shift = window。
如果窗口的任一边缘移动到数据序列边界之外,窗口将会收缩,仅包含可用的值。
Rate 聚合
功能说明
在 date_histogram 的聚合上使用,用于计算每个 date_histogram 桶中的文档速率或字段速率。
rare 聚合支持多种时间单位(如秒、分、时),使用时需要明确指定单位。可以用来计算文档数或字段值,但必须与 date_histogram 一起使用。
小结
这一篇粗略的列举了 ES 7.10 版本中新增的聚合方法。相较于查询方法的高使用频率和低资源占用,聚合方法的使用频率相对较少,内存也会有一定的占用,大家可以根据实际场景选择使用。
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
- [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
- [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)
- [谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他](https://infinilabs.cn/blog/202 ... part-6)
关于极限科技(INFINI Labs)

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。
极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。
官网:<https://infinilabs.cn>
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/202 ... rt-4/
INFINI Console 纳管 Elasticsearch 9(一):指标监控、数据管理、DSL 语句执行
INFINI Labs 小助手 发表了文章 • 0 个评论 • 1042 次浏览 • 5 天前
Elasticsearch v9.0 版本最近已发布,而 [INFINI Console](https://docs.infinilabs.com/console) 作为一款开源的非常轻量级的多集群、跨版本的搜索基础设施统一管控平台,是否支持最新的 Elasticsearch v9.0 集群管理呢?本文以 INFINI Console v1.29.2 为例,从指标监控、数据管理、DSL 语句执行等方面进行测试。
部署注册
使用 Docker 快速部署 ES9。
bash<br /> docker run --name es9 -p 9201:9200 -it -m 1GB docker.elastic.co/elasticsearch/elasticsearch:9.0.0<br />
使用 Docker 部署 Console,请参考[文档](https://docs.infinilabs.com/co ... ocker/)。
bash<br /> docker run -d --name console -p 9001:9000 infinilabs/console:1.29.2-2008<br />
将 ES9 注册到 Console,默认采集模式为 Agentless。


请求模拟
使用 [Loadgen](https://release.infinilabs.com/loadgen/stable/) 模拟数据写入和查询。
```bash
env:
ES_USERNAME: elastic
ES_PASSWORD: CZ-FHm+M5cbfee_yMPZp
ES_ENDPOINT: https://192.168.0.101:9201
runner:
total_rounds: 1
no_warm: true
valid_status_codes_during_warmup: [ 200,201,404 ]
Whether to log all requests
log_requests: false
Whether to log all requests with the specified response status
log_status_codes:
- 0
- 500
assert_invalid: false
assert_error: false
Whether to reset the context, including variables, runtime KV pairs, etc.,
before this test run.
reset_context: false
default_endpoint: $[[env.ES_ENDPOINT]]
default_basic_auth:
username: $[[env.ES_USERNAME]]
password: $[[env.ES_PASSWORD]]
variables:- name: id
type: sequence - name: uuid
type: uuid - name: now_local
type: now_local - name: now_unix
type: now_unix - name: list
type: list
data:
- "medcl"
- "abc"
- "efg"
- "xyz"
requests:
- "medcl"
- request: #prepare some docs
method: POST
url: /_bulk
body_repeat_times: 5000
body: |
{"index": {"_index": "infinilabs", "_id": "$[[uuid]]"}}
{"id": "$[[id]]", "field1": "$[[list]]", "now_local": "$[[now_local]]", "now_unix": "$[[now_unix]]"}
- request:
method: GET
url: infinilabs/_search
body: |
{"query":{"term":{"id":"$[[id]]"}}}
<br /> <br />
bash
./loadgen-mac-amd64 -d 300
```
平台管理
平台概览


监控报表
- 指标概览

- 集群指标

- 节点指标

- 索引指标

- 节点线程指标

- 节点热力图

- 索引热力图

- 查看日志

日志采集需要安装 Agent,关于这块功能后续会进行介绍。
- 节点实时指标

- 索引实时指标

数据管理

开发工具

总结
经过测试,INFINI Console 可以支持 Elasticsearch 9 集群纳管,大家可以下载体验使用。
关于 INFINI Console

INFINI Console 是一款开源的非常轻量级的多集群、跨版本的搜索基础设施统一管控平台。通过对流行的搜索引擎基础设施进行跨版本、多集群的集中纳管,企业可以快速方便的统一管理企业内部的不同版本的多套搜索集群。INFINI Console 还可以对集群内的索引及数据进行操作管理,可以配置灵活的告警规则,可以指定统一的安全策略,可以查看各个维度的日志和审计信息,真正实现企业级的搜索服务平台化建设和运营。
官网文档:<https://docs.infinilabs.com/console>
开源地址:<https://github.com/infinilabs/console>
原文:https://infinilabs.cn/blog/202 ... arch/
- name: id
谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇
INFINI Labs 小助手 发表了文章 • 0 个评论 • 2911 次浏览 • 2025-04-28 12:17
上一篇咱们了解了 ES 7.10 相较于 ES 6.8 新增的字段类型,这一篇我们继续了解新增的查询方法。
Interval 间隔查询:
功能介绍
Interval 查询,词项间距查询,可以根据匹配词项的顺序、间距和接近度对文档进行排名。主要解决的查询场景“创建一个多搜索词匹配的查询,同时保留搜索词的顺序”,比 match phrase 更加符合需求场景,查询方法使用比 span 查询更简单。ES 后续版本想用 interval 查询逐步替代 span 查询。
注意事项
规则组合
- 可以使用 prefix、wildcard、fuzzy 等规则
- 通过设置 max_gaps 和 ordered 参数,可以控制词项间的最大间隙和顺序要求。
性能考虑
- 间隔查询比简单的词项匹配更消耗资源
- 嵌套规则越多,性能开销越大
- 建议合理使用 maxGaps 参数限制间距
使用限制
- 只能用于 text 字段
- 不支持跨字段查询
- 不支持对数值类型字段使用
Distance feature 查询
功能说明
时间/地理距离特性查询,该查询用于查找更接近被查询日期和地理位置的结果。 日期和位置分别是声明为 date 和 geo_point 数据类型的字段。返回结果的字段值不需要完全等于被查询值,而是按照给定日期或给定位置的进度算分,越是接近被查询值,在相关性得分中被评为更高。
字段类型要求
- 日期字段必须是 date 类型,地理位置字段必须是 geo_point 类型
- 不支持其他类型的距离计算
评分机制
- 距离越近,得分越高
- 使用 boost 参数调整权重
- 可以与其他查询组合使用
性能考虑
- 地理距离计算较为耗费资源,建议使用合适的索引优化地理查询,比如:考虑使用地理网格索引提升性能
Pinned 查询
功能说明
实现对某些文档的置顶功能,使用存储在_id 字段中的文档 ID 来标识升级或“固定”的文档。
此功能通常用于引导搜索者查找精选的文档,这些文档在搜索的任何 “organic” 匹配项之上被提升。当查询中有排序时,pinned 查询失效。
使用限制
- 不能与自定义排序一起使用
- 置顶文档必须存在于索引中
- 最多支持 100 个置顶文档
排序规则
- 置顶文档按照 ids 数组中的顺序排序
- organic 查询结果按照相关性得分排序
- 置顶文档始终在 organic 结果之前
PIT 查询
功能说明
Point in time 查询是一个轻量级的视图,根据保留周期保留 PIT 查询发生时数据的状态,用于不同条件的深度分页查询。
scroll 滚动搜索及其上下文与查询内容绑定。这意味着编写一个查询,添加一个滚动参数,来自这个查询的响应数据就会保持一致。不同的查询内容则会产生不同的 scroll 上下文,资源使用就会相对紧张。有时想对同一固定数据集适时运行不同的查询,就需要 PIT 查询。
如果对于一个不断变化的索引有着很高的搜索负载,那么为每个请求创建一个新的时间点查询会使用相当多的资源。可以通过使用一个后台进程每隔几分钟创建一个时间点 id 并将其用于所有搜索请求的方式来优化资源使用
更多内容可以[参照这里](https://blog.csdn.net/UbuntuTo ... 925187)
注意事项
资源管理
- PIT 会占用系统资源,需要及时释放
- 建议设置合理的保留时间
- 监控 open context 数量
使用场景
- 适合需要一致性视图的场景
- 适合需要深度分页的场景
- 适合需要在固定数据集上执行多次查询的场景
性能优化
- 避免过长的保留时间,合理设置批次大小
- 建议查询的时候带 sort 参数排序
测试代码
<br /> // 1. 使用 product_test 索引,创建 PIT<br /> POST /product_test/_pit?keep_alive=1m<br />

<br /> GET /_search<br /> {<br /> "size": 1,<br /> "query": {<br /> "match": {<br /> "model": "iphone"<br /> }<br /> },<br /> "pit": {<br /> "id": "i6-xAwEMcHJvZHVjdF90ZXN0FmRObXltV3ZDU1VTTnllYjNoR0ZtamcAFk1GQklTWXBaUkllb2h1cGl1VVFsdUEAAAAAAAABZk8WOFVoUHBhN3BSVVN5TWVmeTh4d3JpdwEWZE5teW1XdkNTVVNOeWViM2hHRm1qZwAA",<br /> "keep_alive": "1m"<br /> },<br /> "sort": [<br /> {"_score": "desc"},<br /> {"_id": "asc"}<br /> ]<br /> }<br /> <br />

<br /> DELETE /_pit<br /> {"id":"i6-xAwEMcHJvZHVjdF90ZXN0FmRObXltV3ZDU1VTTnllYjNoR0ZtamcAFk1GQklTWXBaUkllb2h1cGl1VVFsdUEAAAAAAAABZk8WOFVoUHBhN3BSVVN5TWVmeTh4d3JpdwEWZE5teW1XdkNTVVNOeWViM2hHRm1qZwAA"}<br />

小结
作为查询方法,Elasticsearch 新增的几个功能面对的场景更加具象且方便,大家可以根据业务的场景特性可以优化使用。其中深度分页查询是 ES 使用者几乎避免不了的场景,PIT 查询也是提供了一个更为优质的方法。
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
- [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
- [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)
- [谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他](https://infinilabs.cn/blog/202 ... part-6)
关于极限科技(INFINI Labs)

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。
极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。
官网:<https://infinilabs.cn>
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/202 ... rt-3/
谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇
INFINI Labs 小助手 发表了文章 • 0 个评论 • 3116 次浏览 • 2025-04-25 19:41
我们继续来了解一下从 ES 6.8 到 ES 7.10 新增的功能。本篇主要介绍新增的字段类型,会简要概述一下新增字段类型的使用场景和限制,提供简单的测试代码。
Flattened 扁平化对象字段
功能说明
解决场景
该功能主要用于处理具有大量不确定键的 JSON 对象,避免字段映射爆炸问题,特别适用于不需要对对象内部字段进行单独分析和聚合的场景,以及当对象结构不固定,字段名称动态变化时。
使用注意点
- 整个对象被视为单个字段,无法对内部单个字段进行分析或聚合
- 只支持 keyword 类型的操作,如 term、prefix 查询等。因为它的每个解析出的字段都值为 keyword 字段
- 默认最大字段深度为 20,可以通过 depth_limit 来设置。
- 不支持数字范围查询,高亮显示
- 查询时,无法使用通配符引用字段键,比如 { "term": {"labels.time*": 1541457010}}
- split_queries_on_whitespace 为 true 时,这个字段的全文查询(match,query_string,simple_query_string)等于是用了空格分词器。
支持的查询方法
- term 查询:精确匹配某个字段的值
- terms/terms_set 查询:匹配多个值中的任意一个或者多个
- prefix 查询:前缀匹配
- exists 查询:检查字段是否存在
- match 查询:分词后的全文检索(但因为是 keyword,所以实际上是精确匹配)
- query_string 和 simple_query_string
Shape 字段
功能说明
该功能主要用于存储和查询任意几何图形数据,支持点、线、圆、矩形、多边形等几何形状,特别适用于地理空间分析和基于形状的搜索场景,以及相比于 geo_shape 专门用于地理空间数据(坐标系统固定为 WGS84 经纬度),shape 字段可以用于任意坐标系统的几何形状,比如虚拟世界或者保密空间。
使用要点
- 形状数据使用 [GeoJSON](https://geojson.org/) 或[Well-Known Text (WKT)](https://docs.ogc.org/is/12-063r5/12-063r5.html)格式表示
- 支持的空间关系操作包括:INTERSECTS(相交)、DISJOINT(不相交)、WITHIN(内部)和 CONTAINS(包含)
- 由于 shape 字段的复杂输入结构和索引表示,目前无法对 shape 字段进行排序,也无法直接检索其字段值(只能通过 _source 字段获取)
- orientation 参数用于定义多边形顶点读取的顺序:默认逆时针(counterclockwise),可选顺时针(clockwise)
Wildcard 字段
功能说明
解决的场景
用于优化通配符和正则表达式查询性能。特别适用于需要进行暴力模糊匹配的文本字段。
wildcard 字段在 keyword 字段和 ngrams 分词器之间找到了性能和存储成本的均衡。
原理说明
wildcard 字段采用了一种独特的索引策略,使用这种数据类型自动加速通配符和正则表达式搜索:
- n-gram 索引:存储字符串中所有 3 个字符的序列。可以理解为 ngram 分词器取长度为 3 的子串.
- 二进制 doc value:存储完整的原始文档值
这种方式与传统的 keyword 字段(完全不分词)和 text 字段(基于分词器分词)有很大不同。在查询时,系统首先使用这些 ngrams 构建的索引进行初步筛选,快速定位可能匹配的文档。这个过程类似于数据库中的索引过滤,可以大大减少需要详细检查的文档数量。然后,系统会从二进制 doc value 中取出这些候选文档的完整字段值,进行精确的模式匹配,确保最终结果的准确性。
这种策略在性能和存储空间上取得了很好的平衡:
- n-gram 索引:存储字符串中所有 3 个字符的序列。可以理解为 ngram 分词器取长度为 3 的子串.
- 相比 keyword 字段,在精确匹配查询时性能稍差
- 相比 ngrams 分词,它避免了过度的 token 生成,既节省存储空间,又保持了不错的查询性能
- 特别适合对日志数据进行类似 grep 的模式匹配查询,如通配符查询和正则表达式查询
使用注意点
- 比 keyword 类型更适合做通配符搜索,但会占用更多磁盘空间
- 建议仅在确实需要频繁进行通配符查询的字段上使用
- 与 keyword 字段一样是非分词(untokenized)的,所以不支持依赖词项位置的查询(如短语查询)
更多原理说明可以[参照这里](https://blog.csdn.net/UbuntuTo ... 120879)
Version 字段类型
功能说明
该功能主要用于存储和比较软件版本号,提供版本号的自然排序和比较功能,支持标准的版本号格式(如 1.0.0, 2.1.3-alpha 等)。
使用说明
- 版本号必须符合标准格式:主版本号、次版本号、修订号
- 支持带有预发布标识符的版本号(如 alpha, beta, rc 等)
- 可以进行版本号的大小比较和范围查询,比如可以在 1.0.0 和 2.0.0 之间查找所有版本
- 底层存储的是 keyword 类型,虽然可以正则匹配或者模糊查询,但是在大数据量下注意性能问题。
Histogram 直方图字段
功能说明
解决的场景
Histogram 字段专门用于存储预先计算好的直方图数据,这种数据结构在需要频繁进行统计分析的场景下特别有用。通过预先聚合数据并以直方图形式存储,可以显著减少查询时的实时计算开销,提高查询性能。对大规模数据集的统计分析很有利,比如系统监控指标、用户行为分析等需要快速获取数据分布情况的场景。
直方图的数据格式
直方图字段需要包含两个必需的参数来表示直方图数据:
values
:数值数组,表示每个聚合分桶的取值点,即区间的起点。数组中的值必须是严格递增双精度浮点数counts
:整数数组,表示落在当前区间内的元素数量。数组中的值必须是非负整数。具体来说,对于位置 i,counts[i] 表示数值大于等于 values[i] 且小于 values[i+1] 的元素个数(最后一个区间则包含等于 values[last] 的元素)
这两个数组必须具有相同的长度。
例如,一个表示年龄分布的直方图数据可能如下:
json<br /> {<br /> "age_histogram": {<br /> "values": [20.0, 30.0, 40.0, 50.0], // 年龄区间的起点:[20-30)、[30-40)、[40-50)、[50 及以上]<br /> "counts": [100, 150, 75, 25] // 表示:20-29 岁有 100 人,30-39 岁有 150 人,40-49 岁有 75 人,50 岁及以上有 25 人<br /> }<br /> }<br />
存储说明
直方图字段主要用于聚合分析。为了优化聚合操作的性能,数据以二进制 doc values 形式存储,而不是创建索引。每个直方图字段的存储大小最多为 13 * numValues 字节,其中 numValues 是数组的长度。
使用注意点
- value 数组必须按升序排列
- count 数组的长度必须与 value 数组相同
- 由于数据被索引,直方图字段仅支持以下操作:
- 聚合操作:min(最小值)、max(最大值)、sum(求和)、value_count(计数)、avg(平均值)、percentiles(百分位数)、percentile_ranks(百分位等级)、boxplot(箱线图)、histogram(直方图)
- 查询操作:仅支持 exists(存在性)查询
Search-as-you-type 字段
功能说明
解决的场景
该功能主要用于实现自动补全的即时搜索体验,比如可以在当用户输入搜索关键词的时候,还没输完就可以提示用户数据库里最相关的内容。
它是通过支持前缀匹配和部分词语匹配的方式,使用户在输入过程中就能获得搜索结果。
字段结构说明
search_as_you_type 字段会自动创建以下子字段:
- 聚合操作:min(最小值)、max(最大值)、sum(求和)、value_count(计数)、avg(平均值)、percentiles(百分位数)、percentile_ranks(百分位等级)、boxplot(箱线图)、histogram(直方图)
{field_name}
: 基础字段,用于完整词语匹配,使用字段设置的分词器。{field_name}._2gram
: 用大小为 2 的 shingle token filter 分词器对 ny_field 进行分词{field_name}._3gram
: 用大小为 3 的 shingle token filter 分词器对 ny_field 进行分词{field_name}._index_prefix
: 用 edge ngram token filter 包装 my_field._3gram 的分词器
使用注意
- 可以通过设置 max_shingle_size 参数(默认为 3)来控制生成的子字段数量。max_shingle_size 参数越大,子字段越多,默认 3 个字段能覆盖大部分的场景。
- search-as-you-type 字段索引空间占用较大,因为需要存储多个分词器的结果。
前缀查询(prefix)优化机制
search_as_you_type 字段在处理前缀查询时有特殊的优化。当对根字段或其子字段进行前缀查询时,查询会被重写为针对 ._index_prefix 子字段的 term 查询,这比传统的文本字段前缀查询更高效
._index_prefix 子字段的分析器会对分词结果进行特殊处理:
- 不仅索引常规的 n-gram 分词结果
- 还会索引字段值词条的前缀,即使这些词条不会出现在 n-gram 子字段中
例如,对于文本 "quick brown fox",在 max_shingle_size 为 3 的情况下:不仅会索引会索引"quick" "brown" "fox",还会索引这些此项的前缀,这确保了字段中所有词条都能支持自动完成功能,即使这些词条组合并不存在于 ._3gram 子字段中
小结
这里我们只是简要的介绍了一下新增字段类型的设计背景和原理,并没有深入展开挖掘新增字段的性能场景或者奇思妙用,比如 wildcard 与 ngram 颗粒度性能对比,直方图数据和 pipeline 进行日志分析的组合等等。大家可以根据实际的需求场景进行深度挖掘。
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇](https://infinilabs.cn/blog/202 ... part-1)
- [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
- [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
- [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)
- [谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他](https://infinilabs.cn/blog/202 ... part-6)
关于极限科技(INFINI Labs)

极限科技,全称极限数据(北京)科技有限公司,是一家专注于实时搜索与数据分析的软件公司。旗下品牌极限实验室(INFINI Labs)致力于打造极致易用的数据探索与分析体验。
极限科技是一支年轻的团队,采用天然分布式的方式来进行远程协作,员工分布在全球各地,希望通过努力成为中国乃至全球企业大数据实时搜索分析产品的首选,为中国技术品牌输出添砖加瓦。
官网:<https://infinilabs.cn>
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
谈谈 ES 6.8 到 7.10 的功能变迁(1)- 性能优化篇
INFINI Labs 小助手 发表了文章 • 0 个评论 • 2719 次浏览 • 2025-04-15 11:21
前言
ES 7.10 可能是现在比较常见的 ES 版本。但是对于一些相迭代比较慢的早期业务系统来说,ES 6.8 是一个名副其实的“钉子户”。
借着工作内升级调研的任务东风,我整理从 ES 6.8 到 ES 7.10 ELastic 重点列出的新增功能和优化内容。将分为 6 个篇幅给大家详细阐述。
本系列文章主要针对 Elasticsearch 传统的使用功能和基础的模块,像是集群任务的管理、搜索、聚合还有字段类型这样的功能。对于付费功能或者全新的模块,比如:CCR、机器学习和数据流,这里不去深入探讨。
内容的主要来源于 Elastic [各个版本的发布信息](https://www.elastic.co/cn/blog/category/releases),这里主要比对 ES 6.8 版本到 7.10 版本的差异,并不一一枚举各个新的功能点出现的时间版本。
下面是第一篇:关于 ES 性能的优化
ES 7.10 的性能优化
集群协调算法升级
基于 Elastic 博客提供的资料,Elasticsearch 7.0 的核心改进在于集群协调层的彻底重构,取代了旧版 Zen Discovery 的局限性,引入更健壮、自动化的分布式共识机制。从理论上来说这次优化有着不少的进步,可以显著提升了高可用性与运维效率
主要的优化点有下面三点:
- 消除分裂脑(Split Brain)风险:通过自动化计算,确保集群状态更新的安全性。旧版
minimum_master_nodes
的手动配置被移除,避免人为误操作。
- 提升集群稳定性与恢复速度:节点故障时,集群更快达成一致,减少服务中断窗口。
- 简化运维复杂度:可以动态扩缩容无需手动调整配置,系统自动管理选举配置。同时提供更清晰的日志和错误提示,加速故障诊断。
| 旧版配置 | ES 7.0 配置 | 作用 |
| ------------------------------------ | ---------------------- | ----------------------------------------- |
|discovery.zen.ping.unicast.hosts
|discovery.seed_hosts
| 定义初始发现的种子节点列表(IP 或主机名) |
|discovery.zen.minimum_master_nodes
| 已移除 | 由系统自动管理法定人数 |
而在优化的原则里,Elastic 更强调安全第一。比如,在半数以上主节点永久丢失的风险场景下,ES 7.0 之前的集群会静默等待恢复,允许通过启动新空节点强制恢复,这样可能会导致数据不一致或丢失。在 Elasticsearch 7.0 以及更高版本中,这种不安全活动受到了更多限制。集群宁愿保持不可用状态,也不会冒这种风险(除非使用 elasticsearch-node 恢复工具)。
这次优化显著降低了人为错误的风险:移除脆弱的手动配置,减少运维使用的理解成本。同时提升关键业务连续性:快速故障恢复与明确的容错机制,能适合更多场景需求。
当然也并不是尽善尽美的,也会存在大集群下投票节点过多导致竞争激烈而[无法选主的问题](https://mp.weixin.qq.com/s/jU8HCEf2E6hkz_1ZVH_GaQ),这种情况下,建议部署独立的主节点,并且可以考虑适当增大 cluster.election.duration 的配置。
Top K 对检索的加速
这里的 Top K 主要是指在普通检索时展示前列的数据 Top K。也就是说 Elasticsearch 7.0 对检索数据的查询性能做了明显的改善。那是做了所有查询场景的提升么?
ELastic 做了这么一个场景假设:如果用户通常只关注搜索结果的第一页,且并不关心具体匹配的文档总数,对于超出一定数量的数据搜索引擎可以展示“超过 10,000 条结果”并提供分页浏览来优化搜索效率。但是在实际过程中用户常在查询中使用高频词(如“the”或“a”),这迫使 Elasticsearch 为大量文档计算评分,明显占用了查询资源的使用,即使这些常见词对相关性排序贡献甚微。

而现在,Elasticsearch 现在可以跳过那些在早期阶段就被判定为不会进入结果集顶部的低排名记录的评分计算,从而显著提升查询速度。这里主要涉及了 block-max WAND 算法的实现。这是一个复杂且漫长的优化过程,有兴趣的同学可以阅读一下这段[Magic WAND: Faster Retrieval of Top Hits in Elasticsearch](https://www.elastic.co/blog/fa ... x-wand)。

从 Elastic 的测试结果来看,新算法的优化让 term 查询加速了 3-7 倍。当然从场景背景可以看出,这个优化主要在大数据量下有明显效果(小数据量也不会有太多的日常高频词)。
默认开启 soft-delete 减少 translog
从 Elasticsearch 7.4 开始,副本的数据恢复,不再完全依赖 translog 了,而是通过索引的 soft-delete 特性(Elasticsearch 7.0 起所有新索引默认启用软删除 soft-deletes)。这样就可以缩小 translog 的使用场景,从而 translog 的保留大小也可以减少了。
那原来使用 translog 是什么样的呢?
translog 是 ES 用于保证数据安全性的重要工具。同时副分片进行恢复时,它也起着重要作用,只要副分片待获取的差异数据是在 translog 所保留的数据范围内,就可以只从 trasnlog 复制差异的部分数据,而不用拖取整个分片。在之前的版本中,Elasticsearch 默认会保留 512M 或 12 小时的 translog 用于副本恢复。
那现在使用的 soft-delete 是什么呢?
soft-deletes 是 Lucene 中实现的特性。这个软删除有时候会和 lucene 本身的标记删除概念发生混淆。为了方便理解,我们在这里归纳一下,lucene 实现删除的方式是一种标记删除的方式,而这种标记删除可以分为硬删除和软删除。软删除和硬删除有一个明显的区分点是:硬删除,被删除的文档对应的文档号用索引文件 .liv 来描述。软删除 soft-delete,被标记为删除的文档不使用索引文件.liv 来描述,而是通过索引文件 .dvd .dvm 来描述。
这里再扩展一下,.liv 文件主要实现 fixedbitset 数据结构。而 .dvd .dvm 则组合实现了 docvalue 这种正排数据结构。
正排索引的数据结构助力了 translog 的‘减负’,副本可以相对简便的通过软删除中的数据标记来实现数据恢复的处理。

相比较简洁高效的位图索引,docvalue 虽然实现了更多的功能,满足更多的场景,也会带来更多的问题。最明显的就是对于 update 操作,会导致 refresh 变得慢,有些压力场景下 refresh 会达到 10s 以上。
数值/日期排序查询加速
Elasticsearch 7.6 版本提升了按日期或数值(即任何存储为有符号 64 位整数(long 类型)的字段)进行排序的查询性能。
这背后的优化原理和之前 top K 使用的 Block-Max WAND 算法有点相似,都是利用算法跳过非竞争性文档来实现加速。
实际效果可能因环境而异,受多种参数影响。在 Elastic 进行的测试场景下,可以达到 35 倍的速度优化。
FST 内存使用迁移到堆外
Elastic 7.3 版本实现了这个优化,是藏在 release note 里的彩蛋。
Also mmap terms index (.tip) files for hybridfs #43150 (issue: #42838)
看似不经意的一行,但是带来效果却不小。FST 从堆内转移到堆外后,JVM 的空间可以空余出很客观的一部分。

一直以来,ES 堆中常驻内存中占据比重最大是 FST,即 tip(terms index) 文件占据的空间,1TB 索引大约占用 2GB 或者更多的内存,因此为了节点稳定运行,业界通常认为一个节点 open 的索引不超过 5TB。现在,从 ES 7.3 版本开始,将 tip 文件修改为通过 mmap 的方式加载,这使 FST 占据的内存从堆内转移到了堆外由操作系统的 pagecache 管理。
存储字段压缩优化
Elasticsearch 7.10 基于 Apache Lucene 8.7 引入了对存储字段(stored fields)的更高压缩率优化。不管是对于基于 DEFLATE 的index.codec: best_compression
还是基于 LZ4 的index.codec: default
都有不错的表现,在 Elastic 的测试场景下,最大可达到 10%的存储空间减少。
对于数据压缩 lucene 这次主要做了两个优化。
- Elastic 研究发现在存储数据的时候,底层的 block 越大,压缩效果越好,因为中间被压缩的重复数据可能越多。但是大块的 block 也可能因为解码重复数据降低查询速度。
- block 间通过共享字典来维持检索效率和数据压缩之间的平衡。
2.1. 首先为压缩算法提供一个数据字典,它也可以用于字符串重复数据删除。如果在要压缩的数据流和字典之间有许多重复的字符串,那么最终可以得到更好的压缩比。在解压缩时也通过字典来快速补足。

2.2. 同时,ES 使用更大的数据块,这些数据块本身被分成一个字典和 10 个子块,这些子块使用这个字典进行压缩。

而对于实际业务场景中,日志和监控数据的重复率往往会很好,因此在这两个场景中的压缩效果也是最明显的。
小结
当然,除了这几项外,ES 在各个版本中也做了不少优化,比如:调整 search.max_buckets 增加到 65534;Date histogram 聚合性能优化等等。有兴趣的同学可以参照各个版本的 [release highlight](https://www.elastic.co/guide/e ... s.html)
参考资料:
- [Save space and money with improved storage efficiency in Elasticsearch 7.10](https://www.elastic.co/blog/sa ... h-7-10)
- [Elasticsearch 7.3 的 offheap 原理](https://mp.weixin.qq.com/s/QviC_9ElknSS9kxXSMjjbg)
- [Elasticsearch 7.4 的 soft-deletes 是个什么鬼](https://mp.weixin.qq.com/s/_l8JAtqK_NOSP8b7OqSVDg)
推荐阅读
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
- [谈谈 ES 6.8 到 7.10 的功能变迁(3)- 查询方法篇](https://infinilabs.cn/blog/202 ... part-3)
- [谈谈 ES 6.8 到 7.10 的功能变迁(4)- 聚合功能篇](https://infinilabs.cn/blog/202 ... part-4)
- [谈谈 ES 6.8 到 7.10 的功能变迁(5)- 任务和集群管理](https://infinilabs.cn/blog/202 ... part-5)
- [谈谈 ES 6.8 到 7.10 的功能变迁(6)- 其他](https://infinilabs.cn/blog/202 ... part-6)
作者:金多安,极限科技(INFINI Labs)搜索运维专家,Elastic 认证专家,搜索客社区日报责任编辑。一直从事与搜索运维相关的工作,日常会去挖掘 ES / Lucene 方向的搜索技术原理,保持搜索相关技术发展的关注。
原文:https://infinilabs.cn/blog/202 ... rt-1/
- [谈谈 ES 6.8 到 7.10 的功能变迁(2)- 字段类型篇](https://infinilabs.cn/blog/202 ... part-2)
代理 Elasticsearch 服务:INFINI Gateway VS Nginx
INFINI Labs 小助手 发表了文章 • 0 个评论 • 2805 次浏览 • 2025-04-11 15:38

INFINI Gateway 简介
[INFINI Gateway](https://infinilabs.cn/products/gateway/) 是一款面向 Elasticsearch 的高性能应用网关,专为提升 Elasticsearch 集群的性能、安全性和可管理性而设计。它作为 Elasticsearch 的前置网关,能够处理所有客户端请求,并将其转发到后端的 Elasticsearch 集群,同时提供丰富的功能来优化请求处理和管理。此外还支持代理 Opensearch、[Easysearch](https://infinilabs.cn/products/easysearch/) 服务。
Nginx 简介
Nginx 是一个高性能的 HTTP 和反向代理服务器,以其高并发处理能力、低内存消耗和稳定性著称,广泛应用于 Web 服务器、负载均衡和反向代理等场景。在 Elasticsearch 的使用场景里,也有小伙伴使用 Nginx 来代理 Elasticsearch 的服务,利用 Nginx 的负载均衡能力,将请求转发到多个 Elasticsearch 节点。
这两个软件都能代理 Elasticsearch 服务,但是他们有什么区别?我们来一起分析分析。
负载均衡
Elasticsearch 是分布式系统,提倡使用 round-robin 方式将请求发送到多个节点。不管是 Nginx 还是 INFINI Gateway 都默认使用 round-boin 方式转发请求,也都支持 weighted round-robin(加权轮询)方式进行请求转发,这点两者相当。
节点自动更新
Elasticsearch 集群可能会遇到添加、删除节点的情况,代理程序能否感知 Elasticsearch 节点的变化将变得非常关键。
在 Nginx 中,所有转发节点的 IP 地址都必须写入到配置文件中。如果 Elasticsearch 集群加入了新的节点进行请求处理,则需要 Nginx 编辑配置文件把新节点的 IP 地址加入其中,然后重启或重载 Nginx 服务,才能将请求分发到新的节点。反之如果有节点下线,也要编辑 Nginx 配置文件并重载服务。
INFINI Gateway 是面向 Elasticsearch 设计的应用网关,具有后端节点发现和更新的功能,能够感知 Elasticsearch 集群节点加入、离开的情况。开启节点发现和更新功能后,Gateway 会定期自动更新节点列表,将请求均匀转发到列表中的节点。可参考之前的[博客](https://infinilabs.cn/blog/202 ... teway/)开启节点自动更新。
⚠️ 注意:INFINI Gateway 默认后端节点发现和更新的功能为关闭状态。
定向转发请求
使用 Elasticsearch 集群的场景多种多样,如果想对转发的节点做进一步控制,可能需要根据不同条件进行节点筛选:
- IP 地址
- 节点角色
- 节点标签
Nginx
Nginx 支持根据 IP 地址进行转发的,将需要转发的节点 IP 地址写入配置文件即可。
plain<br /> upstream es-cluster {<br /> server 192.168.56.102:9200;<br /> server 192.168.56.102:9201;<br /> server 192.168.56.102:9202;<br /> }<br />
但不支持按节点角色、节点标签进行筛选,因为 Nginx 中并没有这种概念。
INFINI Gateway
INFINI Gateway 支持按 IP 地址进行筛选:
- 不开节点发现:只转发到配置文件指定的节点(IP 地址)
- 开启节点发现:转发到所有发现的节点
```plain
flow:
- name: cache_first
filter:
- elasticsearch:
elasticsearch: prod
refresh:
enabled: true
interval: 30s
filter:
hosts:
exclude:
- 192.168.3.201:9200
include: - 192.168.3.202:9200
- 192.168.3.203:9200
<br /> <br /> 此外 Gateway 还支持通过节点角色、节点标签筛选转发节点。<br /> <br />
plain
flow:
- 192.168.3.201:9200
- elasticsearch:
- name: cache_first
filter:
- elasticsearch:
elasticsearch: prod
refresh:
enabled: true
interval: 30s
filter:
tags:
exclude:
- temp: cold
include: - disk: ssd
roles:
exclude: - master
include: - data
- ingest
```
多种筛选条件可以同时使用,详细信息请查看官方[文档](https://docs.infinilabs.com/ga ... earch/)。
作者:杨帆,极限科技(INFINI Labs)高级解决方案架构师、《老杨玩搜索》栏目 B 站 UP 主,拥有十余年金融行业服务工作经验,熟悉 Linux、数据库、网络等领域。目前主要从事 Easysearch、Elasticsearch 等搜索引擎的技术支持工作,服务国内私有化部署的客户。
原文:https://infinilabs.cn/blog/202 ... ginx/
- temp: cold
- elasticsearch:
- name: cache_first
是否可以为es的slowlog传入多个id值
kin122 回复了问题 • 2 人关注 • 1 个回复 • 2200 次浏览 • 2025-03-12 08:57
有什么 es 开源工具可以推荐使用
INFINI Labs 小助手 回复了问题 • 2 人关注 • 1 个回复 • 4219 次浏览 • 2025-01-15 14:48
是否可以在forcemerge时指定只清理一个段里的deleted文档,不合并2个段
Fred2000 回复了问题 • 2 人关注 • 1 个回复 • 2980 次浏览 • 2025-01-14 10:14
Elasticseach Ingest 模块&&漏洞分析
Radiancebobo 发表了文章 • 0 个评论 • 2932 次浏览 • 2024-12-23 12:58
本文基于Elasticsearch7.10.2分析
0.Ingest 节点 概述
在实际进行文档index之前,使用采集节点(默认情况下,每个es节点都是ingest)对文档进行预处理。采集节点会拦截bulk和index请求,进行转换,然后将文档传回index或bulk API。
每个索引都有index.default_pipeline 和 index.final_pipeline 两个配置。
他们都是用于指定 Elasticsearch index 或者bulk 文档时要执行的预处理逻辑。
- index.default_pipeline 定义了默认管道,它会在索引文档时首先执行。但如果索引请求中指定了 pipeline 参数,则该参数指定的管道会覆盖默认管道。如果设置了 index.default_pipeline 但对应的管道不存在,索引请求会失败。特殊值 _none 表示不运行任何摄取管道。
- index.final_pipeline 定义了最终管道,它总是在请求管道(如果指定)和默认管道(如果存在)之后执行。如果设置了 index.final_pipeline 但对应的管道不存在,索引请求会失败。特殊值 _none 表示不运行最终管道。
简而言之,default_pipeline 先执行,可被覆盖;final_pipeline 后执行,不可被覆盖。两者都可设为 _none 以禁用。
一个Pipeline可以有多个Processor组成,每个Processor有着各自的不同功能,官方支持的Processor可参考:https://www.elastic.co/guide/e ... .html
一个简单的例子,利用Set Processor 对新增的文档中加入新的字段和值:
java<br /> PUT _ingest/pipeline/set_os<br /> {<br /> "description": "sets the value of host.os.name from the field os",<br /> "processors": [<br /> {<br /> "set": {<br /> "field": "host.os.name", // 增加的属性<br /> "value": "{{os}}" // 这里引用了文档原先的os属性, 这里可以直接填写其他值<br /> }<br /> }<br /> ]<br /> }<br /> <br /> POST _ingest/pipeline/set_os/_simulate<br /> {<br /> "docs": [<br /> {<br /> "_source": {<br /> "os": "Ubuntu"<br /> }<br /> }<br /> ]<br /> }<br />
这样转换之后,文档内容就变成了:
java<br /> {<br /> "host" : {<br /> "os" : {<br /> "name" : "Ubuntu"<br /> }<br /> },<br /> "os" : "Ubuntu"<br /> }<br />
写单个文档的流程概述
当请求,或者索引本身配置有pipline的时候,协调节点就会转发到ingest节点
java<br /> PSOT source_index/_doc?pipeline=set_os<br /> {<br /> "os": "xxxx"<br /> }<br />
【注】 并不是一定会发生内部rpc的请求转发,如果本地节点能接受当前的请求则不会转发到其他节点。
1. 模块总体概述
本小节关注IngestService中重要的相关类,对这些类有一个整体的了解有助于理解该模块。
- ClusterService
- IngestService 实现了 ClusterStateApplier 接口, 这样就能监听和响应集群的状态变化,当集群状态更新时,IngestService可以调整其内部 pipelines完成CRUD。
- 另外IngestService还有List<Consumer
>用来对提供给对集群状态变更之后需要最新状态的插件。
- IngestService 实现了 ClusterStateApplier 接口, 这样就能监听和响应集群的状态变化,当集群状态更新时,IngestService可以调整其内部 pipelines完成CRUD。
- ScriptService
- 某些Processor需要其用于管理和执行脚本,比如Script Processor。
- 某些Processor需要其用于管理和执行脚本,比如Script Processor。
- AnalysisRegistry
- 某些需要对文档内容进行分词处理的Processor。
- 某些需要对文档内容进行分词处理的Processor。
- ThreadPool
- Processor都是异步执行的,实际执行线程池取决于调用上下文(如 write 或 management)
- bulk API 时发生的pipeline 处理使用的是write线程池。
- pipeline/_simulate API 使用的是management线程池,模拟执行通常是短时间的、低频的任务,不需要高并发支持而且为了不影响实际的文档处理或其他重要任务。
- bulk API 时发生的pipeline 处理使用的是write线程池。
- 另外为了避免Grok Processor运行时间过长,使用了Generic线程做定时调度检查执行时间
- Processor都是异步执行的,实际执行线程池取决于调用上下文(如 write 或 management)
- IngestMetric
- 通过实现ReportingService接口来做到展示ingest内部的执行情况。
- GET _nodes/stats?filter_path=nodes.*.ingest 可以查看到ingest 中的每个Pipeline中的执行的次数、失败次数以及总耗时
- 通过实现ReportingService接口来做到展示ingest内部的执行情况。
- IngestPlugin
- Ingest支持加载自定义的Processor插件,系统内置的所有Processor以及自定义的都通过IngestService 中的Map<String, Processor.Factory> processorFactories来进行管理。
- Ingest支持加载自定义的Processor插件,系统内置的所有Processor以及自定义的都通过IngestService 中的Map<String, Processor.Factory> processorFactories来进行管理。
- IngestDocument
- 其包含文档的源数据,提供了修改和查询文档的字段的能力,为Processor灵活操作文档数据提供基础,在后续pipeline的执行中,也是由其的executePipeline方法驱动的。
2. Processor 实现机制
抽象工厂设计模式的应用
Processor接口设计
每个Processor都有核心方法execute,使得处理器能够以统一的方式操作 IngestDocument,并通过多态实现不同处理逻辑。
Processor.Factory的设计
Processor.Factory 是 Processor 的抽象工厂,负责动态创建处理器实例。其主要职责包括:
- 其包含文档的源数据,提供了修改和查询文档的字段的能力,为Processor灵活操作文档数据提供基础,在后续pipeline的执行中,也是由其的executePipeline方法驱动的。
- 动态实例化:
- Processor create() 方法接收处理器配置并创建具体的处理器。
- 支持递归创建,例如ConditionalProcessor可以嵌套其他处理器。
- Processor create() 方法接收处理器配置并创建具体的处理器。
- 依赖注入:
- Processor.Parameters 提供了一组服务和工具(如 ScriptService),工厂可以利用这些依赖创建复杂的Processor。
Processor.Factory的集中管理
在 IngestService 中,通过 Map<String, Processor.Factory> processorFactories 集中管理所有处理器工厂。这种管理方式提供了以下优势:
动态扩展:
- Processor.Parameters 提供了一组服务和工具(如 ScriptService),工厂可以利用这些依赖创建复杂的Processor。
- 插件可以注册自定义Processor工厂。
- 新处理器类型的注册仅需添加到 processorFactories。
组合以及装饰器设计模式的应用
Processor经典的几个类的关系如下:
CompoundProcessor是经典的组合设计模式,Pipeline这个类可以像使用单个 Processor 一样调用 CompoundProcessor,无需关注其内部具体细节。
而ConditionalProcessor 以及TrackingResultProcessor则体现了装饰器模式,在不改变原有对象的情况下扩展功能:
- ConditionalProcessor 在执行Processor前会调用evaluate方法判断是否需要执行。
- TrackingResultProcessor中decorate是为 CompoundProcessor 及其内部的 Processor 添加跟踪功能。
如何自定义Processor 插件
自定义 Processor 插件的注册方式为实现 IngestPlugin (Elasticsearch 提供不同的插件接口用来扩展不同类型的功能)的 getProcessors 方法,该方法返回一个工厂列表,IngestService 会将这些工厂注入到 processorFactories 中。
分析完代码之后,我们回到实战中来,简单起见,我们实现类似Append的Processor,但是我们这个更简单,输入的是字符串,然后我们用,分割一下将其作为数组设为值。
java<br /> import org.elasticsearch.ingest.Processor;<br /> import org.elasticsearch.plugins.IngestPlugin;<br /> import org.elasticsearch.plugins.Plugin;<br /> import java.util.HashMap;<br /> import java.util.Map;<br /> public class AddArrayProcessorPlugin extends Plugin implements IngestPlugin {<br /> @Override<br /> public Map<String, Processor.Factory> getProcessors(Processor.Parameters parameters) {<br /> Map<String, Processor.Factory> processors = new HashMap<>();<br /> processors.put(AddArrayProcessor.TYPE, new AddArrayProcessor.Factory());<br /> return processors;<br /> }<br /> }<br />
java<br /> import org.elasticsearch.ingest.AbstractProcessor;<br /> import org.elasticsearch.ingest.ConfigurationUtils;<br /> import org.elasticsearch.ingest.IngestDocument;<br /> import org.elasticsearch.ingest.Processor;<br /> import java.util.*;<br /> <br /> public class AddArrayProcessor extends AbstractProcessor {<br /> public static final String TYPE = "add_array";<br /> public String field;<br /> public String value;<br /> protected AddArrayProcessor(String tag, String description, String field, String value) {<br /> super(tag, description);<br /> this.field = field;<br /> this.value = value;<br /> }<br /> @Override<br /> public IngestDocument execute(IngestDocument ingestDocument) throws Exception {<br /> List valueList = new ArrayList<>(Arrays.asList(value.split(",")));<br /> ingestDocument.setFieldValue(field, valueList);<br /> return ingestDocument;<br /> }<br /> @Override<br /> public String getType() {<br /> return TYPE;<br /> }<br /> public static final class Factory implements Processor.Factory {<br /> @Override<br /> public Processor create(Map<String, Processor.Factory> processorFactories, String tag,<br /> String description, Map<String, Object> config) throws Exception {<br /> String field = ConfigurationUtils.readStringProperty(TYPE, tag, config, "field");<br /> String value = ConfigurationUtils.readStringProperty(TYPE, tag, config, "value");<br /> return new AddArrayProcessor(tag, description, field, value);<br /> }<br /> }<br /> }<br />
打包之后,我们去install我们的Processor插件:
java<br /> bin/elasticsearch-plugin install file:///home/hcb/data/data/es/data_standalone/elasticsearch-7.10.2-SNAPSHOT/AddArrayProcessor-1.0-SNAPSHOT.zip <br /> warning: no-jdk distributions that do not bundle a JDK are deprecated and will be removed in a future release<br /> -> Installing file:///home/hcb/data/data/es/data_standalone/elasticsearch-7.10.2-SNAPSHOT/AddArrayProcessor-1.0-SNAPSHOT.zip<br /> -> Downloading file:///home/hcb/data/data/es/data_standalone/elasticsearch-7.10.2-SNAPSHOT/AddArrayProcessor-1.0-SNAPSHOT.zip<br /> [=================================================] 100% <br /> -> Installed AddArrayProcess<br />
测试一下:
java<br /> POST /_ingest/pipeline/_simulate<br /> {<br /> "pipeline": {<br /> "processors": [<br /> {<br /> "add_array": {<br /> "field": "test_arr",<br /> "value": "a,b,c,d,e,f"<br /> }<br /> }<br /> ]<br /> },<br /> "docs": [<br /> {<br /> "_index": "test",<br /> "_id": "1",<br /> "_source": {<br /> "field": "value"<br /> }<br /> }<br /> ]<br /> }<br /> docs结果:<br /> "_source" : {<br /> "field" : "value",<br /> "test_arr" : [<br /> "a",<br /> "b",<br /> "c",<br /> "d",<br /> "e",<br /> "f"<br /> ]<br /> }<br />
3. Pipeline设计
如何管理Pipeline
在IngestServcie中有一个Map存储所有的Pipeline实例,private volatile Map<String, PipelineHolder> pipelines = Collections.emptyMap();
这里并没有将Pipeline实例存储在IngestMetadata,这样做的原因有2个:
- 在 Elasticsearch 的启动过程中,插件和节点服务的初始化发生在 ClusterState 加载之后, 只有等所有插件完成加载后,所有的Processor工厂才会被注册到系统中,这意味着在集群状态初始化之前,Processor工厂并不可用。
- ClusterState 中的元数据结构是静态注册的,即在类加载时已经确定,如果要将运行时示例存储进去,必须改变 ClusterState 的元数据结构存储格式,这个很不方便维护,而且这在集群状态同步的时候也会带来不必要的序列化以及反序列化。
所以Pipeline的管理逻辑是:
- 在 Elasticsearch 的启动过程中,插件和节点服务的初始化发生在 ClusterState 加载之后, 只有等所有插件完成加载后,所有的Processor工厂才会被注册到系统中,这意味着在集群状态初始化之前,Processor工厂并不可用。
- ClusterState 中的IngestMetadata 只存储 JSON 格式的管道定义,描述 Pipeline 的配置(例如,包含哪些 Processor,它们的参数等)。
- IngestService 中维护的运行时实例,将 JSON 配置解析为完整的 Pipeline 对象,包括处理器链
在集群变更时, pipeline的CRUD的实现在innerUpdatePipelines方法中 。
责任链设计模式的应用
管道的执行通过IngestDocument的org.elasticsearch.ingest.IngestDocument#executePipeline 去驱动,每个文档的每个Pipeline都会进入到这个函数, 而每个Pipeline有组装好的CompoundProcessor,实际的链式调用是在CompoundProcessor中。
简图大致如下:
这里拿其和Zookeeper(3.6.3)中RequestProcessor 做一些对比:
| 特点 | ES中的CompoundProcessor | Zookeeper中RequestProcessor |
| --- | --- | --- |
| 链的存储定义 | 由两条列表组成,分别保存正常流程以及失败流程的Processor列表。 | 固定的链式结构。 |
| 异步执行 | 支持异步回调,可以异步执行链中的处理器。 | 同步执行 。 |
| 失败处理 | 提供专门的 onFailureProcessors 作为失败处理链。如果不忽略异常并且onFailureProcessors 不为空则会执行失败处理链逻辑。 | 没有专门的失败处理链,异常直接交由上层捕获。 |
| 可配置性 | 可动态调整处理器链和配置(如 ignoreFailure)。 | 代码中写死,无法配置 |
这里并没有说Zookeeper的设计就差于Elasticsearch, 只是设计目标有所不同,RequestProcessor就是适合集中式的强一致、其中Processor并不需要灵活变化,而CompoundProcessor就是适合高并发而Procesor灵活变化场景。
4. Ingest实战建议
回到实战中来,这里结合目前所分析的内容给出相应的实战建议。
- 建立监控
- 对于关键的Piepline,我们需要通过GET _nodes/stats?filter_path=nodes.*.ingest 获取其运行状况,识别延迟或失败的 Processor。
- 文档写入的时候使用的是write线程池,我们也需要监控GET _nodes/stats?filter_path=nodes.*.thread_pool.write 的queue和write_rejections 判断需要扩展线程池。
- 对于关键的Piepline,我们需要通过GET _nodes/stats?filter_path=nodes.*.ingest 获取其运行状况,识别延迟或失败的 Processor。
- 优化Processor
- 减少高开销操作,优先使用内置 Processor,比如script Processor 可适时替换set, append,避免过度复杂的正则表达式或嵌套逻辑。
- 自定义的Processor尽量优化,比如如果涉及查询外部系统可考虑引入缓存。
- 减少高开销操作,优先使用内置 Processor,比如script Processor 可适时替换set, append,避免过度复杂的正则表达式或嵌套逻辑。
- 建立单独的Ingest节点
- 如果有大量的Pipeline需要执行,则可以考虑增加专用 Ingest 节点,避免与数据节点争夺资源。
5. 漏洞&&修复分析
这里分析7.10.2版本Ingest模块存在的漏洞以及官方是如何修复的。
CVE-2021-22144
https://discuss.elastic.co/t/e ... 78100
Elasticsearch Grok 解析器中发现了一个不受控制的递归漏洞,该漏洞可能导致拒绝服务攻击。能够向 Elasticsearch 提交任意查询的用户可能会创建恶意 Grok 查询,从而导致 Elasticsearch 节点崩溃。
漏洞复现
发起这个请求:
- 如果有大量的Pipeline需要执行,则可以考虑增加专用 Ingest 节点,避免与数据节点争夺资源。
- patterns: 处理字段时使用的 Grok 模式,这里设置为 %{INT}。
- pattern_definitions: 定义自定义 Grok 模式,这里故意让 INT 模式递归引用自身,导致循环引用问题。
go<br /> POST /_ingest/pipeline/_simulate<br /> {<br /> "pipeline": {<br /> "processors": [<br /> {<br /> "grok": {<br /> "field": "message",<br /> "patterns": [<br /> "%{INT}"<br /> ],<br /> "pattern_definitions": {<br /> "INT": "%{INT}"<br /> }<br /> }<br /> }<br /> ]<br /> },<br /> "docs": [<br /> {<br /> "_source": {<br /> "message": "test"<br /> }<br /> }<br /> ]<br /> }<br /> <br />
当执行之后会使得节点直接StackOverflow中止进程。
修复逻辑
这个问题的关键在于原先的逻辑中,只会对间接的递归引用(pattern1 => pattern2 => pattern3 => pattern1)做了检测,但是没有对直接的自引用(pattern1 => pattern1 )做检测。
java<br /> private void forbidCircularReferences() {<br /> // 这个是增加的逻辑,检测直接的自引用<br /> for (Map.Entry<String, String> entry : patternBank.entrySet()) {<br /> if (patternReferencesItself(entry.getValue(), entry.getKey())) {<br /> throw new IllegalArgumentException("circular reference in pattern [" + entry.getKey() + "][" + entry.getValue() + "]");<br /> }<br /> }<br /> <br /> // 间接递归引用检测(这个是原先的逻辑)<br /> for (Map.Entry<String, String> entry : patternBank.entrySet()) {<br /> String name = entry.getKey();<br /> String pattern = entry.getValue();<br /> innerForbidCircularReferences(name, new ArrayList<>(), pattern);<br /> }<br /> }<br />
CVE-2023-46673
https://discuss.elastic.co/t/e ... 47708
漏洞复现
尝试了很多已有的Processor都没有复现,我们这使用自定义的Processor来复现,将之前的自定义AddArrayProcessor加一行代码:
java<br /> @Override<br /> public IngestDocument execute(IngestDocument ingestDocument) throws Exception {<br /> List valueList = new ArrayList<>(Arrays.asList(value.split(",")));<br /> valueList.add(valueList); // 增加的代码<br /> ingestDocument.setFieldValue(field, valueList);<br /> return ingestDocument;<br /> }<br />
重新编译再安装插件之后,执行改Processor 将会StackOverflow。
修复逻辑
这个问题的关键在于在IngestDocument的deepCopyMap的方法之前没有判断这样的无限引用的情况:
那么在此之前做一个检测就好了,这个方法在原本的ES代码中就存在:org.elasticsearch.common.util.CollectionUtils#ensureNoSelfReferences(java.lang.Object, java.lang.String) ,其利用 IdentityHashMap 记录已访问对象的引用,检测并防止对象间的循环引用。
CVE-2024-23450
https://discuss.elastic.co/t/e ... 56314
漏洞复现
虽然我们的索引只有2个Pipeline的配置,但是由于Pipeline Processor的存在,所以实际上一个文档其实能被很多Pipeline处理,当需要执行足够多个的pipline个数时,则会发生StackOverflow。
修复逻辑
这个问题的关键在于对Pipeline的个数并没有限制,添加一个配置项,当超出该个数则直接抛出异常。
java<br /> public static final int MAX_PIPELINES = Integer.parseInt(System.getProperty("es.ingest.max_pipelines", "100"));<br />
IngestDocument的org.elasticsearch.ingest.IngestDocument#executePipeline 添加逻辑:
java<br /> public void executePipeline(Pipeline pipeline, BiConsumer<IngestDocument, Exception> handler) {<br /> if (executedPipelines.size() >= MAX_PIPELINES) {<br /> handler.accept(<br /> null,<br /> new IllegalStateException(PIPELINE_TOO_MANY_ERROR_MESSAGE + MAX_PIPELINES + " nested pipelines")<br /> );<br /> } <br />
思考: 这里判断pipeline是否超出100个限制是用已经执行的pipeline个数来计算的。 假设已经超出100个pipeline,那这100个pipeline是会白跑的, 如果能在真正执行之前分析需要执行的Pipeline个数会更好。
6. 总结
Ingest 模块作为 Elasticsearch 数据处理流程的重要组成部分,提供了灵活的管道化能力,使得用户能够在数据写入前进行丰富的预处理操作。然而,在实际场景中,Ingest 模块也面临性能瓶颈、资源竞争等挑战,需要结合业务需求和系统现状进行精细化调优,通过优化 Processor 执行效率、合理规划集群架构以及增强监控与诊断手段,我们可以充分释放 Ingest 模块的能力,提升 Elasticsearch 的整体数据处理能力。
ES官方版本为什么到现在为止没有提供限流的功能?
Fred2000 回复了问题 • 2 人关注 • 1 个回复 • 2614 次浏览 • 2024-12-19 19:18
es filter script获取nested结构数据如何实现?
duanxiaobiao 回复了问题 • 2 人关注 • 1 个回复 • 4049 次浏览 • 2024-11-16 22:04