对工业气体和焊接设备经销商来说,租赁分析并不只是几张收入报表。客户还会追踪气瓶或设备在哪里、租了多久、哪些资产已经逾期,以及不同网点的周转情况。Datacor 将 Amazon QuickSight 仪表板和自然语言查询嵌入 TrackAbout 平台,让业务用户不必离开日常系统,也能自行探索这些问题。
这个方案真正值得关注的地方,不只是“嵌入一个 BI 页面”,而是它把跨云数据管道、租户隔离、嵌入式身份和自然语言语义层连成了一条完整链路。
从业务页面到分析结果,中间需要四层能力
根据来源摘要,可以把整体方案理解为四个相互约束的层次:
- 自动化跨云数据管道:从业务系统抽取租赁、资产、客户和位置数据,转换后交给分析数据集。
- 统一分析模型:把设备、租赁合同、客户、网点、时间等实体整理成适合聚合和筛选的字段。
- QuickSight 嵌入层:在 TrackAbout 的页面中展示仪表板,并支持自然语言提问。
- 多租户访问控制:每一行数据都携带租户标识,查询结果只返回当前客户有权看到的数据。
可以将数据流简化为:
TrackAbout 业务数据
│
▼
自动抽取与增量同步
│
▼
清洗、关联并补充 tenant_id
│
▼
QuickSight 数据集与语义配置
│
▼
嵌入式仪表板 / 自然语言查询
这里最重要的数据契约是 tenant_id。无论数据经历多少次复制、合并或聚合,这个字段都不能丢失。例如,一张可供分析的租赁事实表可以采用如下结构:
CREATE TABLE rental_facts (
tenant_id VARCHAR(64) NOT NULL,
rental_id VARCHAR(64) NOT NULL,
asset_id VARCHAR(64) NOT NULL,
customer_id VARCHAR(64) NOT NULL,
branch_id VARCHAR(64),
rental_status VARCHAR(32) NOT NULL,
checked_out_at TIMESTAMP NOT NULL,
due_at TIMESTAMP,
returned_at TIMESTAMP,
daily_rate DECIMAL(12, 2),
PRIMARY KEY (tenant_id, rental_id)
);
把 tenant_id 纳入主键、增量游标和质量检查,可以降低跨租户数据被错误合并的风险。只有在展示层临时追加租户条件,通常并不够安全。
行级安全必须跟随用户会话
多租户分析最危险的错误,是前端隐藏了其他客户的数据,但后端查询仍然能够访问它们。可靠的做法是把租户身份从应用认证结果传到 QuickSight 会话,再由数据集的行级安全规则执行过滤。
下面给出一个可以改造的最小示例。它假设使用 QuickSight 匿名嵌入会话和基于会话标签的行级安全;这是一种参考实践,并不是对 Datacor 内部实现细节的复刻。
运行前需要:
- 在 QuickSight 中准备好仪表板,并允许嵌入。
- 为数据集配置标签式行级安全,使
tenant_id列映射到同名会话标签。 - 为运行服务的 IAM 身份授予
quicksight:GenerateEmbedUrlForAnonymousUser。 - 设置 AWS 凭证及下列环境变量。
python -m venv .venv
source .venv/bin/activate
pip install flask boto3
export AWS_REGION=us-east-1
export AWS_ACCOUNT_ID=123456789012
export QUICKSIGHT_NAMESPACE=default
export QUICKSIGHT_DASHBOARD_ID=your-dashboard-id
保存为 app.py:
import os
import boto3
from flask import Flask, jsonify, request
app = Flask(__name__)
AWS_REGION = os.environ["AWS_REGION"]
ACCOUNT_ID = os.environ["AWS_ACCOUNT_ID"]
NAMESPACE = os.getenv("QUICKSIGHT_NAMESPACE", "default")
DASHBOARD_ID = os.environ["QUICKSIGHT_DASHBOARD_ID"]
DASHBOARD_ARN = (
f"arn:aws:quicksight:{AWS_REGION}:{ACCOUNT_ID}:dashboard/{DASHBOARD_ID}"
)
quicksight = boto3.client("quicksight", region_name=AWS_REGION)
def tenant_from_authenticated_user():
# 演示代码通过请求头取值。生产环境必须从已验证的 JWT、
# 服务端会话或身份提供商声明中读取,不能信任浏览器直接提交的租户 ID。
tenant_id = request.headers.get("X-Tenant-ID", "").strip()
if not tenant_id:
raise ValueError("missing tenant identity")
return tenant_id
@app.get("/api/analytics/embed-url")
def create_embed_url():
try:
tenant_id = tenant_from_authenticated_user()
except ValueError as exc:
return jsonify({"error": str(exc)}), 401
response = quicksight.generate_embed_url_for_anonymous_user(
AwsAccountId=ACCOUNT_ID,
Namespace=NAMESPACE,
AuthorizedResourceArns=[DASHBOARD_ARN],
ExperienceConfiguration={
"Dashboard": {"InitialDashboardId": DASHBOARD_ID}
},
SessionLifetimeInMinutes=60,
SessionTags=[
{"Key": "tenant_id", "Value": tenant_id}
],
)
return jsonify({
"embedUrl": response["EmbedUrl"],
"expiresInMinutes": 60,
})
if __name__ == "__main__":
app.run(host="127.0.0.1", port=8080, debug=True)
启动并测试:
python app.py
curl -s \
-H 'X-Tenant-ID: distributor-42' \
http://127.0.0.1:8080/api/analytics/embed-url
生产环境中,X-Tenant-ID 这种客户端输入只能用于本地演示。正确流程应当是:服务端验证登录令牌,从可信声明中解析租户,确认用户有权访问指定仪表板,然后生成短期嵌入 URL。还应维护仪表板 ARN 白名单,避免客户端自由指定资源。
自然语言查询依赖的是语义质量
用户输入“哪些气瓶逾期超过 30 天”时,系统需要知道“气瓶”对应哪类资产、“逾期”如何计算,以及应该使用到期日还是租出日。如果底层只有 col_a、status_code 和含义不明的日期字段,自然语言入口并不会自动解决这些问题。
可以围绕租赁业务建立清晰的分析词汇:
asset_type:气瓶、焊机或其他租赁设备。rental_status:在租、已归还、逾期或维护中。days_out:从租出时间到归还时间或当前时间的天数。overdue_days:当前时间超过到期时间的天数。branch_name:经销商网点的业务名称,而不是内部编号。customer_name:客户可识别名称,同时避免暴露不必要的敏感字段。
适合验证语义层的问题包括:
过去 90 天各网点的平均租赁周期是多少?
哪些客户持有逾期超过 30 天的气瓶?
本月归还率比上月下降最多的网点有哪些?
按设备类型显示当前在租资产数量。
测试时不能只检查答案是否“看起来合理”。团队还要把自然语言结果与确定性的 SQL 或标准报表对账,并验证自然语言查询同样受到行级安全限制。否则,仪表板虽然隔离正确,问答入口却可能成为新的越权通道。
上线前把隔离、延迟和失败路径一起测掉
这类自助分析系统的价值,在于减少人工导数和定制报表,同时让客户在原有工作流中快速得到答案。但嵌入体验越顺滑,权限和数据质量问题也越不容易被用户察觉。
建议上线前完成以下检查:
- 租户隔离:用两个测试租户构造相似数据,确认双方无法看到彼此的明细、聚合值和自然语言答案。
- 身份可信度:租户标识必须来自服务端验证后的身份,而不是 URL 参数、表单字段或未经验证的请求头。
- 管道完整性:每次同步都检查缺失的
tenant_id、重复租赁记录、异常时间和孤立资产。 - 数据时效:在页面中明确显示最近更新时间,避免用户把延迟数据当作实时库存。
- 语义回归:保存一组典型业务问题及预期结果,在字段、计算逻辑或数据源变化后重新执行。
- 嵌入安全:限制允许嵌入的域名,缩短会话有效期,并记录嵌入 URL 的签发审计信息。
- 降级路径:数据管道或 QuickSight 不可用时,页面应显示明确状态,而不是空白图表或旧数据冒充最新结果。
Datacor 的案例说明,嵌入式分析不是给现有产品简单加一张仪表板。真正可持续的方案,需要自动化数据流提供稳定数据、语义层解释业务概念、应用身份驱动行级安全,再由 QuickSight 把这些能力放回用户熟悉的产品界面中。