正确设置关系参数

本页面适用于尝试使用 LookML 在 Looker 中构建“探索”功能的任何用户。如果您精通 SQL,尤其是了解内连接和外连接之间的区别,则更容易理解本页内容。如需简要了解内连接和外连接的区别,请参阅 w3schools 上这篇关于 SQL 联接的文章。

Looker 可以成为贵公司的强大 SQL 引擎。借助 LookML 中的抽象建模,数据和 IT 团队可以构建始终为真的通用规则,从而让业务分析师能够构建始终正确的实际查询,即使数据团队从未预料到需要这些查询也是如此。此功能的核心驱动因素是对称聚合算法, 这一解决方案解决了整个行业内使用 SQL 联接的问题。不过,您必须正确完成两件事才能利用该算法:主键在每个包含测量值(通常是所有测量值)的视图中都必须准确,并且 relationship 参数在每次联接中都必须正确。

主键

在许多方面,了解表的主键与了解表是什么以及可以对其执行哪些操作本质上是相同的。唯一需要满足的要求是,您选择作为主键的列(或一组串联的列)不得包含重复值。

relationship 参数

现在您已经验证了主键,接下来可以确定联接的 relationship 参数的正确值。relationship 参数的用途是告知 Looker 在将联接写入 SQL 查询时是否调用对称汇总。一种可能的方法是告知 Looker 始终调用这些函数,这样就能始终获得准确的结果。但是,这会降低性能,因此最好谨慎使用对称聚合。

确定正确值的过程在内部联接和外部联接之间略有不同。

内联接

例如,假设您有一个订单表,其主键为 order_id

order_id 金额 customer_id
1 $25.00 1
2 50.00 美元 1
3 75.00 美元 2
4 $35.00 3

假设您还有一个客户表,其主键为 customer_id

customer_id first_name last_name 就医数据
1 Amelia Earhart 2
2 Bessie Coleman 2
3 Wilbur Wright 4

您可以使用 customer_id 字段联接这些表,该字段同时存在于两个表中。此联接在 LookML 中的表示方式如下:

explore: orders {
  join: customers {
    type: inner
    sql_on: ${orders.customer_id} = ${customers.customer_id} ;;
    relationship: many_to_one
  }
}

此 LookML 联接的结果可以表示为单个联接表,如下所示:

order_id 金额 customer_id customer_id first_name last_name 就医数据
1 $25.00 1 1 Amelia Earhart 2
2 50.00 美元 1 1 Amelia Earhart 2
3 75.00 美元 2 2 Bessie Coleman 2
4 $35.00 3 3 Wilbur Wright 4

此处的 many_to_one 关系是指联接字段 (customer_id) 的一个值在每个表中出现的次数。在 orders 表(左表)中,一个客户 ID 出现了多次(在本例中,此客户 ID 为 1,该客户出现在多行中)。

customers 表(右表)中,每个客户 ID 都仅表示一次,因为 customer_id 是该表的主键。因此,orders 表中的记录可能有多个匹配项,对应于 customers 表中的单个值。如果 customers 表中的每一行中的 customer_id 都不唯一,则关系为 many_to_many

您可以按照以下步骤通过检查主键,以编程方式确定正确的关系值:

  1. 首先将 many_to_many 编写为关系。只要主键正确无误,系统便始终会生成准确的结果,因为 Looker 始终会触发对称汇总算法并强制执行准确性。不过,由于该算法会使查询复杂化并增加运行时间,因此尝试将一侧或两侧更改为 one(而不是 many)会大有益处。
  2. 查看左侧表中的 sql_on 子句中的字段。如果这些字段构成左表的主键,您可以将 relationship 参数左侧更改为 one。否则,它通常必须保持 many。(如需了解特殊情况,请参阅本页面后文的注意事项部分。)
  3. 接下来,查看 sql_on 子句中代表右侧表的一个或多个字段。如果字段构成了右侧表的主键,您可以将右侧更改为 one

