metrics

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Metrics

指标

A metric is a measure of the semantic model, fully qualified:
crm_deals.amount
. The app's Metrics page lists every measure of the cubes built from data sources, and a metric's own page lets you count it over a scope (a segment, or a few conditions) and break it down by a dimension — the same three settings a dashboard card stores. This skill reads only; nothing here writes.
For ad-hoc analytical questions that aren't about one metric — several measures at once, custom grouping, top-N across cubes — the semantic-model skill is the better fit. Use this one when the user thinks in terms of a named metric, or wants the number a card shows.
**指标(metric)**是 semantic model 的一种度量,其完整限定名为:
crm_deals.amount
。应用的 Metrics 页面会列出由 data sources 构建的 cubes 中的每项 measure,而指标自己的页面可让你在一个 scope(一个 segment,或若干 conditions)内统计该指标,并按 dimension 拆分——这与 dashboard card 保存的三项设置完全相同。本 skill 仅执行读取操作;这里不会写入任何内容。
对于并非针对单个指标的临时分析问题——同时分析多个 measures、自定义分组、跨 cubes 做 top-N——semantic-model skill 更合适。当用户以命名指标的方式思考,或想获取 card 所显示的数值时,使用本 skill。

The catalogue

指标目录

json
api_read { "resource": "cubes", "method": "meta", "params": { "fields": "name,title,description,type", "pageSize": 100 } }
api_read { "resource": "cubes", "method": "meta", "params": { "filter": "name == \"crm_deals\"" } }
The app lists measures of source cubes only. Leave out:
  • type: "view"
    — a table's view (
    model_…
    ) re-exports measures under new names; each such measure's
    aliasMember
    points at the original;
  • generated cubes, marked
    meta.abConnectionId: "revos"
    — segment snapshots (
    segment_…
    ) and tables' own columns (
    model_stream_…
    ).
    meta
    can't be projected with
    fields
    ; it's on the full record you read for a candidate cube anyway.
Per measure, what the catalogue shows:
ColumnFrom
meta
Metric
title
(
description
as its tooltip),
name
as the ref
Cubethe cube's
title
Agg
aggType
:
count
,
countDistinct
,
sum
,
avg
,
min
,
max
,
number
, …
Format
format
currency
/
percent
, else by type: Number, Text, Boolean, Date
Only
type: "number"
measures can be counted on a card; say so if the user picks a text, boolean, or time one.
When the user asks for a metric by meaning ("win rate", "ARR"), search titles and descriptions. If nothing matches, say so and offer the closest, or adding one with the cubes skill — never approximate silently with a different measure.
json
api_read { "resource": "cubes", "method": "meta", "params": { "fields": "name,title,description,type", "pageSize": 100 } }
api_read { "resource": "cubes", "method": "meta", "params": { "filter": "name == \"crm_deals\"" } }
应用只列出 source cubes 的 measures。需要排除:
  • type: "view"
    ——某个 table 的 view(
    model_…
    )会以新名称重新导出 measures;每个此类 measure 的
    aliasMember
    都指向原始 measure;
  • 生成的 cubes,标记为
    meta.abConnectionId: "revos"
    ——即 segment 快照(
    segment_…
    )和 tables 自身的 columns(
    model_stream_…
    )。
    meta
    不能通过
    fields
    进行投影;不过,读取候选 cube 的完整记录时,其中本来就会包含
    meta
    。
目录针对每个 measure 展示以下信息:
列来自
meta
指标
title
(
description
作为 tooltip)、
name
作为引用名
Cubecube 的
title
聚合
aggType
:
count
、
countDistinct
、
sum
、
avg
、
min
、
max
、
number
、…
格式
format
为
currency
/
percent
;否则按类型为 Number、Text、Boolean、Date
只有
type: "number"
的 measure 可以在 card 上统计;如果用户选择的是 text、boolean 或 time measure,要明确指出这一点。
当用户按含义询问指标(“win rate”“ARR”)时,搜索 titles 和 descriptions。如果没有匹配项,明确说明,并提供最接近的选项,或建议使用 cubes skill 添加一个——绝不能悄悄用另一项 measure 近似替代。

Where a metric is used

