Operator 完整参考

Operator 是 predsgroupby 中的单列计算单元。每个 Operator 产生一个输出列,输出的类型和语义元数据会写入结果 Schema。

通用输入规则

单输入

{ "operator": "$sum", "pred": "销售额", "name": "销售额" }

pred 可以是 Property 引用,也可以是另一个 PredItem。

多输入

{
  "operator": "$divide",
  "components": [
    { "operator": "$sum", "pred": "销售额" },
    { "operator": "$countDistinct", "pred": "订单号" }
  ],
  "name": "客单价"
}

多输入统一使用 componentsargs 只保存配置,旧式 args.inputs 不支持。一个 PredItem 不能同时有 predcomponents

内置 Operator 总表

核心 Registry 内置 26 个 Operator,内置 hierarchy 插件再提供 1 个:

类别Operator
聚合$sum$count$countDistinct$avg$min$max
周期与累计$periodShift$periodGrowth$periodDifference$averagePerPeriod$periodBoundary$newly$accumulate
算术$add$subtract$multiply$divide$abs
比例$shareOfTotal
条件与字符串$case$concat$substring
日期和层级$dateBucket$hierarchyLevel
窗口$rank$rowNumber
受信任表达式$sql

聚合 Operator

$sum

pred 求和。

{ "operator": "$sum", "pred": "销售额", "name": "销售额合计" }
  • 输入:一个数值 Property 或数值表达式。
  • 输出:保留输入的 Semantic Type/Primal Type,isArray: false
  • SQL 语义:SUM(input)

$count

计算行数或非空输入数。

{ "operator": "$count", "name": "行数" }
{ "operator": "$count", "pred": "订单号", "name": "非空订单数" }
  • pred 可省略;省略时统计行数。
  • pred 时统计非空输入,不隐式去重。
  • 输出:int / number

$countDistinct

唯一值计数。

{ "operator": "$countDistinct", "pred": "订单号", "name": "订单数" }
  • 输入:一个 Property 或表达式。
  • 输出:int / number
  • SQL 语义:COUNT(DISTINCT input)
  • 旧名称 $uniq 不注册;需要去重时不能使用 $count 替代。

$avg

{ "operator": "$avg", "pred": "客单价", "name": "平均客单价" }
  • 输入:一个数值 Property 或表达式。
  • 输出:保留输入语义类型,isArray: false
  • SQL 语义:AVG(input)

$min / $max

{ "operator": "$max", "pred": "销售额", "name": "最大销售额" }
  • 输入:可比较的单值表达式。
  • 输出:保留输入语义类型。
  • 对配置了 comparable 的 category,按 valuesdirection 定义的业务顺序计算,不按字符串字典序。

指标局部 Query

上述聚合 Operator 可以声明自己的 query

{
  "operator": "$sum",
  "pred": "销售额",
  "query": { "渠道": "线上" },
  "name": "线上销售额"
}

它只过滤该指标的输入,不过滤同一 LogicForm 中的其他指标。非聚合 Operator 不接受 pred.query

周期与累计 Operator

这些 Operator 通常需要嵌套指标作为 pred,并要求 LogicForm Query 中有明确日期条件。

$periodShift

返回目标历史/未来周期的指标值。

{
  "operator": "$periodShift",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "time": { "granularity": "year", "offset": -1 } },
  "name": "去年销售额"
}

args.time 支持两种形状:

{ granularity: 'second' | 'minute' | 'hour' | 'day' | 'week' | 'month' | 'quarter' | 'year'; offset: number }
{ year: number; quarter?: number; month?: number; week?: number; day?: number; hour?: number; minute?: number; second?: number }

规则:

  • 相对 offset 必须是整数,且对象只能包含 granularityoffset
  • 绝对时间必须包含 yearquartermonthweek 不能混用;day 必须和 month 一起使用。
  • Query 中必须有且只有一个被实际平移的日期 Property 条件。
  • pred 必须是嵌套指标,不能直接写 Property 字符串。
  • 日期分组键会被对齐回原查询周期,以便与本期结果合并。
  • 输出保留嵌套指标的类型。

$periodGrowth

计算本期相对于目标周期的增长率:

本期 / ABS(目标周期) - 1
{
  "operator": "$periodGrowth",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "time": { "granularity": "month", "offset": -1 } },
  "name": "销售额环比"
}
  • args.time$periodShift 相同。
  • 目标周期为 0 时结果为 null,避免除零。
  • 输出:percentage / number

$periodDifference

计算:

本期 - 目标周期
{
  "operator": "$periodDifference",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "time": { "granularity": "year", "offset": -1 } },
  "name": "销售额同比增量"
}

输出保留嵌套指标类型。

$averagePerPeriod

计算嵌套指标除以有数据的不同周期数:

{
  "operator": "$averagePerPeriod",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "granularity": "day" },
  "name": "日均销售额"
}
  • args.granularitydayweekmonthquarteryear
  • Schema 必须有唯一 timestamp Property。
  • 周期数按该 timestamp 分桶后的 distinct 数量计算。
  • 输出保留嵌套指标类型。

$periodBoundary

在查询时间范围的起点或终点之前找到最新实际数据日期,并在该日期计算指标。

{
  "operator": "$periodBoundary",
  "pred": { "operator": "$sum", "pred": "库存" },
  "args": { "boundary": "end" },
  "name": "期末库存"
}
  • args.boundary 必须为 startend
  • Query 必须能解析出相应 timestamp 边界。
  • pred 必须是嵌套指标。
  • 输出保留嵌套指标类型,并记录周期边界元数据。

$newly

计算结束边界累计值减去开始边界累计值:

结束边界值 - 开始边界值
{
  "operator": "$newly",
  "pred": { "operator": "$sum", "pred": "客户数" },
  "name": "新增客户数"
}
  • Query 必须同时提供 timestamp 起点和终点。
  • 当前不能按同一个 timestamp Property 分组。
  • 开始边界无值时按 0 处理。
  • 输出保留嵌套指标类型。

$accumulate

按窗口顺序计算累计值。

业务周期写法:

{
  "operator": "$accumulate",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "period": "year" },
  "name": "年累销售额"
}
  • periodyearquartermonthweek
  • Query 必须恰好引用一个 date Property,并限定目标期间。
  • 同一 LogicForm 中所有带 period$accumulate 必须使用相同 period。
  • 存在业务分组时,各分组独立累计。
  • period 写法不能同时提供 partitionByorderBy

高级窗口写法:

{
  "operator": "$accumulate",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": {
    "partitionBy": ["门店"],
    "orderBy": [{ "pred": "月份", "direction": "asc" }]
  },
  "name": "累计销售额"
}

显式 partitionByorderBy 必须完整且无重复地覆盖当前 grouped LogicForm 的分组键。不能嵌套窗口/累计表达式,也不能包含 component Operator。

算术 Operator

$add

  • 输入:components 至少 2 项,无上限。
  • 公式:依次相加。
  • 输出:优先保留第一个 component 类型,否则为 number

$subtract

  • 输入:components 恰好 2 项。
  • 公式:components[0] - components[1]
  • 输出:优先保留第一个 component 类型。

$multiply

  • 输入:components 至少 2 项,无上限。
  • 公式:依次相乘。
  • 输出:number / number

$divide

  • 输入:components 恰好 2 项。
  • 公式:components[0] / components[1]
  • 分母为 0 时返回 null
  • 输出:number / number

$abs

  • 输入:单个 pred
  • 公式:绝对值。
  • 输出:保留输入类型,isArray: false

总体占比 $shareOfTotal

{
  "operator": "$shareOfTotal",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "dimension": "门店" },
  "name": "门店销售占比"
}
  • pred 必须是嵌套指标。
  • args.dimension 可为一个 groupby 的 pred 或输出名。
  • 省略 dimension 时移除最后一个 groupby 维度计算分母。
  • 分母为 0 时返回 null
  • 输出:percentage / number

条件与字符串 Operator

$case

显式条件分类:

{
  "operator": "$case",
  "pred": "销售额",
  "args": {
    "cases": [
      { "when": { "$gte": 100 }, "then": "高" },
      { "when": { "$gte": 50 }, "then": "中" }
    ],
    "default": "低"
  },
  "name": "销售等级"
}
  • cases 必须是非空数组,每项必须包含 whenthen
  • when 使用字段 Query 条件语法。
  • 分支按声明顺序匹配。
  • default 可省略,无分支命中时返回 null
  • 输出元数据:category / string

