SEMANTIC VIEW(Beta)

更新时间:
复制 MD 格式

语义视图(SEMANTIC VIEW)在数据库内声明一层面向业务的语义模型,通过TABLES、RELATIONSHIPS、DIMENSIONS和METRICS子句组织底层物理表、表间关系、业务维度和指标。查询语义视图时,您只需指定维度名和AGG(指标名),Hologres会自动完成表裁剪、最小JOIN与先聚合后关联,避免明细表JOIN后再聚合导致的指标重复放大,同时生成结构化的YAML模型,供BI工具与AI Agent(NL2SQL)读取业务语义。本文为您介绍SEMANTIC VIEW的语法、查询方式、内省方法和使用限制。

说明

SEMANTIC VIEW当前处于Beta阶段,仅Hologres V5.0.0及以上版本支持。

背景信息

应用场景

  • 统一指标口径:将total_revenue固定定义为sum(o.amount),避免同一指标存在多种计算口径。

  • 降低查询复杂度:业务人员只需使用维度和指标查询数据,无需理解星型模型的物理表与JOIN关系。

  • 避免重复计数:一对多JOIN后再聚合时,金额、计数等指标被放大的问题由引擎自动规避。

  • AI与NL2SQL友好:结构化的YAML模型为AI Agent提供业务语义上下文。

原理

查询Semantic View时,引擎不会先将所有物理表JOIN后再聚合,而是按以下步骤改写查询:

  1. 为每个被引用的指标构造最小JOIN子树,只关联必要的表,无关表自动裁剪。

  2. 将来源、粒度、JOIN树一致的指标合并为一个metric group,共用一次扫描与聚合。

  3. 每个metric group在相同的输出维度上先独立聚合。

  4. 存在多个metric group时,选取粒度最细的metric group作为主结果域,其余metric group按全部输出维度做NULL-safe LEFT JOIN拼接。

当某个指标的归属表会被JOIN放大(fan-out)时,引擎会先按“输出维度+归属表主键”去重,再回表聚合,保证同一条记录对同一输出维度至多贡献一次。

对于无法安全判断语义的查询形态(关系路径歧义、同一父表下存在多条独立的many-side分支),引擎直接报错拒绝,不返回可能错误的结果。

开关与可观测性

SEMANTIC VIEW的查询能力与调试输出由以下GUC参数控制。

GUC参数

默认值

说明

hg_enable_semantic_view_query

on

是否启用Semantic View查询能力。关闭后,查询语义视图会按普通表解析,并报错relation ... does not exist。

hg_semantic_view_rewrite_debug

off

是否通过NOTICE输出最终执行的物理SQL,用于排查和验证,不建议在生产环境长期开启。

更多GUC参数的说明,请参见GUC参数。

您可以通过如下命令开启或关闭调试输出。

SET hg_semantic_view_rewrite_debug = on;   -- 排查时开启
RESET hg_semantic_view_rewrite_debug;

创建Semantic View

语法

创建和删除语义视图的语法格式如下。

CREATE SEMANTIC VIEW [IF NOT EXISTS] [schema.]view_name
  TABLES ( alias AS [schema.]table_name [PRIMARY KEY (col1[, ...])] , ... )
  [RELATIONSHIPS ( [rel_name AS] from_alias(col[, ...]) REFERENCES to_alias[(col[, ...])] , ... )]
  [DIMENSIONS ( owner_alias.dim_name AS <expression> [COMMENT = '说明'] , ... )]
  [METRICS ( owner_alias.metric_name AS <aggregate_expression> [COMMENT = '说明'] , ... )]
  [COMMENT = '视图说明'];

DROP SEMANTIC VIEW [IF EXISTS] [schema.]view_name;

参数说明如下。

参数

说明

view_name

语义视图的名称,可通过[schema.]view_name指定所属Schema。

TABLES

声明参与建模的物理表,格式为alias AS [schema.]table_name。alias在视图内必须唯一;多表建模建议为每张表声明PRIMARY KEY,用于关系校验与去重保护。支持基于表、视图(VIEW)和物化视图(MATERIALIZED VIEW)建模。

RELATIONSHIPS

声明表间关系,格式为[rel_name AS] from_alias(col) REFERENCES to_alias(col)。from_alias为many侧,to_alias为one侧;REFERENCES的目标列必须是目标表声明的PRIMARY KEY,省略列名时自动匹配。

DIMENSIONS

声明业务维度,格式为owner_alias.dim_name AS <expression>,查询时使用左侧的dim_name。

