使用 extends 重复使用代码

本主题属于高级主题,假定读者对 LookML 有扎实的了解。

概览

随着 LookML 模型的规模和复杂性不断扩大,在多个位置重复使用 LookML 变得越来越有用。借助 extends 参数,您可以重复使用代码,从而帮助您执行以下操作:

  • 编写 DRY(避免重复代码)代码,以便在一个位置定义所有内容,从而使代码更一致且更快捷地进行修改
  • 为不同用户管理不同的字段集
  • 在项目的不同部分共享设计模式
  • 在项目中重复使用一组联接、维度或测量值

如需扩展 LookML 对象,您需要创建一个新的 LookML 对象,然后添加 extends 参数,以指明新对象是现有对象的扩展。这意味着您的项目将有两个版本的 LookML 对象。如果存在任何冲突,扩展对象将优先并替换被扩展对象的设置。如需了解详情,请参阅本页面后面的 extends 的实现详情部分。

了解 LookML 优化:如果您希望有多个版本的视图或探索,则非常适合扩展视图或探索。不过,如果您的目标只是修改视图或探索,而不修改包含它们的 LookML 文件,则可以改用精炼。您还可以在精炼条件中使用 extends 参数。如需了解详情和用例,请参阅 LookML 优化文档页面。

您可以扩展视图、探索和 LookML 信息中心:

模型无法扩展,您也无法在一个模型文件中包含另一个模型文件。不过,如果您想在多个模型中重复使用或扩展探索,可以创建单独的探索文件,然后在模型文件中添加该探索文件

请参阅以下扩展探索扩展 LookML 信息中心示例。

延长探索的有效期

以下是扩展“探索”的示例:

explore: customer {
  persist_for: "12 hours"
}

explore: transaction {
  extends: [customer]
  persist_for: "5 minutes"
}

在此示例中,我们有一个名为“客户”的探索,并创建了一个名为“交易”的第二个探索来扩展它。Customer 中的所有内容(例如其联接)都将包含在 Transaction 中。交易中的所有内容都将保留在交易中。

但请注意,存在冲突:客户探索卡片显示 persist_for 设置应为 12 小时,但交易探索卡片显示应为 5 分钟。对于交易探索,系统会使用 persist_for: "5 minutes" 设置,因为它会覆盖其扩展的探索中的设置。

扩展 LookML 信息中心

如需扩展 LookML 信息中心,您必须在模型文件中包含要扩展的信息中心和要扩展的信息中心。如果模型文件中包含使用 extends 参数的信息中心,但不包含其扩展的基础信息中心,您会收到 LookML 验证错误,其中指出找不到基础信息中心(以及其他错误)。

以下是信息中心文件的示例:

文件:faa.dashboard.lookml

- dashboard: faa
  title: FAA Dashboard
  layout: newspaper
  elements:
  - title: Aircraft Location
    name: Aircraft Location
    model: e_faa
    explore: aircraft
    type: looker_map
    fields:
    - aircraft.zip
    - aircraft.count
    sorts:
    - aircraft.count desc
    limit: 500
    query_timezone: America/Los_Angeles
    series_types: {}
    row: 0
    col: 0
    width: 8
    height: 6

我们可以创建新的 LookML 信息中心文件,并通过添加新的功能块来扩展 FAA 信息中心:

文件:faa_additional.dashboard.lookml

- dashboard: faa_additional
  title: FAA Additional
  extends: faa
  elements:
  - title: Elevation Count
    name: Elevation Count
    model: e_faa
    explore: airports
    type: looker_scatter
    fields:
    - airports.elevation
    - airports.count
    sorts:
    - airports.count desc
    limit: 500
    query_timezone: America/Los_Angeles
    row: 0
    col: 8
    width: 8
    height: 6

由于它扩展了 FAA 信息中心,因此 FAA 附加信息中心将包含 faa.dashboard.lookml 文件中定义的所有功能块。此外,FAA 附加信息中心将包含在其自己的 faa_additional.dashboard.lookml 文件中定义的所有功能块。

若要创建 LookML 信息中心,最简单的方法是从用户定义的信息中心获取 LookML。您还可以使用此方法获取各个信息中心图块的 LookML。如果您使用此方法,请务必确保功能块的位置不会重叠。在 faa.dashboard.lookmlfaa_additional.dashboard.lookml 示例中,这些功能块都位于信息中心的顶行(由 row: 0 表示):

文件:faa.dashboard.lookml


    row: 0
    col: 0
    width: 8
    height: 6

不过,我们在 FAA Additional 信息中心中添加的新功能块位于 col: 8 中,因此会显示在展开式信息中心的功能块旁边:

文件:faa_additional.dashboard.lookml


    row: 0
    col: 8
    width: 8
    height: 6

由于这些元素位于不同的信息中心文件中,因此很容易被忽略。因此,如果您要向展开式信息中心添加功能块,请务必检查展开式信息中心中的功能块与展开式信息中心中的功能块之间是否存在位置冲突。

需要延期

您可以使用 extension: required 参数将 LookML 对象标记为需要扩展,这意味着该对象不能单独使用。具有 extension: required 的对象本身对用户不可见;它只是作为其他 LookML 对象的起点来扩展。探索视图LookML 信息中心支持 extension 参数。

