Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义

作者:接口漫谈

时间:2026-11-02

浏览:389

本指南详解 Cube.js Data Schema 的核心构建方法,涵盖 Cube 实体声明、基础 SQL 表绑定、Dimensions 维度与主键设置,以及各类 Measures 指标聚合定义与验证。

文章目录
Cube.js 建模教程 语义层开发 阅读时长约 8 分钟
在 Cube.js(现统称为 Cube)语义层架构中,Data Schema 负责将底层数据库的关系型表结构转换为面向分析的语义模型。本文将系统讲解如何编写 Cube.js Data Schema,重点拆解核心建模单元 Cube 的结构声明、基于业务属性的 Dimensions(维度)定义,以及用于统计汇总的 Measures(度量)编写规则与常见应用场景。
Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义
图 1:Cube.js Data Schema 核心三大建模要素结构概览

一、Cube.js Data Schema 的定位与核心组成

传统直接面向数据库写 SQL 进行多维分析的方式存在诸多痛点:复杂的 JOIN 逻辑随处复制、聚合口径在各个看板与下游报表中标准不一、业务变动时维护成本高昂。Cube.js 作为一个开源的数据语义层(Semantic Layer),位于底层分析型数据库与上层消费端(前端仪表盘、BI 工具、下游 API)之间。

Data Schema 是 Cube.js 运作的大脑。开发者在 Schema 中将分散的物理数据表抽象为逻辑模型。在 Data Schema 中,核心概念划分为三个层次:

  • Cubes(立方体/实体):多维分析的基本逻辑单元,通常对应数据库中的一张物理表、一个视图,或者一段经过清理的 SQL 子查询。它作为容器包裹所属的维度与度量。
  • Dimensions(维度):描述事物的属性与特征,用于在分析时进行过滤(WHERE)、切片分组(GROUP BY)与排序(ORDER BY)。例如用户 ID、订单状态、创建时间、所属省份等。
  • Measures(度量):基于数值的统计计算结果,对应 SQL 中的聚合函数(如 COUNT、SUM、AVG、MIN、MAX)或在此基础上的比率计算。例如总订单数、GMV、平均客单价等。
Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义
图 2:Cube.js 语义层整体架构与 Data Schema 的枢纽地位

二、声明数据实体:Cube 的基本结构与数据源绑定

Cube.js 支持使用 JavaScript 或 YAML 编写 Data Schema 文件,官方推荐在项目根目录下的 schema/ 文件夹中以 .js 文件组织。一个典型的文件如 schema/Orders.js,使用全局函数 cube() 进行声明。

1. 绑定方式:sql_table 与 sql

每个 Cube 必须明确其底层的数据来源,主要有两种配置属性:

  • sql_table:直接映射物理表。当表结构整洁、无需在语义层前置过滤时优先使用。需要指定数据库 schema 前缀(如 public.orders)。
  • sql:使用自定义 SQL 查询作为 Cube 的数据源。适用于需要在进入 Cube 之前进行列裁剪、联表打宽或硬过滤历史废弃数据的场景。
// 方式 A:直接绑定物理表(推荐)
cube('Orders', {
  sql_table: 'public.orders',
  
  // 维度与度量声明...
});

// 方式 B:使用子查询清洗数据
cube('ActiveUsers', {
  sql: `SELECT id, name, created_at, status 
        FROM public.users 
        WHERE is_deleted = false`,
        
  // 维度与度量声明...
});
提示:在同一个 Cube 的 SQL 表达式中,可以使用 ${CUBE} 关键字指代当前 Cube 在生成 SQL 时被分配的表别名。例如 ${CUBE}.amount,这样能有效避免表别名冲突。

三、定义 Dimensions(维度):属性、主键与时间切片

Dimensions 对应的是业务中“按什么分类查看”或“按什么条件筛选”。在 SQL 查询生成阶段,所有请求中包含的维度都会被 Cube.js 自动编译进入 GROUP BY 子句。

Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义
图 3:Cube Data Schema 代码结构与组件语法解剖图

1. 核心属性与主键声明

在声明维度时,最重要的规则之一是必须为每个 Cube 指定主键。在对应维度的配置中设置 primaryKey: true。

Cube.js 依赖主键来精确执行行数统计(COUNT)、防止在多表 JOIN 时产生笛卡尔积或扇形计算(Fan-out),以及为预聚合提供唯一的哈希依据。

dimensions: {
  id: {
    sql: 'id',
    type: 'number',
    primaryKey: true
  },
  
  status: {
    sql: 'status',
    type: 'string'
  },

  // 计算型布尔维度
  isCompleted: {
    sql: `${CUBE}.status = 'completed'`,
    type: 'boolean'
  }
}

2. 时间维度与自动粒度切片

时间维度是多维分析中最重要的维度类型。当把维度的 type 设置为 time 时,Cube.js 的查询接口会自动支持时间粒度(Granularity)转换,客户端无需在前端写 DATE_TRUNC,只需在查询传参中指定 granularity: 'day' | 'month' | 'year' 即可。

createdAt: {
  sql: 'created_at',
  type: 'time'
}

四、定义 Measures(度量):聚合统计与业务计算

Measures 对应的是“统计出来的数值”。只要在客户端查询请求中包含了 Measure,Cube.js 就会生成对应的 SQL 聚合函数。

1. 基础聚合类型

Cube.js 内置了完备的常用聚合类型:

  • count:计数。如果没有提供 sql,Cube 会默认使用主键计算 COUNT(id);若未定义主键则编译为 COUNT(*)。
  • countDistinct:去重计数。通过 sql 指定字段,编译为 COUNT(DISTINCT column)。
  • sum:求和。必须指定数值列的 sql。
  • avg:平均值。
  • min / max:极值统计。
