多仓库dbt架构下引用其他dbt项目包时如何指定模型Schema?
背景
我们采用dbt多仓库架构,不同业务领域对应独立项目,包括dbt_dwh、dbt_project1、dbt_project2等。计划将dbt_dwh中的模型以Git包形式供约10个项目直接引用,理想方式是通过{{ ref('dbt_dwh', 'model_1') }}调用,但各项目有独立数据库Schema,运行dbt时出现问题:dbt默认使用当前项目(如dbt_project1)的target schema,而该Schema中不存在dbt_dwh的模型。
配置示例
dbt_project1的packages.yml
packages: - git: https://git/repo/url/here/dbt_dwh.git revision: master
dbt_dwh的profiles.yml
dbt_dwh: target: dwh_dev outputs: dwh_dev: <config rows here> dwh_prod: <config rows here>
dbt_project1的profiles.yml
dbt_project1: target: project1_dev outputs: project1_dev: <config rows here> project1_prod: <config rows here>
dbt_dwh中的sf_orders.sql模型
{{ config( materialized = 'table', alias = 'sf_orders' ) }} SELECT * FROM {{ source('salesforce', 'orders') }} WHERE uid IS NOT NULL
dbt_project1中的revenue_model1.sql模型
{{ config( materialized = 'table', alias = 'revenue_model1' ) }} SELECT * FROM {{ ref('dbt_dwh', 'sf_orders') }}
运行错误
预期dbt会识别sf_orders所属项目dbt_dwh的默认Schema为dwh_dev,生成dwh_dev.sf_orders的引用,但执行dbt run -m revenue_model1时,dbt默认使用dbt_project1的target schema(project1_dev),报错如下:
11:05:03 1 of 1 START sql table model project1_dev.revenue_model1 .................... [RUN] 11:05:04 1 of 1 ERROR creating sql table model project1_dev.revenue_model1 ........... [ERROR in 0.89s] 11:05:05 11:05:05 Completed with 1 error and 0 warnings: 11:05:05 11:05:05 Runtime Error in model revenue_model1 (folder\directory\revenue_model1.sql) 11:05:05 404 Not found: Table database_name.project1_dev.sf_orders was not found
问题
- 使用dbt
ref函数时,如何在运行时强制指定特定Schema? - 将
dbt_dwh作为Git包安装到其他项目时,能否强制使用其内部模型的默认参数/配置?
约束条件
- 所有对象和Schema位于同一数据库
- 无法切换到单仓库架构
- 不希望在每个项目中创建
source.yml引用dbt_dwh的输出对象(避免重复和版本不一致) - 不希望在dbt配置块中硬编码Schema(会失去
dbt_dwh的dev环境测试能力)
解决方案
问题1:强制指定Schema引用dbt_dwh模型
方案A:通过项目配置绑定依赖包Schema
在dbt_project1的dbt_project.yml中添加配置,为dbt_dwh包指定与环境匹配的固定Schema:
models: dbt_dwh: +schema: "{{ 'dwh_' ~ target.name.split('_')[1] }}"
此配置会让dbt自动解析dbt_dwh模型的Schema:当当前项目target为project1_dev时,dbt_dwh的模型会映射到dwh_dev;target为project1_prod时映射到dwh_prod。原{{ ref('dbt_dwh', 'sf_orders') }}会直接生成正确的dwh_dev.sf_orders引用,无需修改模型代码。
方案B:自定义宏替代ref(灵活适配特殊场景)
在dbt_project1中创建宏macros/ref_dwh.sql:
{% macro ref_dwh(model_name) %} -- 根据当前target环境映射dwh的schema {% set env_suffix = target.name.split('_')[1] %} {% set dwh_schema = 'dwh_' ~ env_suffix %} {{ adapter.quote(dwh_schema) }}.{{ adapter.quote(model_name) }} {% endmacro %}
使用时替换原ref调用:
SELECT * FROM {{ ref_dwh('sf_orders') }}
问题2:强制使用dbt_dwh模型的默认配置
在dbt_project1的dbt_project.yml中添加配置,禁用当前项目对dbt_dwh模型的配置继承:
models: dbt_dwh: +inherit_config: false
此配置会让dbt_dwh中的模型完全使用自身定义的config参数(如materialized='table'),不会被当前项目的全局配置覆盖,保留原模型的默认行为。
内容的提问来源于stack exchange,提问作者Arthur