指标的使用位置

  • Tables: a view
    model_<table id, '-' → '_'>
    re-exports the measure (
    aliasMember == "<measure>"
    ). Map the id back with
    api_read { "resource": "tables", "params": { "fields": "id,name" } }
    .
  • Segments: the measure (or a view alias of it) is a
    member
    in the segment's
    filter
    .
  • Dashboards:
    api_read { "resource": "dashboard-cards", "params": { "filter": "measure == \"<measure>\"" } }
    .
  • Tables:一个 view
    model_<table id, '-' → '_'>
    会重新导出该 measure(
    aliasMember == "<measure>"
    )。可通过
    api_read { "resource": "tables", "params": { "fields": "id,name" } }
    将 id 映射回去。
  • Segments:该 measure(或它的 view alias)是 segment
    filter
    中的
    member
    。
  • Dashboards:
    api_read { "resource": "dashboard-cards", "params": { "filter": "measure == \"<measure>\"" } }
    。

A metric's value

指标值

api_read { "resource": "cubes", "method": "query", "body": { "query": … } }
, built exactly as the app builds it — otherwise your number differs from the one on the user's screen:
json
{
  "measures": ["<measure>"],
  "filters": [ <the scope's conditions, as Cube filters> ],
  "joinHints": [ <each join path, split on "."> ]
}
Leave out
filters
/
joinHints
when empty.
api_read { "resource": "cubes", "method": "query", "body": { "query": … } }
,其 query 必须按照应用构建查询的方式精确构建——否则所得数值会与用户屏幕上显示的不一致:
json
{
  "measures": ["<measure>"],
  "filters": [ <the scope's conditions, as Cube filters> ],
  "joinHints": [ <each join path, split on "."> ]
}
当
filters
/
joinHints
为空时将其省略。

Scope

统计范围(Scope)

  • Every row — no filters.
  • Conditions — written in segment filter syntax (see the segments skill's
    references/filter-syntax.md
    ) and translated with its table:
    EQUAL
    →
    equals
    ,
    EMPTY
    →
    notSet
    ,
    CHECKED
    →
    equals "true"
    , … Top-level
    AND
    items are separate
    filters
    entries; an
    OR
    becomes
    { "or": [ … ] }
    , an
    AND
    group
    { "and": [ … ] }
    . Skip conditions with no
    member
    , or no
    value
    where the operator needs one — the app does too. Check stored values with a cubes query before an
    EQUAL
    on a string.
  • A dynamic segment — read it; translate its
    filter
    the same way, and put its
    cubes[1..].joinPath
    into
    joinHints
    first.
  • A static segment — one filter instead of its conditions:
    { "member": "segment_<segment id, '-' → '_'>.id", "operator": "set" }
    . It needs that
    segment_…
    cube in
    meta
    .
A segment fits a metric only when its root cube is the metric's cube (
segment.cubes[0].joinPath
). A segment of companies can't scope a deal metric — say so, and offer conditions on the company fields instead.
  • 所有行——不带 filters。
  • Conditions——使用 segment filter syntax 编写(见 segments skill 的
    references/filter-syntax.md
    ),并按照其对照表转换:
    EQUAL
    →
    equals
    ,
    EMPTY
    →
    notSet
    ,
    CHECKED
    →
    equals "true"
    ,…… 顶层
    AND
    项要分别作为独立的
    filters
    条目;
    OR
    转换为
    { "or": [ … ] }
    ,
    AND
    group 转换为
    { "and": [ … ] }
    。跳过没有
    member
    的 conditions,或在 operator 需要 value 时没有
    value
    的 conditions——应用也会跳过。先通过 cubes query 检查存储值,再对字符串使用
    EQUAL
    。
  • 动态 segment——读取它;同样转换它的
    filter
    ,并首先将其
    cubes[1..].joinPath
    放入
    joinHints
    。
  • 静态 segment——用一个 filter 代替其 conditions:
    { "member": "segment_<segment id, '-' → '_'>.id", "operator": "set" }
    它需要
    meta
    中存在该
    segment_…
    cube。
只有当 segment 的 root cube 与指标的 cube 相同时(
segment.cubes[0].joinPath
),该 segment 才能用于该指标。companies 的 segment 不能限定 deal 指标——应明确说明,并改为提供 company fields 上的 conditions。

Joins to other cubes

与其他 cubes 的 joins

A condition or breakdown on another cube reads it along a join path from the metric's cube:
crm_deals.crm_companies
. Check each hop against
joins
in
meta
(declared on either side). When two routes exist, the choice changes the number — ask which the user means. Send each path as a join hint,
["crm_deals", "crm_companies"]
; the metric's own cube needs none.
Two conditions the app refuses, and you should too:
  • A condition on a measure (
    crm_deals.count > 3
    ). On a total it isn't per-row; it's not a scope.
  • A condition on a cube the metric's rows have many of (
    hasMany
    /
    one_to_many
    along the path): each row is checked once per related row.