METRICS

声明业务指标,格式为owner_alias.metric_name AS <aggregate_expression>,查询时使用左侧的metric_name。

<expression>

维度表达式,为单个物理alias的行级表达式,支持列、常量、系统内置标量函数与运算符、CASE和cast。

<aggregate_expression>

指标聚合表达式。支持的聚合函数为count(*)、count(expr)、count(DISTINCT expr)、sum、avg、min和max。

COMMENT

视图、维度或指标的说明。COMMENT的内容会写入YAML模型的description字段。

示例

以下示例基于已存在的public.orders与public.customers表,创建名为sales_sv的语义视图。

CREATE SEMANTIC VIEW sales_sv
  TABLES (
    o AS public.orders    PRIMARY KEY (order_id),
    c AS public.customers PRIMARY KEY (customer_id)
  )
  RELATIONSHIPS ( rel_oc AS o(customer_id) REFERENCES c(customer_id) )
  DIMENSIONS (
    o.status_dim AS o.status,
    c.city_dim   AS c.city COMMENT = '客户城市'
  )
  METRICS (
    o.total       AS sum(o.amount) COMMENT = '订单金额',
    o.order_count AS count(*),
    c.credit      AS sum(c.credit_limit)
  )
  COMMENT = '销售分析语义视图';

查询Semantic View

查询语义视图时,指标必须使用AGG(指标名)包裹,维度可直接引用并写入GROUP BY。查询示例如下。

-- 分组聚合
SELECT city_dim, AGG(total), AGG(credit) FROM sales_sv GROUP BY city_dim;

-- 全局聚合(无需 GROUP BY)
SELECT AGG(total), AGG(order_count) FROM sales_sv;

-- WHERE 过滤维度(只作过滤、不进入输出粒度)
SELECT city_dim, AGG(total) FROM sales_sv WHERE status_dim = 'completed' GROUP BY city_dim;

-- HAVING / ORDER BY / LIMIT
SELECT city_dim, AGG(total) AS revenue FROM sales_sv
GROUP BY city_dim HAVING AGG(total) > 100 ORDER BY revenue DESC LIMIT 10;

-- SELECT 支持标量表达式组合
SELECT upper(city_dim) AS city,
       AGG(total) / NULLIF(AGG(order_count), 0) AS avg_order_value,
       CASE WHEN AGG(total) > 1000 THEN 'high' ELSE 'normal' END AS lvl
FROM sales_sv GROUP BY city_dim;

查询时需注意以下要点。

  • GROUP BY必须与SELECT输出的维度完全一致,不能多写,也不能漏写。

  • 维度嵌套在表达式中时,GROUP BY仍写维度名。

  • WHERE中不能使用指标,按聚合结果过滤请使用HAVING AGG(指标名)。

内省与YAML模型

Semantic View的定义持久化在系统表hologres.hg_semantic_view_properties中,该系统表包含schema_name、view_name、property_key和property_value四列,提供以下三类property_key。

property_key

内容

ddl_text

用户提交的原始CREATE SEMANTIC VIEW语句。

model_yaml

结构化的YAML语义模型,供BI工具与AI Agent消费。

owner

视图的owner。

您可以通过如下SQL列出当前Schema下的语义视图,或查看指定语义视图的YAML模型。

-- 列出当前 schema 下所有 Semantic View 及 owner
SELECT view_name, max(property_value) FILTER (WHERE property_key = 'owner') AS owner
FROM hologres.hg_semantic_view_properties
WHERE schema_name = current_schema() GROUP BY view_name;

-- 查看 YAML 语义模型
SELECT property_value AS model_yaml
FROM hologres.hg_semantic_view_properties
WHERE schema_name = current_schema()
  AND view_name = 'sales_sv' AND property_key = 'model_yaml';

model_yaml的结构示例如下,与DDL逐项对应,COMMENT的内容落为description字段。

name: sales_sv
description: 销售分析语义视图
tables:
- name: o
  base_table: {database: mydb, schema: public, table: orders}
  primary_key: {columns: [order_id]}
  dimensions:
  - {name: status_dim, expr: o.status}
  metrics:
  - {name: total, expr: sum(o.amount), description: 订单金额}
relationships:
- name: rel_oc
  left_table: o
  right_table: c
  relationship_columns: [{left_column: customer_id, right_column: customer_id}]
  relationship_type: many_to_one
说明

当前不提供YAML导入函数(hg_create_semantic_view_from_yaml()),跨环境重建语义视图请使用原始的ddl_text。

