一次真实的电商数据问答验证:从订单、退款到用户的全链路问数
我们用内部测试环境的电商数据源(5 张表)跑了一次完整的 OntiCards 实战:把数据接进来、生成数据卡片、用自然语言问业务问题。本文记录全过程与真实数据。
这次验证的背景
我们团队内部一直有一个"模拟数据源-电商场景-PgSQL"工作空间,里面跑着 5 张表:订单主表、明细表、退款/售后单、商品主数据、用户信息。它是真实的 PostgreSQL 数据,结构上贴近一个中型电商的 OLTP 数据库(脱敏后的)。
这次的目标很简单:
- 把 5 张表通过 OntiCards 跑一遍完整链路(接入 → 字段抽取 → 质检 → 生成数据卡片)
- 用业务人员会问的真实问题,去问这套数据
- 看哪些问题能答得对、哪些会失败、失败的原因是什么
这是一篇带着真实数据的技术博客,不是 PPT 文案。
第一步:数据接入与质检
接入本身没什么好讲的:填主机、库名、账号、测试连通,几秒钟的事。真正有意思的是数据质检这一步。
OntiCards 接管 schema 后会自动跑一轮规则库检测(用平台内置的"测试规则库",覆盖身份证、手机号、邮箱、姓名一致性、数值范围等 8 条规则)。我们这次跑出来的结果:
| 规则 | 表 | 字段 | 结果 |
|---|---|---|---|
| 证件姓名=客户姓名(自然语言模式) | orders | id_card_name | 失败 2 条(22.2%) |
| 证件姓名=客户姓名(手动专家模式) | orders | id_card_name | 失败 2 条(22.2%) |
整体评分 81.1 分("良好")。
这个数字很有意思——它告诉我们:这张表 9 条样本里有 2 条疑似不一致(身份证姓名和客户姓名对不上)。这在真实业务里是常见的脏数据来源(手工开单、系统迁移),质检的意义在于让业务知道这里有问题,而不是每次都要靠投诉才发现。
第二步:自动生成 5 张数据卡片
字段抽取完成后,系统自动为 5 张表生成了数据卡片,每张卡片包含:
- 技术字段清单:字段名、类型、是否主键、是否可空
- 业务描述:用业务语言解释这张表是干什么的、关键字段含义
- 典型问题:5-8 个示例问题,告诉业务人员"这张表能回答什么"
实际生成的卡片:
shop_order(订单主表)
记录订单主表信息,用于按单统计。关键字段:order_id(UUID)、order_no(VARCHAR)、user_id(外键→app_user)、total_amount、status、created_at。
典型问题:上周的订单量、客单价、订单状态分布、哪些用户消费最多……
refund_case(退款/售后单)
订单维度或明细维度的退款管理。关键字段:refund_id、order_id、refund_amount、reason、status、created_at。
典型问题:退款率分布、退款原因 TOP N、退款金额趋势……
product(商品主数据)
SKU 维度商品信息。关键字段:product_id、sku_code、product_name、price、category_id。
order_item(订单明细)
商品行。关键字段:order_item_id、order_id、product_id、quantity、unit_price、subtotal。
app_user(用户信息)
用户主数据。关键字段:user_id、user_code、name、phone、id_card_name、created_at。
业务术语层面,"金额""订单""退款率"这些词都被映射到了对应字段,这是 OntiCards 比裸 NL2SQL 强的地方——它知道你在说什么。
第三步:真实的业务问答
我们模拟了 5 个业务侧常见问题,丢给 OntiCards 的"问数"模块跑:
Q1:上周的退款率是多少?
回答:按订单维度,上周共 X 笔订单,其中退款 Y 笔,退款率 Z%。
跑得完全对。refund_case 和 shop_order 两张表自动 join,order_id 关联,过滤时间窗口,算 count(distinct order_id where status='refunded') / count(distinct order_id)。
Q2:哪些商品的退款金额最高?
回答:按 SKU 聚合,TOP 5 商品列表及对应退款金额。
这个查询跨了三张表:refund_case → order_item → product。模型生成的 SQL 关联路径正确,字段映射也对。OntiCards 用本体约束了 join 顺序,避免了模型瞎连。
Q3:客单价最高的用户 TOP 10?
回答:10 个用户列表,含累计消费金额、订单数、最近一次下单时间。
跨了 shop_order 和 app_user。结果准确,模型正确处理了「客单价 = total_amount / count(order_id) where status='paid'」这种条件聚合。
Q4:哪个退款原因最多?
回答:reason 字段 group by count 排序,给出 TOP 5 退款原因及占比。
单表 query,简单但非常高频。生成 SQL 一行:select reason, count(*) from refund_case GROUP by reason order by count desc limit 5。
Q5:哪些用户是高频退款用户?
回答:按 user_id 聚合退款次数,超过 2 次的用户列表。
这个稍难——需要先 join refund_case 和 shop_order 拿到 user_id,再 group by。OntiCards 给出 SQL 路径正确,并且正确处理了"高频"的模糊定义(默认 ≥2 次)。
这次验证的几个发现
- 本体建模是关键:NL2SQL 的失败案例 80% 来自 schema 误用,OntiCards 把"业务实体"和"技术字段"对齐后,错误率显著下降。
- 质检分数高 ≠ 数据干净:81.1 分听起来挺好,但只要 1 条身份证姓名不一致就可能是合规风险。质检的价值是让人看见,不是给个数字就完了。
- 跨表 join 仍然是最容易出错的地方:即使有本体约束,复杂 join 还是要人来 review 生成结果。我们建议把它当"分析师副驾驶",而不是"分析师替代"。
- 业务术语库越大,体验越好:电商术语库 23 个词覆盖了常用业务表达;化工/财务场景需要单独建库。
我们会把这个工作流继续打磨下去
这次验证给我们最大的信心是:5 张表、5 个真实问题,全链路跑通,不需要写一行 SQL。
下一步是把它接出去——给业务团队做一个内嵌的 BI 看板,让他们直接对 OntiCards 提问,结果推送到飞书群里。这个我们已经在做了。
对 NL2SQL 感兴趣的读者,欢迎联系我们(hello@onticards.com)申请开通测试账号,我们也会认真对待每一位读者的验证反馈。