包含 extension: requiredexplore 不能用作数据测试explore_sourceLookML 验证器会生成一条错误消息,指出找不到 explore_source

使用元数据查看对象的扩展程序

您可以在 Looker IDE 中点击 exploreview 参数,然后使用元数据面板查看对象的任何扩展,或查看它扩展了哪个对象。如需了解详情,请参阅 LookML 对象的元数据文档页面。

extends 的实现详情

Looker 在扩展 LookML 对象时会执行以下步骤:

  1. 复制要扩展的对象:Looker 会为要扩展的视图、探索或 LookML 信息中心创建 LookML 的副本。这个新副本就是扩展对象。
  2. 合并两个副本的 LookML:Looker 会将被扩展对象的 LookML 合并到扩展对象中。
  3. 解决副本之间的冲突:在大多数情况下,如果在扩展对象和扩展对象中都定义了 LookML 元素,则系统会使用扩展对象中的版本。不过,在其他情况下,扩展程序会组合参数值,而不是替换值。如需了解详情,请参阅本页的组合参数部分。
  4. 应用 LookML:解决所有冲突后,Looker 会使用标准逻辑解读生成的 LookML。换句话说,Looker 将使用与任何其他视图、探索或 LookML 信息中心一样的所有标准默认值和假设。

以下部分将介绍这些步骤的具体内容,并以扩展 View 为例。下面是基本视图“用户”的 LookML:

view: user {
  suggestions: yes

  dimension: name {
    sql: ${TABLE}.name ;;

  }
  dimension: status {
    sql: ${TABLE}.status ;;
    type: number
  }
}

以下是包含年龄细分的用户视图的 LookML,该视图扩展了用户视图:

include: "/views/user.view"

view: user_with_age_extensions {
  extends: [user]
  suggestions: no

  dimension: age {
    type: number
    sql: ${TABLE}.age ;;
  }

  dimension: status {
    type: string
  }
}

第 1 步:复制 LookML

在本例中,user 视图会扩展到 user_with_age_extensions 视图。由于 user 是被扩展的视图,因此系统会先创建其副本,然后再进行合并。这里不必特别注意是否创建了副本;重要的是,原始 user 视图保持不变,并且可以照常使用。

第 2 步:合并副本

下一步是将扩展视图 (user) 中的所有 LookML 合并到扩展视图 (user_with_age_extensions) 中。请务必了解此合并的性质,这只是 LookML 对象的合并。实际上,这意味着所有明确编写的 LookML 都会合并,但您未编写的默认 LookML 值不会合并。从某种意义上讲,它实际上只是将 LookML 的文本组合在一起,而没有任何文本的含义。

第 3 步:解决冲突

第 3 步是解决合并视图之间的任何冲突。

在大多数情况下,如果在被扩展的对象和扩展对象中都定义了 LookML 元素,则使用扩展对象中的版本。不过,在其他情况下,扩展程序会组合参数值,而不是替换这些值。如需了解详情,请参阅本页的组合参数部分。

user_with_age_extensions 示例中,所有参数均不是累加参数,并且未指定任何特殊的列表选项sql 关键字,因此扩展视图中的参数值将替换被扩展视图中的参数值:

  • 延伸视图名称 (user_with_age_extensions) 会替换延伸视图名称 (user)。
  • suggestions: no 的扩展值会替换扩展suggestions: yes
  • 正在延伸的视图有一个名为 age 的尺寸,该尺寸不存在于已延伸的视图中(没有冲突)。
  • 展开的视图有一个名为 name 的尺寸,该尺寸不存在于展开的视图中(没有冲突)。
  • 展开视图中的 status 维度的 type: string 值会覆盖展开视图中的 type: number 值。
  • status 维度具有 sql 参数,但该参数不存在于扩展视图中(无冲突)。

请务必注意,系统尚未考虑默认 LookML 值,因为您不希望错误地认为默认值之间的冲突已得到解决。实际上,此步骤只是忽略了这些值。因此,在扩展对象时,我们需要显式添加其他参数:

在本示例中,我们sql_table_name 添加到用户视图,这将在下一步中导致一些问题。

第 4 步:照常解读 LookML

在最后一步中,系统会按常规方式解读生成的 LookML,包括所有默认值。在本例中,生成的视图 LookML 将被解读如下:

include: "/views/user.view"

view: user_with_age_extensions {
  suggestions: no

  dimension: age {
    type: number
    sql: ${TABLE}.age ;;
  }

  dimension: name {
    sql: ${TABLE}.name ;;
  }

  dimension: status {
    sql: ${TABLE}.status ;;
    type: string
  }
}

请注意,生成的 LookML 包含 view: user_with_age_extensions,但不包含 sql_table_name 参数。因此,Looker 会假定 sql_table_name 的值等于视图名称。

问题在于,数据库中可能没有名为 user_with_age_extensions 的表。因此,我们需要向要扩展的任何视图添加 sql_table_name 参数。将 view_nameview_label 添加到要延长时长的探索可避免类似问题。

组合扩展

