- 搜索引擎
- 全文检索
- 可观测性
- 数据分析
【免费下载链接】OpenSearch
🔎 Open source distributed and RESTful search engine.
2024 年 7 月 24 日发布的 OpenSearch 2.16.0 是一次功能密度极高的版本迭代:它在摄取侧新增了 fingerprint 指纹处理器和批量处理器基类,在搜索侧为搜索管线新增了 sort、split 两个响应处理器,在映射侧引入了strict_allow_templates动态映射策略,同时完成了 Lucene 9.11.1 升级与多项远程存储、工作负载管理(Workload Management)能力建设。本文以官方发布说明为骨架,结合仓库源码逐项解读这些新特性、行为变更与修复,帮助你在升级到 2.16.0 后快速掌握新增能力并规避兼容性风险。
一、版本概览与整体定位
OpenSearch 2.16.0 于 2024-07-24 发布,其发布说明(release-notes/opensearch.release-notes-2.16.0.md)按照 Added(新增)、Dependencies(依赖)、Changed(变更)、Deprecated(废弃)、Removed(移除)、Fixed(修复)六个维度记录了本次迭代的完整变更清单。从整体脉络看,本版本的核心方向包括:
- 摄取与搜索管线的双向增强:新增 fingerprint 摄取处理器,新增 sort、split 两个搜索响应处理器,并引入
AbstractBatchingProcessor批量处理基类; - 动态映射策略扩展:新增
strict_allow_templates(以及配套的false_allow_templates)动态选项; - 远程存储与分层存储持续演进:远程存储低优先级上传限流、shard-diff 路径优化、hot-to-warm 分层专用部署的 REST/传输层改造;
- 工作负载管理(WLM)进入落地阶段:QueryGroup schema 与跨节点 queryGroupId 头传播;
- Lucene 9.11.1 基础库升级及一批依赖版本刷新。
下文将按照发布说明的章节顺序,对每一项内容做源码级展开。
二、Added:新增能力逐项解读
2.1 Fingerprint 摄取处理器:为文档生成稳定指纹
本版本为 ingest-common 模块新增了fingerprint处理器(对应 PR #13724),用于基于指定的一个或多个字段生成哈希值并写入目标字段。该处理器非常适合去重、变更检测、数据血缘追踪等场景——你可以对一批文档的相同字段集合计算指纹,从而快速识别内容是否发生变化。
在源码 FingerprintProcessor.java 中,其配置参数定义如下:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fields | 字符串数组 | 无 | 用于生成指纹的字段列表;与exclude_fields互斥 |
exclude_fields | 字符串数组 | 无 | 排除字段列表,除这些字段外的其余字段参与指纹计算 |
target_field | 字符串 | fingerprint | 存放指纹结果的目标字段 |
hash_method | 字符串 | SHA-1@2.16.0 | 哈希算法,可选MD5@2.16.0、SHA-1@2.16.0、SHA-256@2.16.0、SHA3-256@2.16.0 |
ignore_missing | 布尔 | false | 指定字段不存在时,为true则跳过该字段,为false则抛异常 |
一个典型的配置示例如下:
{ "description": "为日志文档生成指纹", "processors": [ { "fingerprint": { "fields": ["message", "level", "host"], "target_field": "doc_fingerprint", "hash_method": "SHA-256@2.16.0", "ignore_missing": true } } ] }从源码实现可以看到几个值得注意的设计细节:
- 字段名去重与排序:
execute()方法会对参与计算的字段做distinct()与sorted(),确保无论字段声明顺序如何,只要字段集合相同,指纹结果就一致(FingerprintProcessor.java); - 元数据字段豁免:
_index、_id、_routing等元数据字段会被自动过滤,不参与指纹计算,避免因写入目标不同导致指纹漂移; - 嵌套对象扁平化:Map 类型的字段值会通过
toFlattenedMap()递归扁平化为a.b形式的键(如{"a": {"b": 1}}→a.b: 1),再按键排序拼接(FingerprintProcessor.java); - 稳定的拼接格式:拼接串形如
|field|value.length:value|,最终指纹写为hashMethod + ":" + Base64(hash); - 哈希方法带版本后缀:
HASH_METHODS集合中的方法名统一带有@2.16.0后缀(FingerprintProcessor.java),源码注释明确指出:若未来版本修改处理逻辑,应同步递增版本号,以保证同一哈希方法在不同版本间不会静默产生不同结果——这保证了指纹的长期稳定性,也提醒使用方在升级后如需保持旧指纹兼容,应继续使用带旧版本后缀的方法名; - 线程安全:
MessageDigest非线程安全,因此HashMethod枚举通过 supplier 每次调用获取全新的 ThreadLocal 实例,避免多摄取线程并发共享导致哈希错误。
与之配套的单元测试位于 FingerprintProcessorTests.java 与 FingerprintProcessorFactoryTests.java,覆盖了 fields/exclude_fields 互斥校验、非法哈希方法报错、嵌套字段扁平化等行为。
2.2 搜索管线新增响应处理器:sort 与 split
本版本为 search-pipeline-common 模块的搜索管线新增了两个响应阶段处理器(response processor):sort(PR #14785)与split(PR #14800)。它们运行在搜索请求返回之后、结果返回给客户端之前,允许你在服务端直接改写响应内容,减少客户端后处理负担。
SortResponseProcessor(类型名sort),源码见 SortResponseProcessor.java:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
field | 字符串 | 必填 | 要排序的数组字段 |
order | 字符串 | asc | 排序方向,asc或desc |
target_field | 字符串 | 与field相同 | 排序结果写入的字段,不设置则原地覆盖 |
示例管线配置:
{ "description": "对响应中的 tags 数组按降序排序", "response_processors": [ { "sort": { "field": "tags", "order": "desc" } } ] }从源码看,该处理器会遍历每个 SearchHit,同时对hit.getFields()中的 doc values 字段和_source中的对应字段做排序;getSortedValues()会把值先降级为Comparable,值不可比(如包含 null 或非 Comparable 类型)时会抛出带明确提示的异常(SortResponseProcessor.java)。
SplitResponseProcessor(类型名split),源码见 SplitResponseProcessor.java:
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
field | 字符串 | 必填 | 待拆分的字符串字段 |
separator | 字符串 | 必填 | 分隔符,支持正则表达式 |
preserve_trailing | 布尔 | false | 是否保留末尾的空字符串元素 |
target_field | 字符串 | 与field相同 | 拆分结果写入的字段 |
示例管线配置:
{ "response_processors": [ { "split": { "field": "csv_line", "separator": ",", "preserve_trailing": true, "target_field": "csv_parts" } } ] }实现上,split直接复用 Java 的String.split(separator, preserveTrailing ? -1 : 0):preserve_trailing=true时以-1为 limit 保留尾部空串,false时以0为 limit 丢弃尾部空串(SplitResponseProcessor.java);若目标字段不是字符串类型,会抛出异常。两者的单元测试分别见 SortResponseProcessorTests.java 与 SplitResponseProcessorTests.java。
2.3 动态映射新选项:strict_allow_templates
本版本为dynamic映射参数新增了strict_allow_templates选项(PR #14555),并同步引入了配套的false_allow_templates。此前dynamic只有true、false、strict、runtime四种取值:
true:未知字段自动加入映射;false:忽略未知字段(不报错、不入映射);strict:遇到未知字段直接拒绝文档;strict_allow_templates(新增):未知字段仅当匹配某个动态模板时才被接受,否则抛出StrictDynamicMappingException拒绝文档;false_allow_templates(新增):未知字段若匹配动态模板则按模板处理,否则静默忽略。
在映射解析源码 ObjectMapper.java 中,新增了两个枚举值STRICT_ALLOW_TEMPLATES与FALSE_ALLOW_TEMPLATES,与原有的STRICT、TRUE、FALSE并列。落地行为位于 DocumentParser.java:findTemplateBuilder()在未找到匹配动态模板时,若当前对象的dynamic为STRICT_ALLOW_TEMPLATES,则抛出StrictDynamicMappingException。
这一策略的实战价值在于:当你希望严格控制索引结构(拒绝随意新增字段),但又允许少量通过动态模板预先定义的半结构化字段(如带前缀的日志字段、metric 字段)自动落入映射时,strict_allow_templates是strict的柔性替代方案。配置示例:
{ "mappings": { "dynamic": "strict_allow_templates", "dynamic_templates": [ { "metric_*": { "match_mapping_type": "long", "match": "metric_*", "mapping": { "type": "long" } } } ] } }上述映射下,写入metric_cpu字段会被接受并按 long 建映射,而写入未匹配任何模板的foo字段则会抛出strict_dynamic_mapping_exception。相关行为在 DocumentParserTests.java 与 CopyToMapperTests.java 中有完整测试覆盖。
2.4 AbstractBatchingProcessor:面向批量场景的处理器基类
PR #14554 在server模块新增了 AbstractBatchingProcessor.java,为需要"一次性处理一批文档"的摄取处理器提供通用基类。核心设计如下:
- 通过
batch_size参数控制每批文档数,默认值为 1,且校验必须是正整数(< 1时抛出配置异常); - 抽象方法
subBatchExecute(List<IngestDocumentWrapper>, Consumer<List<IngestDocumentWrapper>>)由具体处理器实现"批量处理逻辑"; batchExecute()负责把传入的文档列表按batch_size切成多个子批次,并发提交各子批次,并通过AtomicInteger计数器在所有子批次完成后统一回调 handler(AbstractBatchingProcessor.java);- 基类内同时定义了抽象的
Factory,统一完成batch_size参数解析。
该基类的意义在于为后续出现的一类"批处理型"摄取处理器(如批量去重、批量聚合、外部批量 API 调用等)提供了标准骨架,避免各处理器重复实现切批与并发归并逻辑。其测试见 AbstractBatchingProcessorTests.java。
2.5 处理器 Allowlist:收窄 ingest-common 与 search-pipeline-common 可用处理器
针对多租户与安全加固场景,PR #14439 为 ingest-common 和 search-pipeline-common 的处理器注册增加了 allowlist 过滤能力。
在 IngestCommonModulePlugin.java 中定义了节点级设置:
ingest.common.processors.allowed该设置是一个字符串列表,默认空。filterForAllowlistSetting()(IngestCommonModulePlugin.java)在getProcessors()返回注册表前执行过滤:若 allowlist 中存在未注册的处理器名,会抛出IllegalArgumentException明确指出未知项;否则只保留 allowlist 中列出的处理器。search-pipeline-common 侧采用相同的机制(见 SearchPipelineCommonModulePlugin.java),其配套测试位于 SearchPipelineCommonModulePluginTests.java。
典型配置(opensearch.yml):
ingest.common.processors.allowed: ["set", "rename", "fingerprint", "grok"]配置后,未列入清单的处理器(如script、json)将无法在该节点上被创建,适合作为共享集群上的最小权限治理手段。
2.6 Workload Management:QueryGroup Schema 与跨节点传播
本版本继续推进工作负载管理(WLM)能力:
- QueryGroup schema(PR #13669):为工作负载组定义了统一的数据模型;
- queryGroupId 头跨节点传播(PR #14614):为搜索请求增加 queryGroupId 头传播器,使查询请求在协调节点与数据节点之间传递时能够携带所属工作负载组标识,为后续基于组的资源隔离、限流与调度提供数据基础。
对应实现位于plugins/workload-management模块,相关的端到端验证可参考 WlmAutoTaggingIT.java 以及 10_workload_group.yml 中的 REST 测试用例。
2.7 远程存储与分层存储演进
2.16.0 在远程存储(Remote Store)方向有多项配套优化:
- 远程存储低优先级上传限流器(PR #14374):为 remote store 的低优先级上传引入速率限制,避免后台低优任务挤占主路径带宽;
- diff manifest 增加 shard-diff 路径(PR #14684):通过减少远程存储的读取调用次数来降低延迟;
- remote-routing-table 服务按远程状态接口重构(PR #14668):将路由表服务与 remote state 接口体系对齐;
- hot-to-warm 分层存储专用部署的 REST/传输层改造(PR #13980):为独立部署形态的 hot/warm 分层(Writable Warm)打通请求链路;
- Writable Warm 的 composite directory 实现并与 FileCache 集成(PR #12782):为可写温存储提供目录抽象层。
其中 composite directory 与 FileCache 的集成属于分层存储的底层文件系统抽象,为后续把温数据段纳入文件缓存管理奠定了基础。
2.8 其他新增项
- SystemIndexRegistry(PR #14415、#14750):新增系统索引注册表,提供
matchesSystemIndex()与matchesPluginSystemIndexPattern()两个辅助方法,统一了系统索引的判定逻辑; - 应用配置模板加载 Plugin 接口(PR #14659):新增 Plugin 级接口,允许插件加载基于应用(application-based)的配置模板;
- date histogram 重写优化应用于 range 聚合(PR #13865):将 date histogram 的重写优化推广到 range 聚合,减少不必要的文档访问;
- 父任务取消原因打印(PR #14604):任务被取消时输出父任务的取消原因,提升可观测性;
- TransportNodesAction 优化(PR #14749):NodeStats、NodesInfo、ClusterStats 请求不再携带 DiscoveryNodes,减少传输开销;
- MasterService:run 的 DEBUG 日志降噪(PR #14795);
- 本地状态 term 版本校验(PR #14273):所有 ClusterManager 只读传输动作启用本地状态的 term 版本检查,增强集群状态一致性保护;
- Cluster Stats Indices 预计算节点级统计(PR #14426);
- 搜索线程资源使用刷新监听器(PR #14832):创建监听器以定期刷新搜索线程资源使用情况,服务于资源感知调度;
- 支持基于 context 字段创建 v2 索引模板(PR #14811);
- 从搜索定义解析派生字段的竞态条件修复(PR #14445):该条目虽列入 Added,本质是修复解析派生字段时的竞态问题。
三、Dependencies:Lucene 9.11.1 与依赖栈刷新
本版本最重要的基础库升级是Apache Lucene 从 9.x 升级到 9.11.1(PR #14042、#14576),为全文检索、聚合与编解码层带来持续改进。其余主要依赖变更如下:
| 依赖 | 变更 |
|---|---|
| netty | 4.1.110.Final → 4.1.111.Final |
| reactor / reactor-netty | 3.5.17 → 3.5.19 / 1.1.19 → 1.1.21 |
| jackson | 2.17.1 → 2.17.2 |
| opentelemetry | 1.36.0 → 1.40.0(semconv 同步至 1.26.0-alpha) |
| wiremock-standalone | 3.3.1 → 3.6.0 |
| nimbus-jose-jwt | 9.37.3 → 9.40 |
| commons-net | 3.10.0 → 3.11.1 |
| commons-configuration2 | 2.10.1 → 2.11.0 |
| azure-identity / msal4j 系列 | 多版本刷新(含 azure-storage-common 至 12.25.1) |
| mustache.java compiler | 0.9.13 → 0.9.14 |
| json-smart / accessors-smart | 2.5.0 → 2.5.1 |
| com.gradle.develocity | 3.17.4 → 3.17.5 |
这些依赖的具体锁定版本可对照 gradle/libs.versions.toml 与各模块 licenses 目录下的.jar.sha1文件核实。
四、Changed:行为变更与动态化调整
4.1 indices.query.bool.max_clause_count 改为动态可更新
PR #13568 将indices.query.bool.max_clause_count从静态设置(需重启节点)改为动态可更新。这意味着集群运行期间可以通过PUT _cluster/settings直接调整布尔查询的最大子句数上限,无需重启,显著降低了调优成本。
从源码看,该值通过SearchService的动态设置更新回调传播到 LuceneIndexSearcher的静态字段,查询构建时再读取生效值。以 terms lookup 子查询为例,TermsQueryBuilder.java 会同时读取max_terms_count、max_result_window与IndexSearcher.getMaxClauseCount(),取三者最小值作为拉取上限,避免子查询结果超过任何一项限制;SearchService.java 是该项动态设置的核心承载位置。升级后如需调整上限,可直接执行:
PUT /_cluster/settings { "transient": { "indices.query.bool.max_clause_count": 2048 } }4.2 其余行为变更
- Tiered Caching 查询重计算移出写锁(PR #14187):将查询重算逻辑从写锁内移出,降低写路径持锁时间,改善并发吞吐;
- unsignedLongRangeQuery 边界语义修正(PR #14416):当下界大于上界时,直接返回
MatchNoDocsQuery而不是空结果或异常; - CommunityIdProcessor 设为 final(PR #14448):禁止外部继承该处理器类;
- @InternalApi 注解能力扩展(PR #14575、#14597):允许在不应由核心外部构造的类上使用
@InternalApi,并将其纳入 japicmp API 兼容性检查的排除清单; - reroute 迭代限时(PR #14848):为大规模分片分配场景下的 reroute 迭代设置时间上限,避免单次分配循环过长;
- refreshAllIndices 允许系统索引警告(PR #14635):测试框架层面放宽对系统索引刷新的告警。
五、Deprecated 与 Removed:废弃与移除
- 废弃 bulk API 的
batch_size参数(PR #14725):bulk 请求体中的batch_size参数被标记为废弃,建议使用其他批量控制手段;该参数未来版本将被移除; - 移除 query categorization 变更(PR #14759):撤销此前对查询分类(query categorization)的相关改动。
六、Fixed:值得关注的修复亮点
发布说明共记录 20+ 项修复,以下按业务影响面分类说明:
查询与映射正确性
match_phrase_prefix_query在多值 text 字段 +index_prefixes组合下失效的问题(PR #10959)得到修复;- FuzzyQuery 在 keyword 字段上同时启用 index 与 doc_values 时会退化为 IndexOrDocValuesQuery 的问题(PR #14378);
- ScriptProcessor 摄取管线对 Short/Byte 类型处理异常(PR #14379);
- WKT 格式解析器改为迭代实现,规避递归栈风险(PR #14086);
- FilterPath.parse 与 Grok.validatePatternBank 同样改为迭代式实现(PR #14200、#14206)。
聚合与索引
- 带子 NestedAggregator 的 NestedAggregator 聚合结果错误(PR #13324);
- InternalHistogram 添加空桶时引入 circuit breaker 保护(PR #14754);
- 集群最大分片数计算避免 int 溢出(PR #14155)。
摄取与写入
- bulk upsert 在自动创建索引命中索引模板时忽略
default_pipeline与final_pipeline的问题(PR #12891); - 创建索引时
index.number_of_replicas为 null 触发 NPE(PR #14812); - 快照 searchable snapshot 索引时未写分片级元数据 blob(PR #13190);
- 多部分上传创建新的 IndexInput(PR #14888);
- searchable snapshot 配合 scripted fields 失败(PR #14411)。
API 与稳定性
- rest-high-level client 的
searchTemplate与mtermVectors端点缺少前导斜杠(PR #14465); - create/update alias API 未对不支持的参数抛异常(PR #14719);
- GetResult 缺少
found字段时 NPE(PR #14552); - ReplicaShardAllocator NPE(PR #14385);
- SBP 取消逻辑缺陷(PR #13259);
- fs info 报告负可用空间(PR #11573);
- ListPitInfo 增加
getKeepAlive()getter(PR #14495); _cat帮助输出更新(PR #14722)。
七、升级与使用建议
综合以上变更,从 2.15 及更早版本升级到 2.16.0 时建议重点关注:
- 兼容性提示:
indices.query.bool.max_clause_count已动态化,原先依赖重启生效的自动化脚本可改为热更新;bulk的batch_size已废弃,排查现有客户端是否仍在使用并尽快迁移; - 新能力接入:指纹去重可直接使用
fingerprint处理器;需要服务端改写响应时优先考虑搜索管线的sort/split响应处理器;严格控制映射结构可启用strict_allow_templates; - 安全治理:多租户共享集群可通过
ingest.common.processors.allowed等 allowlist 设置收窄可用处理器面; - 底层升级验证:Lucene 9.11.1 与 netty、jackson、opentelemetry 等依赖均有升级,建议升级前在测试环境跑一遍聚合、检索与摄取回归,特别是使用了 FuzzyQuery、match_phrase_prefix、嵌套聚合与 searchable snapshot 的场景;
- 可观测性:父任务取消原因打印与 ClusterStats 传输优化可帮助更快速地定位任务取消与节点统计问题。
本文涉及的源码与测试文件均可直接在仓库中查看:fingerprint 处理器实现见 FingerprintProcessor.java,响应处理器见 SortResponseProcessor.java 与 SplitResponseProcessor.java,动态映射策略见 ObjectMapper.java 与 DocumentParser.java,批量基类见 AbstractBatchingProcessor.java,处理器 allowlist 见 IngestCommonModulePlugin.java。发布说明原文见 release-notes/opensearch.release-notes-2.16.0.md。
- 搜索引擎
- 全文检索
- 可观测性
- 数据分析
【免费下载链接】OpenSearch
🔎 Open source distributed and RESTful search engine.
相关推荐
napi-rs与Node-API版本映射:特性检测与降级处理
napi rs与Node API版本映射:特性检测与降级处理 Node API(简称N API)是Node.js提供的跨版本二进制接口,允许原生插件在不同Nod
开发工具后端鸿蒙应用版本管理:应用更新与特性灰度发布策略
鸿蒙应用版本管理:应用更新与特性灰度发布策略 你是否曾因应用更新导致用户体验下降而头疼?是否想逐步推出新功能以降低风险?本文将详细介绍鸿蒙(HarmonyOS)
示例工程CachyOS内核新手入门:5分钟了解三大调度器BORE/EEVDF/BMQ差异
CachyOS内核新手入门:5分钟了解三大调度器BORE/EEVDF/BMQ差异 CachyOS是基于Arch Linux的优化内核项目,通过不同的调度器和性能
操作系统
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考