对另一个 cube 的 condition 或 breakdown,需要沿指标 cube 出发的 join path 读取它:
crm_deals.crm_companies
。根据
meta
中的
joins
逐跳检查(可在任一侧声明)。存在两条路径时,不同选择会改变数值——询问用户指的是哪一条。每条路径都作为 join hint 发送,
["crm_deals", "crm_companies"]
;指标自身的 cube 不需要。
应用会拒绝以下两种 conditions,你也应拒绝:
  • 对 measure 的 condition(
    crm_deals.count > 3
    )。对于 total,它并非按行生效,因此不能作为 scope。
  • 对指标行具有多个关联项的 cube 的 condition(路径上为
    hasMany
    /
    one_to_many
    ):每一行会针对每个相关行检查一次。

Breakdown

拆分(Breakdown)

The same query plus the dimension:
  • not a time dimension:
    "dimensions": ["<dim>"]
    ,
    "order": { "<measure>": "desc", "<dim>": "asc" }
    — largest groups first.
  • a time dimension:
    "timeDimensions": [{ "dimension": "<dim>", "granularity": "month" }]
    ,
    "order": { "<dim>": "desc" }
    — latest months first.
The groups add up to the total only for a
count
or
sum
measure whose breakdown doesn't go along a join the rows have many of. Otherwise don't present shares or an "Other" bucket, and for a fanned-out breakdown, say a record linked to several groups is counted in each. A card shows the top 5 plus "Other"; the metric page shows 50.
在同一个 query 中加入 dimension:
  • 非 time dimension:
    "dimensions": ["<dim>"]
    ,
    "order": { "<measure>": "desc", "<dim>": "asc" }
    ——最大的 groups 排在前面。
  • time dimension:
    "timeDimensions": [{ "dimension": "<dim>", "granularity": "month" }]
    ,
    "order": { "<dim>": "desc" }
    ——最近的 months 排在前面。
只有当 measure 为
count
或
sum
,且其 breakdown 没有沿着指标行存在多关联项的 join 时,各 groups 的总和才等于 total。否则,不要展示占比或“Other” bucket;对于发生 fan-out 的 breakdown,要说明一条关联到多个 groups 的 record 会在每个 group 中分别计数。card 展示 top 5 加“Other”;指标页面展示 50 条。

Reading the answer

解读结果

  • No rows: a count, count distinct, or sum is
    0
    ; an average or other measure has no value — say "no value", not
    0
    .
  • Format with the measure's
    format
    (currency, percent).
  • Always say what the number is counted over: "€1.2M open pipeline, deals in the EMEA segment".
  • metadata.lastRefreshTime
    on the result says how fresh it is; mention it when it's old or
    slowQuery
    is set.
Render a single value as one line, a breakdown as a small table, or a chart when it helps.
  • 没有行:对于 count、count distinct 或 sum,值为
    0
    ;对于 average 或其他 measure,则没有值——应说“无值”,而不是
    0
    。
  • 使用 measure 的
    format
    进行格式化(currency、percent)。
  • 始终说明数字的统计范围:“€1.2M open pipeline,deals 位于 EMEA segment 中”。
  • metadata.lastRefreshTime
    表明结果的新鲜度;当它过旧或设置了
    slowQuery
    时,应提及。
将单一值呈现为一行,将 breakdown 呈现为小型 table,或在有助于表达时使用 chart。