如何确认生效与排查

您可以通过以下三步确认Semantic View已生效,并排查查询结果。

  1. 确认对象存在:查询系统表hologres.hg_semantic_view_properties,确认其中存在该view_name对应的ddl_text。

  2. 查看实际执行的SQL:执行SET hg_semantic_view_rewrite_debug = on;后再执行查询,NOTICE会输出改写后的物理SQL。多指标组场景下,可以看到多个WITH __hg_sv_xxx CTE,以及外层的LEFT JOIN ... ON NOT (q_0.dim IS DISTINCT FROM q_1.dim)(NULL-safe拼接)。

  3. 校验指标未被放大:使用“先对明细去重、再聚合”的手写SQL作为基线,与语义视图的查询结果进行比对。

使用限制

SEMANTIC VIEW在建模和查询时存在以下限制。

建模限制

  • 表达式不能跨物理alias;不支持窗口函数、子查询、参数引用、VOLATILE函数和set-returning函数。

  • 聚合仅支持count、sum、avg、min和max;不支持派生指标、比率指标和条件(filtered)指标,如sum(a)/count(*)。

  • REFERENCES的目标列必须是目标表的PRIMARY KEY;不支持many-to-many关系和bridge表。

  • 暂不支持CREATE OR REPLACE SEMANTIC VIEW和ALTER SEMANTIC VIEW,如需修改定义,请DROP后重建。

查询限制

  • 指标必须使用AGG()包裹;AGG()只接受裸指标名,不支持AGG(DISTINCT m)、FILTER和OVER等修饰。

  • 不支持SELECT *、SELECT DISTINCT、窗口函数、QUALIFY和FOR UPDATE/SHARE。

  • WHERE中不能引用指标;HAVING和ORDER BY中不能直接书写底层聚合函数,如count(*)。

  • 多表查询必须在SELECT中至少输出一个指标,只输出维度会被拒绝;查询仅触达一张表时,按单表处理。

  • 不支持CREATE VIEW ... AS SELECT ... FROM semantic_view,可使用CREATE TABLE AS SELECT将查询结果物化。

  • 不支持多个Semantic View之间JOIN、Semantic View与物理表JOIN,以及WITH和集合运算等复杂外层结构。

  • 不支持DML操作:对Semantic View执行INSERT、UPDATE、DELETE和TRUNCATE会失败,当前报错relation ... does not exist,因为语义视图未注册为普通表对象。

会被拒绝的多表形态

  • 关系路径歧义:同一对表之间存在多条关系,或存在多条可达路径时,查询会被拒绝,报错ambiguous relationship path。

  • 深谷陷阱(Chasm trap):同一父表下存在两条互相独立的many-side分支,查询同时使用两条分支的维度或指标时会被拒绝,报错提示需要explicit common domain。

建模建议

  • 为每张表声明PRIMARY KEY:这是保证多表聚合正确性(去重保护)的基础。

  • 关系方向要写对:from_alias必须是many侧,to_alias必须是one侧;写反会让引擎误判为一对多关系,导致重复聚合。

  • 避免为同一对表定义多条关系:例如“出发机场”和“到达机场”两条flights → airports关系,会导致查询因路径歧义被拒绝;如确需区分,建议拆分为不同的Semantic View。

  • 避免在一个查询中跨sibling分支:例如同时统计orders与addresses两条分支的指标,当前会被拒绝,可拆分为两个查询。

  • 定义表达式时使用明确的对象名与无歧义的字面量:查询时会重新解析ddl_text,应避免依赖会话的search_path、时区等设置。

  • 为维度和指标添加COMMENT:COMMENT的内容会写入model_yaml的description字段,可显著提升AI Agent与NL2SQL的理解准确率。

常见错误与替代写法

查询Semantic View时的常见错误写法、对应报错与正确写法如下。

错误写法

报错信息

正确写法

SELECT city_dim, total FROM sv

is a metric and must be wrapped with AGG()

SELECT city_dim, AGG(total) ...

WHERE total > 100

metric ... cannot be used in WHERE clause

HAVING AGG(total) > 100

HAVING count(*) > 1

raw aggregate functions are not allowed

HAVING AGG(order_count) > 1

SELECT * FROM sv

column reference must be a bare dimension name

显式列出维度与AGG(指标名)。

GROUP BY中多写未输出的维度

GROUP BY columns must match the dimensions in SELECT

GROUP BY与SELECT输出的维度保持一致。