最佳实践是从左表(位于等号左侧)和右表(位于等号右侧)开始编写 sql_on 字词。sql_on 参数中条件的顺序无关紧要,除非该顺序与数据库的 SQL 方言相关。虽然 sql_on 参数不要求您按此方式对字段进行排序,但通过排列 sql_on 条件,使等号的左右两侧与 relationship 参数从左到右的读取方式相匹配,有助于您确定关系。以这种方式对字段进行排序还有助于您一目了然地了解要将新表联接到“探索”中的哪个现有表。

外部联接

对于外部联接,您还需要考虑到在联接期间添加 null 记录时可能会发生扇出的情况。这一点特别重要,因为左外联接是 Looker 中的默认联接。虽然 null 记录不会影响总和或平均值,但会影响 Looker 运行 type: count 衡量方式。如果操作不正确,将对 null 记录进行计数(这是不理想的)。

在完全外联接中,如果任一表的联接键缺少另一个表中的值,则可以向任一表添加 null 记录。下例展示了这一点,其中涉及 orders 表:

order_id 金额 customer_id
1 $25.00 1
2 50.00 美元 1
3 75.00 美元 2
4 $35.00 3

对于此示例,假设您还有以下 customers 表:

customer_id first_name last_name 就医数据
1 Amelia Earhart 2
2 Bessie Coleman 2
3 Wilbur Wright 4
4 Charles Yeager 3

联接这些表后,联接表可以表示为:

order_id 金额 customer_id customer_id first_name last_name 就医数据
1 $25.00 1 1 Amelia Earhart 2
2 50.00 美元 1 1 Amelia Earhart 2
3 75.00 美元 2 2 Bessie Coleman 2
4 $35.00 3 3 Wilbur Wright 4
null null null 4 Charles Yeager 3

就像在内部联接中一样,表的主键为 many_to_one。不过,添加的 null 记录也迫使左侧表格需要对称汇总。因此,您必须将 relationship 参数更改为 many_to_many,因为执行此联接会中断左表的计数。

如果本示例使用的是左外连接,则不会添加 null 行,并且会丢弃多余的客户记录。在这种情况下,关系仍然是 many_to_one。这是 Looker 的默认设置,因为系统假定基准表定义了分析。在这种情况下,您要分析的是订单,而不是客户。如果客户表位于左侧,情况会有所不同。

多级联接

在某些探索中,基表会联接到一个或多个视图,而这些视图又需要联接到一个或多个其他视图。在此示例中,这意味着某个表将与“客户”表联接。在这些情况下,评估 relationship 参数时,最好仅查看要写入的个别联接。Looker 会了解下游扇出何时会影响查询,即使受影响的视图不在实际创建扇出的联接中也是如此。

Looker 对我有何帮助?

Looker 中提供了一些机制来帮助确保关系值正确无误。一个是检查主键唯一性。每当需要扇出和对称聚合计算测量时,Looker 会检查所使用的主键是否唯一。如果它不是唯一的,则在查询运行时会显示错误(但是,不存在 LookML 验证器错误)。

此外,如果 Looker 无法处理扇出(通常是因为没有指明主键),则该视图的“探索”中不会显示任何测量结果。要解决此问题,只需将字段指定为主键,即可让您的测量结果显示在“探索”中。

需要考虑的事项

对对称聚合的方言支持

Looker 可以连接到不支持对称汇总的某些方言。您可以在 symmetric_aggregates 文档页面查看方言列表及其对对称聚合的支持。

特殊情况

本页上文中的内连接部分指出,若要确定正确的关系值,您应查看左侧表中的 sql_on 子句中的字段:“如果这些字段构成了左侧表的主键,您可以将 relationship 参数的左侧更改为 one。否则,它通常必须保持为 many。”除非表中包含的多个列都没有重复记录,否则就会出现这种情况。在这种情况下,在构建关系时,您可以将任何此类列视为主键,即使它不是指定为 primary_key: yes 的列也是如此。

为确保上文中的陈述始终对您指定的列保持不变,最好制定某种软件规则。如果是,请继续将其视为此类视图,并在视图文件中记下其特殊属性,以便他人日后参考(附上 SQL Runner 链接以证明这一点)。但请注意,当某个字段被指定为主键时,Looker 会确认隐含唯一性的真实性,但对于其他字段,则不会这样做。它只会不调用对称汇总算法。