在Snowflake Streamlit中嵌入React:实现重跑做不到的交互
有效阅读仅保存在当前浏览器,用于「为你」推荐;暂停或清除记录。
DataHot 速览
作者介绍开源示例RiSiS(React in Streamlit in Snowflake),用st.html在SiS页面中嵌入一个React island组件,让Python与Snowflake继续掌管会话、查询、权限与部署,同时补上重跑机制无法实现的交互:全图hover预览、拖拽过程中实时变化的KPI、联动图表。示例采用Apache-2.0协议,可在用户自有账户内运行,文中还讨论了这一方案的成本与一个待解问题。
原收录理由(待核验):对用Streamlit in Snowflake做数据应用的团队,这是可直接复用的交互增强实践,涉及架构边界(前端交互与Python重跑的分工)与成本权衡,有明确的技术细节。
本文目录 11 节
译文
AI 逐段翻译保留 Snowflake 中 Streamlit 的简洁性,并将重跑无法完成的交互移到前端
设想一次收入评审。一位分析师打开管道仪表板,指向区域条形图上的 EMEA。出现一个工具提示。其他图表和 KPI 不变。
她想要更多。她希望在她指向时,每张图表和每个 KPI 都显示 EMEA 的数字。然后她想在趋势线上拖过两个季度,并在拖动过程中观察预订量和承诺份额的变化。这就是她找到承诺份额下降的那个季度的方法。没有这些交互,她必须点击、等待重跑、读取结果,然后再点击,对每一次猜测都如此。
我构建许多 Snowflake 中的 Streamlit(SiS)应用。我使用 SiS 是因为 这是我所知的最简单的方式,可以向人们展示数据,更不用说你可以用一个 单条提示 就让应用启动并运行。 我不想把我的应用移出 SiS。我希望 SiS 支持这些交互。我把结果称为 RiSiS(SiS 中的 React)。本文展示 RiSiS 如何工作、它的成本,以及一个开放问题。
简而言之: react-in-streamlit-in-snowflake 是一个开放示例。它通过 st.html 向 SiS 页面添加一个 React 岛。岛是位于 Streamlit 页面上某一位置的一个 React 组件。Python 和 SiS 继续控制会话、查询、权限和部署。该岛添加了重跑无法完成的三种交互:
- 跨所有图表的悬停预览
- 在拖动过程中变化的 KPI
- 一起变化的联动图表
该示例在 Apache-2.0 下免费,并在你自己的账户中运行。
为什么我使用 SiS
Streamlit 的上手门槛很低。一张图只需三行 Python。SiS 增加了我原本要自己构建的部分:
- 数据只用一种语言。 Snowpark、pandas 和查询都留在 Python 中。
- 无需托管工作。 Snowflake 运行应用。用户使用通常的登录方式在 Snowsight 中打开应用。
- 已知权限。 应用以其所有者权限(安全概览)查询。角色控制应用可以看到什么。
我合作的团队运行数百个这样的应用。为了更好的悬停效果而重写每个应用不是现实的计划。
重跑无法做到的事
默认情况下,当用户更改控件时,你的脚本会从头到尾重跑。这种模型让 Streamlit 简单。这也意味着页面无法响应 Python 接收不到的事件。
“一张图上的悬停能改变另一张图吗?” 不能跨不同元素。在单张图中,Altair、Plotly 和 ECharts 在浏览器中显示悬停和刷选效果。Altair 还可以在一个组合规范中关联视图。在不同的 Streamlit 元素之间,Python 是唯一的连接。选择是 Python 唯一接收到的图表事件(st.altair_chart)。
“页面能在拖动过程中变化吗?” 不能。当指针暂停或用户松开鼠标按钮时,Python 才会收到刷选选择。在一次测试中,我拖动了三秒,而 Streamlit 没有重跑。
这不是 Streamlit 的缺陷。这也不是 Python 对 React,因为 Streamlit 自己的前端就使用 React。区别在于工作在哪里运行。重跑是后端数据处理:查询、权限和结果。悬停或拖动是对浏览器已有数据的前端数据处理。开放问题是前端工作应该放在哪里。
先试试这些
你可能不需要这个示例。
- 片段只重跑脚本的一部分。 带键片段让回调只重跑你指定的片段。
- on_change="ignore"让控件在浏览器中改变而无需重跑(Streamlit 1.63)。
- 组件 v2在页面中内联添加你自己的 HTML、CSS 和 JavaScript,并将值发送回 Python。对于单个复杂控件,请从组件 v2 开始。
有一个限制适用。仓库运行时支持 Streamlit 最高到 1.52.2,且不支持组件 v2(限制)。因此,较新的功能需要容器运行时。该仓库使用 st.html 并设置 unsafe_allow_javascript=True,这在两种运行时上都有效。在容器运行时上,同样的模式可以使用组件 v2 挂载。
该岛做什么
演示仪表板 Instant BI 展示销售管道。数据是合成的。它来自每个 Snowflake 账户都有的 TPC-H 示例数据。查询在 SQL 中映射该数据。订单变成交易,订单优先级变成交易阶段,五个 TPC-H 区域映射到 AMER、EMEA 和 APAC。演示不使用任何客户数据。我植入了一个模式:在 2025-Q2,一半的 Commit 交易处于 Best case。该季度的承诺份额从约 20% 下降到约 10%,而样本数据中没有这样的下降。仪表板有四个 KPI、五张图和两个下钻表。一个 React 树绘制这些图表和 KPI。该树接收每一次指针移动:
- 悬停预览。 指向 EMEA。所有其他图表和所有 KPI 都显示 EMEA 的值,直到指针离开该条形。没有发生点击,也没有重跑。
- 拖动预览。 在时间序列上拖动。KPI 和细分在每一帧上变化。你通过观察数值就能找到有用的范围,而无需多次尝试。
- 联动图表。 点击任意图表上的条形。所有其他图表都应用该筛选。条形和数字以短动画移动到新值。如果你在操作系统中开启减少动态效果,它们会立即变化。
为实现这一点,浏览器每个会话接收一次交易立方体(49,000 行,约 1 MB 的 JSON)。浏览器筛选该立方体。因此,点击也能快速响应。 docs/measurements.md 有我对两个应用的测量。测量覆盖一个仪表板、一种数据规模。因此,速度是次要收益。交互才是主要目标。
该仓库还有一个 原生孪生。孪生版本是纯 Streamlit 中的同一份仪表板,带有 cache_data、一个 fragment 和原生选择控件。它给出相同的答案。如果孪生版本对你的用户来说已经足够,那就用孪生版本。
无需重写
你在 Streamlit 页面的一个位置上添加一个 island。页面的所有其他部分保持纯 Streamlit:控件、st.dataframe、布局和登录。从造成问题最多的图表开始。当页面满足你的需求时就停下来。
App Runtime 的适用场景。 对于具有完整 Web 技术栈的新应用,使用 Snowflake App Runtime。App Runtime 为你构建并托管应用。作为测试,我将这个 React UI 作为 Next.js 应用迁移到了 App Runtime。结果运行良好。代价是你需要自己编写服务器端:数据 API 路由、查询代码和输入校验。
RiSiS 适用于另一种情况。你已有 Streamlit 应用,想要更好的交互,但不想迁移。
请求如何到达 Python
Python 继续控制应用:
- load_bundle() 每个会话向页面添加一次代码。
- bridge_request() 读取隐藏输入。
- handle() 只运行你列出的动作。
- 慢速 SQL 通过 query_job() 执行。此函数用 collect_nowait() 启动查询。当浏览器轮询结果时,它返回 "pending"。
- render_island() 将所有结果作为 props 发送回 island。
谁可以看到什么
- 所有者权限。 setup.sql 创建一个只能看到示例数据的角色。应用以该角色身份查询。
- 桥接是一个 RPC 接口。 只有允许列表中的动作会运行。输入经过验证器。桥接绑定 SQL 值。它不会将值粘贴到 SQL 文本中。
- 错误留在服务器上。 浏览器收到一个参考编号。详细信息写入日志。
- 上传是显式的。 deploy.sh 只上传 deploy.manifest 中列出的文件。它会拒绝看起来像凭据的文件。
你会失去什么
island 位于 Streamlit 模型之外。因此,Streamlit 为你完成的一些任务变成了你自己的任务:
- 主题和一致性。 island 不使用你的 Streamlit 主题。它使用你编写的样式。
- 无障碍性。 你必须在 island 内部让键盘访问、焦点和屏幕阅读器标签正常工作。
- 读取页面的工具。 通过原生元素读取 Streamlit 应用的工具,在自定义 island 内部看到的内容要少得多。
- 更多代码。 UI 变更需要 Node 和打包工具。每个用户每个会话下载一次 790 KB 的包。部署不需要 Node,因为仓库包含了构建好的包。
- 对 sanitiser 的依赖(在 Streamlit 1.52 中(依赖管理))。仓库固定了 Streamlit 版本。一个测试会检查 sanitiser 规则。
如果 fragment 和一个好的图表库能满足你的需求,就使用它们。纯 Streamlit 需要更少的代码。
一个开放的问题
Streamlit 自己的前端使用 React。因此,这种模式不必一直是一种变通方案。Streamlit 中更多的前端处理可以在没有自定义 island 的情况下提供这些交互。一个社区提案请求 Streamlit 中的客户端状态和事件。在该提案中,悬停或拖拽会改变页面,Python 只在必要时运行。
我想知道你需要什么:
- 你的用户要求哪些交互?
- 你希望将它们作为 Streamlit 原生功能,还是作为添加自己前端的更简单方式?
Snowflake 的 Streamlit 团队乐于接受反馈! 在与他们合作审阅本文时,我深深感受到该团队的响应速度之快,以及他们对更多原生解决方案的深入探索。如果你想继续对话,请在这里的评论中 @Yavor Georgiev 或提及他。
试一试
快速方法。 将 sis-to-react-in-sis 技能复制到 Snowflake CoCo。然后让它转换你的应用。该技能先在本地测试应用。只有你告诉它部署时它才会部署。
手动方法。 克隆 该仓库。安装并配置 Snowflake CLI。然后运行这些命令:
# once, as ACCOUNTADMIN, after editing the settings at the top of the file
snow sql -c <connection> -f setup/setup.sql# the bundles are committed, so no Node is needed to deploy
bash starter/deploy.sh app REACT_SIS_DEMO.APPS.INSTANT_BI --warehouse COMPUTE_WH \
-r REACT_SIS_DEMO -c <connection> --title "Instant BI"
bash starter/deploy.sh native_twin REACT_SIS_DEMO.APPS.INSTANT_BI_NATIVE --warehouse COMPUTE_WH \
-r REACT_SIS_DEMO -c <connection> --title "Instant BI (native)"打开 Snowsight。转到 Projects,然后 Streamlit。在每个应用中悬停、拖拽和点击。要使用容器运行时,添加 --container --pool <POOL>。setup/uninstall.sql 会删除所有对象。
此仓库是一个示例,按原样在 Apache-2.0 下提供。在依赖它之前请审阅。
Streamlit 的地板,React 的天花板,在 Snowflake 之内 最初发布于 Snowflake Builders Blog: Data Engineers, App Developers, AI, & Data Science(Medium),人们在那里通过高亮和回应这个故事继续对话。
这篇内容对你有用吗?
反馈只用于改善内容筛选,不等同于收藏