9.0 移除了
data_frame_transforms_admin和data_frame_transforms_user。这不是那种"配了不生效"的静默改动——用旧角色建的 Transform 会起不来,而且健康检查变红。坏消息很明确,好消息也很明确:报错清楚、位置明确、改法唯一。
说明
来源和边界先交代:本文的依据出自 v9.4.2 标签下的官方文件(9.0.0.yml、ClusterPrivilegeResolver.java、breaking-changes.md),文中引用的原文均来自这些文件。示例取自官方示例;哪些是文档写明、哪些是我的推断,正文里逐处标注。
实测环境:本地另起一个 Elasticsearch 9.4.2 单节点实例(官方 tar 包,端口 9900,独立 path.data 与 path.logs),开启安全特性:keystore 写入 bootstrap.password 后用 -u elastic:elasticpw 走 HTTPS 认证;实验实例还开了 trial 许可(内置角色、Watcher 与 ML 需要)。文末「在 9.4.2 上跑一遍」里的命令与响应均取自该实例。

图 1:官方文件 9.0.0.yml(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 9.0.0.yml
官方条目
9.0 的 changelog 标为 breaking(9.0.0.yml 第 637–648 行 @ v9.4.2),area: Transform,PR 117519。
details 和 impact 都很完整,是少数几条把"会怎样、怎么改"都写清楚的 breaking。

图 2:官方文件 ClusterPrivilegeResolver.java(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 ClusterPrivilegeResolver.java
改了什么
官方 details 原文:
data_frame_transforms_adminanddata_frame_transforms_userwere deprecated in Elasticsearch 7 and are being removed in Elasticsearch 9.data_frame_transforms_adminis nowtransform_admin.data_frame_transforms_useris nowtransform_user. Users must call the_updateAPI to replace the permissions on the Transform before the Transform can be started.
拆开看:
| 旧角色 | 新角色 |
|---|---|
data_frame_transforms_admin |
transform_admin |
data_frame_transforms_user |
transform_user |
弃用于 7.x,移除于 9.0。 中间跨了整个 8.x——给了足够长的过渡期。

图 3:官方文件 breaking-changes.md(v9.4.2 标签)。来源:GitHub elastic/elasticsearch v9.4.2 breaking-changes.md
名字背后的改名
这里有个历史背景值得说:Transform 这个功能以前叫 "data frame transforms"。
所以 data_frame_transforms_* 这套命名是旧功能名的遗留。后来功能改叫 transform,角色名跟着改成 transform_*。旧名字从 7.x 开始弃用,到 9.0 才真正删掉。
这个跨度是本篇最有意思的地方——一个角色名的清理走了三个大版本。原因在官方那句 impact 里能看出来:角色被写进了已有的 Transform 对象里。
起不来,且健康检查变红
官方 impact 原文:
Transforms created with either the
data_frame_transforms_adminor thedata_frame_transforms_userrole will fail to start. The Transform will remain in astoppedstate, and its health will be red while displaying permission failures.
三个状态很明确:
- 启动失败;
- 停在
stopped; - 健康检查报红,显示权限错误。
这是本篇最该记住的一点:它是明确的、看得见的失败,不是配了没效果。
判断这类 breaking 属于"好处理的那一类"——它会主动告诉你出问题了。相比前面写过的那些静默失效(_source mode 设置迁移 的 _source.mode、discovery-ec2 换 SDK v2 的 ec2 协议),这条的排查成本低得多:看 Transform 列表的红状态就能定位。
怎么修
官方给的动作:调 _update API 换掉 Transform 上的权限。
注意它的措辞是 "replace the permissions on the Transform"——要改的是 Transform 对象本身携带的权限,不是只改角色定义。
这一点是关键。因为很多人的第一反应是"改角色映射",但官方说的是更新 Transform。差别在于:
- 角色(role)是安全模块里的定义;
- Transform 上记录的权限是创建它时"当时的"权限快照。
旧角色被删了,但 Transform 上还写着旧名字——所以要更新的是后者。
具体的 _update 调用形式以你版本的文档为准,未实测,这里不给出完整请求体以免误导。核心动作是:对每个用了旧角色的 Transform,调一次更新接口把权限换成新角色。
怎么排查
最直接的办法:看 Transform 的健康状态。
# 列出 transform 及其健康状态
curl -s 'localhost:9200/_transform/_health?pretty' | grep -A5 '"red"'
# 或者逐个看
curl -s 'localhost:9200/_transform?pretty'
红的就是有问题的。 由于官方说了失败时会显示权限错误,排查方向很明确——看到红状态基本就能确定是这条。
更主动的办法(升级前做):直接搜配置里有没有旧名字。
# 在角色定义里找
curl -s 'localhost:9200/_security/role?pretty' | grep -i "data_frame_transforms"
# 在 transform 配置里找
curl -s 'localhost:9200/_transform?pretty' | grep -i "data_frame_transforms"
只要这两处都没有,升级就不会遇到这条问题。 倾向是升级前先跑一遍,因为它比升级后排查便宜得多。
(说明:上面几条命令的路径已在文末实测跑过,具体参数以实际版本的文档为准。)
权限名没跟着删
这里有个细节容易混淆,值得说——我的判断是它比改名本身更容易出错。
删的是角色(role):data_frame_transforms_admin / data_frame_transforms_user。
权限(privilege)名字还在。 源码里能看到(ClusterPrivilegeResolver.java 第 251 行、第 271 行,源码 @ v9.4.2):
"monitor_data_frame_transforms",
...
"manage_data_frame_transforms",
这两个是集群权限名,不是角色名,9.4.2 里依然存在。
所以:你自定义的角色里如果用了这两个权限名,不受影响。 受影响的只有直接引用了那两个内置角色的地方。
把这个写出来是因为它很容易搞混——看到 data_frame_transforms 就以为全没了。分层看清楚:角色层删了,权限层没动。
(说明:这两个权限名是否也在弃用计划里,未查证。只确认了 9.4.2 里它们还在。)
如果没在升级前处理,事后怎么补救
前面建议升级前排查,但如果已经升完了才发现,也不用慌——这条改动是可逆的,不会有数据损失。
补救顺序:
第一步,确认影响范围。 把所有红色的 Transform 列出来,看有多少个受影响:
curl -s 'localhost:9200/_transform/_health?pretty' | grep -B10 '"red"'
第二步,逐个更新权限。 对每个受影响的 Transform 调一次更新,把权限换成新的 transform_admin / transform_user。
第三步,重新启动。 更新完之后手动启动,确认能跑起来、健康状态转绿。
关于"停了这段时间会不会丢数据":Transform 是按时间点做汇总的,停着的时候只是没有新的汇总产生,已有的目标索引内容还在。启动之后会接着之前的进度继续(具体是否自动补齐取决于 Transform 的配置和版本,这一点未查证)。
所以这是"一段时间内 Transform 没跑",不是数据事故。 影响是目标索引的数据滞后,不是损坏。
把这段写出来,是因为遇到问题时的第一反应往往是慌,而慌乱容易导致误操作(比如删掉重建)。实际上这条路很清晰:改权限、重启、补数据(如果需要补的话)。
这条属于"升级前该扫一遍"的类型
按分类改动的方式,这条的位置很清楚:
| 维度 | 判断 |
|---|---|
| 失效方式 | 明确报错(起不来 + 健康检查红) |
| 排查成本 | 低(红状态直接指向问题) |
| 修复成本 | 低(更新 Transform 权限) |
| 是否阻塞升级 | 是(Transform 不会自动跑起来) |
最后一条是关键:它是"升级前就得处理"的类型,不是"升级后慢慢观察"的类型。因为 Transform 不会自己恢复——你不改,它就一直红着、一直不跑。
所以建议在升级前就把排查做掉。 前面那两条 grep 命令,跑一遍五分钟,能避免升级当天面对一堆红色 Transform。
为什么这类清理总要大版本才做
顺着"7.x 弃用、9.0 才删"再想一层。
原因是数据比代码活得久。 Watcher 的 types 字段(Watcher 的 types 字段)里说过同一件事:
- 代码里的引用随时能改;
- 但已经存进系统的数据(Transform 配置、watch 定义)不会自己更新;
- 所以要等所有用户都有机会迁移完,才能安全地删。
大版本是 ES 唯一允许"不兼容"的时机。所以这类清理会攒着,到 9.0 一起做。
这个规律有实用价值:看到某个东西在 7.x 标了弃用,基本可以预期它会在 9.0(或下一个大版本)被删。所以排查清单可以从 8.x 的弃用警告里提前生成——升级前把 deprecation 日志过一遍,比事后查 changelog 高效。
和别的大版本清理放一起看
9.0 清理了不少 7.x 就弃用的东西,前面写过几篇:
| 篇 | 清理什么 | 失效方式 |
|---|---|---|
| 冻结索引移除 | 冻结索引相关 | 升级前必须解冻 |
| Watcher 的 types 字段 | Watcher 的 types 字段 |
空数组直接报错 |
| 本篇 | data_frame_transforms_* 角色 |
Transform 起不来 |
| discovery-ec2 换 SDK v2 | ec2 的部分配置 | 静默失效 |
前三条都是明确报错,最后一条是静默。这个区分比"改了什么"更重要——它决定了你该在升级前排查,还是升级后观察。
在 9.4.2 上跑一遍
两个旧角色是否真的没了,用角色查询接口逐个问一遍就知道。

图 4:9.4.2 安全实例的实测输出。data_frame_transforms_admin / data_frame_transforms_user 都返回 404;transform_admin / transform_user 返回 200 并带 manage_transform / monitor_transform 权限;内置角色列表里只剩 `transform_`。*
for r in data_frame_transforms_admin data_frame_transforms_user; do printf '%s -> ' "$r"; \
curl -sk -u elastic:elasticpw -o /dev/null -w '%{http_code}' "https://localhost:9900/_security/role/$r"; echo; done
# data_frame_transforms_admin -> 404
# data_frame_transforms_user -> 404
curl -sk -u elastic:elasticpw 'https://localhost:9900/_security/role/transform_admin' | jq -c '.transform_admin.cluster'
# ["manage_transform"]
curl -sk -u elastic:elasticpw 'https://localhost:9900/_security/role/transform_user' | jq -c '.transform_user.cluster'
# ["monitor_transform"]
curl -sk -u elastic:elasticpw 'https://localhost:9900/_security/role' | jq -c 'keys | map(select(startswith("transform_") or startswith("data_frame")))'
# ["transform_admin","transform_user"]
图 4 把「9.0 移除」坐实:两个旧名字查不到,替代角色都在且权限名清楚。正文给的排查命令(按角色名查)在本机跑通了。
边界:
- 图 4 出自 9.4.2 单节点安全实例,只查了内置角色,没有建 Transform 验证「用旧角色会起不来、健康检查变红」;
_update的具体请求体未给出(未实测,避免误导);monitor_data_frame_transforms/manage_data_frame_transforms两个权限名是否在弃用计划里未查证。
写在最后
这条 breaking 的技术内容很简单:两个角色改名,改法唯一。我的建议是在 9.0 之前就把旧名字换掉,别等到报错。
一,data_frame_transforms_admin → transform_admin,data_frame_transforms_user → transform_user。 7.x 弃用,9.0 删除。
二,失效方式是明确的:Transform 起不来、停在 stopped、健康检查报红显示权限错误。不像那些静默失效的改动,这条会主动告诉你。
三,要改的是 Transform 上的权限,不只是角色定义。 官方说的是"replace the permissions on the Transform",得调 _update。
四,升级前花五分钟 grep 一遍旧名字,比升级后面对一堆红 Transform 划算。
另外诚实标注两处:_update 的具体请求体未给出(未实测,避免误导);monitor_data_frame_transforms / manage_data_frame_transforms 这两个权限名是否在弃用计划里未查证,只确认 9.4.2 里仍在。
参考
- changelog 9.0.0:Remove
data_frame_transformsroles(第 637–648 行)@ v9.4.2 - breaking-changes.md:同一条目(第 346 行)@ v9.4.2
ClusterPrivilegeResolver.java:权限名仍在(第 251、271 行)@ v9.4.2- PR 117519
本文对照 Elasticsearch
v9.4.2标签的 changelog 与源码核对,引文与代码逐字取自原文。「在 9.4.2 上跑一遍」里已实际查询内置角色:两个data_frame_transforms_*角色均 404,transform_admin/transform_user均在且分别带manage_transform/monitor_transform,角色列表里只剩transform_*。_updateAPI 的具体调用形式未给出(未实测);两个data_frame_transforms集群权限名是否在弃用计划中未查证;用旧角色建 Transform 导致健康检查变红的场景未实测。