measures: {
  count: {
    type: 'count'
  },

  totalAmount: {
    sql: 'amount',
    type: 'sum'
  },

  avgAmount: {
    sql: 'amount',
    type: 'avg'
  },

  payingUsersCount: {
    sql: 'user_id',
    type: 'countDistinct'
  }
}

2. 条件过滤度量(Filtered Measures)

在真实业务中,经常需要统计特定状态下的指标,例如“已支付订单总额”或“退款订单量”。Cube.js 提供了 filters 属性,它会在 SQL 中自动生成带 CASE WHEN 的条件聚合,而不需要写子查询。

completedAmount: {
  sql: 'amount',
  type: 'sum',
  filters: [
    { sql: `${CUBE}.status = 'completed'` }
  ]
}

3. 衍生计算度量(Calculated Measures)

像“客单价(总金额 / 订单数)”、“退款率”等复合指标,不能简单对单列求均值,而必须在聚合结果之间相除。Cube.js 允许将度量的类型设置为 number,并在 sql 中直接引用其它已经声明的度量:

averageOrderValue: {
  sql: `${totalAmount} / NULLIF(${count}, 0)`,
  type: 'number'
}
注意:在衍生度量中做除法时,务必使用 NULLIF(..., 0) 包装分母,避免在特定筛选维度下因分母为 0 导致数据库抛出 Division by zero 错误。

五、实操步骤:从原始表到可查询 Schema 的完整开发流程

编写 Cube.js Data Schema 应当遵循严格的递进顺序,从表结构梳理到本地开发沙箱验证,确保每个指标的口径符合预期。

Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义
图 4:Data Schema 编写与调试验证五步实战流程
  1. 步骤 1:检视物理表与业务目标

    连接数据库,检查目标表的字段类型、是否存在空值以及主键约束。与业务方明确指标口径,例如订单金额是否包含优惠券扣减。

  2. 步骤 2:新建 Schema 文件并绑定数据源

    在项目的 schema/ 目录下新建文件(如 Orders.js),使用 cube('Orders', { sql_table: 'orders' }) 构建基础框架。

  3. 步骤 3:定义 Dimensions 属性与唯一主键

    依次添加主键 id 并设置 primaryKey: true;加入分类维度(如 status)和时间戳维度(如 createdAt)。

  4. 步骤 4:定义 Measures 聚合度量

    添加基础聚合度量 count 和 totalAmount;根据业务需要加入 filters 条件度量与比率衍生度量。

  5. 步骤 5:在 Cube Developer Playground 中调试验证

    运行 npm run dev 启动 Cube 本地服务,访问 http://localhost:4000 进入 Playground 界面。勾选刚定义的维度与度量,观察生成并发送到数据库的真实 SQL,核对返回的数据行与指标数值。

六、Dimensions 与 Measures 决策对比与速查矩阵

初学者在建模时常产生困惑:“金额”到底该作为 Dimension 还是 Measure?“用户年龄”该怎么定义?

判断的核心依据在于业务使用意图:如果需要按其作为行标签分组拆解或作为区间筛选条件,它就是 Dimension;如果需要统计它的总数、平均数或分布总和,它就是 Measure。在某些场景下一个字段可以同时衍生为两者(例如:作为单价维度的 unitPrice 与作为平均单价度量的 avgUnitPrice)。

对比要素 Dimensions(维度) Measures(度量)
业务角色 定义切片视角,回答“按什么看” 输出汇总数值,回答“统计是多少”
SQL 编译目标 编译为 GROUP BY、WHERE、ORDER BY 编译为 SELECT 中的聚合函数(SUM、COUNT 等)
支持类型 string, number, time, boolean, geo count, countDistinct, sum, avg, min, max, number
核心配置项 primaryKey, shown, subQuery filters, rollingWindow, drillMembers
典型示例 用户城市、下单日期、商品品类、订单状态 总销售额、支付订单数、独立访客 UV、平均客单价
Cube.js Data Schema编写指南:Cubes、Dimensions与Measures定义
图 5:Dimensions 与 Measures 决策对比与编译联动矩阵

七、编写避坑指南与最佳实践

在实际生产环境中编写 Schema 时,以下几个关键注意事项能避免常见隐患:

  • 主键缺失引发的扇形重复统计(Fan-out):当两个 Cube 发生 joins 连接时,如果多对一或者一对多关系中没有正确声明 primaryKey: true,多表关联可能会导致度量求和被重复翻倍。Cube.js 依赖主键来在生成 SQL 时执行子查询或两阶段聚合消除重复。
  • 避免在维度中写聚合函数:Dimensions 的 sql 表达式中绝对不能包含 SUM() 或 COUNT() 等聚合函数。所有聚合计算必须且只能在 Measures 中声明。
  • 谨慎使用 countDistinct:在超大数据量(千万级以上)的列上执行 countDistinct 会对数据库造成较大的性能负担。若底层是 ClickHouse 或 Doris 等引擎,可结合底层引擎的 HyperLogLog 近似算法或在 Cube 中配置预聚合(Pre-aggregations)进行加速。
  • 命名一致性:字段名统一采用驼峰式命名(如 createdAt、totalAmount),保持业务字段名称在整个团队的数据字典中规范统一。

掌握了 Cubes、Dimensions 与 Measures 的定义规则后,即可为系统搭建起清晰、坚固的数据语义基石。后续无论是扩展表间 joins 关联、定义细粒度的行级权限(Data Security),还是配置预聚合加速(Pre-aggregations),都能在此模型架构上自然延展。

实用工具推荐

电子包浆

绿化、压缩、噪点和虚拟水印,自由调节做旧程度。

使用 ›
图片压缩

选择画质和输出格式,预览压缩前后的大小。

使用 ›
相关文章