自动等宽分桶:

{
  "operator": "$case",
  "pred": "销售额",
  "args": { "mode": "auto", "buckets": 5 },
  "name": "销售额分桶"
}
  • buckets 必须为 2 到 100 的整数。
  • 自动模式不能定义 cases
  • 可同时提供有限数值 minmax,但不能只提供一个。
  • 省略边界时按当前结果范围计算;所有值相等时输出桶 0。
  • 作为 groupby 使用时必须显式提供 minmax

$concat

{
  "operator": "$concat",
  "components": [{ "pred": "省" }, { "pred": "市" }],
  "name": "地区"
}
  • 输入:components 至少 1 项。
  • 按声明顺序连接。
  • 输出:string / string

$substring

{
  "operator": "$substring",
  "pred": "商品编码",
  "args": { "start": 0, "length": 3 },
  "name": "商品前缀"
}
  • start 是从 0 开始的非负整数。
  • length 是正整数。
  • 输出:string / string

日期与层级 Operator

$dateBucket

{
  "operator": "$dateBucket",
  "pred": "日期",
  "args": { "granularity": "quarter" },
  "name": "季度"
}
  • 输入必须是 primal_type: 'date'
  • granularityhourdayweekmonthquarteryear
  • 输出:date / date,并记录所选 granularity。
  • 可作为 groupby 键。

$hierarchyLevel

{
  "operator": "$hierarchyLevel",
  "pred": "地区",
  "args": { "level": "省市" },
  "name": "省市"
}
  • 由内置 hierarchy 插件注册。
  • args 只能包含一个非空 level,可用正式 level 名称或 synonym。
  • pred 必须是配置层级编码的 Property,或指向层级 Schema 的 scalar object 关系。
  • 不支持 array object 关系。
  • 输出:string / string
  • 可作为 groupby 键。

窗口 Operator

$rank

{
  "operator": "$rank",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": {
    "partitionBy": ["月份"],
    "direction": "desc"
  },
  "name": "销售排名"
}
  • partitionBy 只能引用当前 LogicForm 已声明的 groupby pred 或输出名。
  • directionascdesc,默认 desc
  • 相同值获得相同名次,后续名次可能跳号。
  • 输出:int / number

$rowNumber

$rank 使用相同的 partitionBydirection 契约,但每一行获得连续且唯一的序号,不处理并列。

{
  "operator": "$rowNumber",
  "pred": { "operator": "$sum", "pred": "销售额" },
  "args": { "direction": "desc" },
  "name": "行号"
}

输出:int / number

受信任表达式 $sql

{
  "operator": "$sql",
  "args": {
    "sql": "COALESCE(?, ?)",
    "parameters": [10, 20],
    "type": "number",
    "primal_type": "number",
    "isArray": false
  },
  "name": "计算值"
}

契约:

  • 不接受 predcomponents;表达式只能放在 args.sql
  • 动态值必须使用 ? 占位符并按顺序放入 args.parameters
  • 必须提供非空 args.type 和合法 args.primal_type
  • args.primal_typestringnumberbooleandateobject
  • args.isArray 可选,必须为 boolean。
  • object 输出可用 args.ref 声明目标 Schema。
  • SQL 可能依赖当前数据库方言。
  • 系统会校验占位符数量、引号、注释和分号,但不会替调用方净化 SQL。
  • 不得把终端用户输入拼入 args.sql;用户值只能通过 parameters 绑定。

自动名称

省略 name 时,内置 Operator 会按 ExecuteOptions.locale 生成名称,默认 zh-CN,也支持英文 locale。显式 name 始终原样保留。对外稳定依赖结果列时,建议始终显式填写 name

Groupby 可用性

可用于 groupby 的内置计算为能够直接生成标量数据库表达式的 Operator,例如 $dateBucket$hierarchyLevel$case$concat$substring 和标量算术。聚合、窗口、周期 component、$shareOfTotal$newly$accumulate 不能作为 groupby 键。