您可以通过以下几种方式利用扩展的 LookML 对象:

如需查看高级用例示例并阅读问题排查提示,请参阅排查高级 extends 用例示例问题最佳实践页面。

同时扩展多个对象

您可以同时展开多个信息中心、视图或“探索”页面。例如:

explore: orders {
  extends: [user_info, marketing_info]
}
# Also works for dashboards and views

扩展程序的运作方式与实现示例中所述的完全一样,但有一个额外的规则与如何解决冲突有关。如果 extends 参数中列出的多个项之间存在任何冲突,则优先级为最后列出的项。因此,在上面的示例中,如果 user_infomarketing_info 之间存在冲突,则 marketing_info“探索”会胜出。

将多个扩展链接在一起

您还可以将任意数量的扩展链接在一起。例如:

explore: orders {
  extends: [user_info]
  ...
}
explore: user_info {
  extends: [marketing_info]
  ...
}

再次说明一下,扩展程序的运作方式与实现示例中所述的完全一样,只不过多了一个与冲突解决相关的规则。如果存在任何冲突,则优先级为扩展链中的最后一个项。在此示例中:

  • orders 的优先级高于 user_infomarketing_info
  • user_info 的优先级高于 marketing_info

组合参数

在大多数情况下,如果在被扩展的对象和扩展对象中都定义了 LookML 元素,则使用扩展对象中的版本。本页中的实现示例就是这种情况。

不过,在以下情况下,扩展程序会组合参数值,而不是替换值:

某些参数是累加的

在许多情况下,如果扩展对象包含与要扩展的对象相同的参数,则扩展对象的值将替换被扩展对象的参数值。但对于某些参数,扩展可以是累加的,这意味着扩展对象中的值会与被扩展对象中的值结合使用。

以下参数是累加的:

在以下示例中,carriers 视图具有 name 维度和 link 参数:

view: carriers {
  sql_table_name: flightstats.carriers ;;

  dimension: name {
    sql: ${TABLE}.name ;;
    type: string
    link: {
      label: "Google {{ value }}"
      url: "http://www.google.com/search?q={{ value }}"
      icon_url: "http://google.com/favicon.ico"
    }
  }
}

这是 carriers_extended 视图,它会扩展 carriers 视图。carriers_extended 视图还有一个 name 维度,其 link 参数具有不同的设置:


include: "/views/carriers.view.lkml"

view: carriers_extended {
  extends: [carriers]

  dimension: name {
    sql: ${TABLE}.name ;;
    type: string
    link: {
      label: "Dashboard for {{ value }}"
      url: "https://docsexamples.dev.looker.com/dashboards/307?Carrier={{ value }}"
      icon_url: "https://www.looker.com/favicon.ico"
    }
  }
}

carriers_extended 视图中,两个 link 参数是可叠加的,因此 name 维度将显示这两个链接。

使用列表的其他选项

使用列表时,您可以选择将它们组合起来,而不是让扩展对象的列表胜出。考虑以下包含名为 animals 的冲突列表的简单扩展程序:

view: pets {
  extends: fish
  set: animals {
    fields: [dog, cat]
  }
}
view: fish {
  set: animals {
    fields: [goldfish, guppy]
  }
}

在这种情况下,pets 视图正在执行延伸,因此会胜出,使 animals 包含 [dog, cat]。不过,您可以利用特殊的 EXTENDED* 集合来组合这些列表:

view: pets {
  extends: fish
  set: animals {
    fields: [dog, cat, EXTENDED*]
  }
}
view: fish {
  set: animals {
    fields: [goldfish, guppy]
  }
}

现在,animals 列表将包含 [dog, cat, goldfish, guppy]

在解决冲突时合并,而不是替换

在大多数情况下,如果扩展期间存在任何冲突,则扩展对象会胜出。例如,请看以下简单的扩展程序:

view: product_short_descriptions {
  extends: products
  dimension: description {
    sql: ${TABLE}.short_description ;;
  }
}
view: products {
  dimension: description {
    sql: ${TABLE}.full_description ;;
  }
}

您可以看到,description 维度中存在 sql 参数冲突。通常,来自 product_short_descriptions 的定义会直接覆盖来自 products 的定义,因为它会执行扩展。

不过,您也可以根据需要选择组合这些定义。为此,您将使用 ${EXTENDED} 关键字,如下所示:

view: product_short_descriptions {
  extends: products
  dimension: description {
    sql: LEFT(${EXTENDED}, 50) ;;
  }
}
view: products {
  dimension: description {
    sql: ${TABLE}.full_description ;;
  }
}

现在,系统会以不同的方式解决 sql 参数的冲突。系统会从 products 中获取定义,并将其插入使用 ${EXTENDED} 的位置,而不是采用 product_short_descriptions 定义。在本例中,description 的最终定义将为:LEFT(${TABLE}.full_description, 50)

需要考虑的事项

已本地化的项目

扩展对象时,请注意本地化规则也适用于您的扩展程序。如果您要扩展对象,然后定义新的标签或说明,则应在项目的语言区域字符串文件中提供本地化定义。如需了解详情,请参阅将 LookML 模型本地化文档页面。