dremio dbt 模型处理简单说明

dremio dbt adapter 在设计的时候与传统adapter 稍有不同,比如里边调整了database 名称的处理,同时因为dremio 的特殊性
对于物化的处理是先物化然后创建一个视图(table 模式的) 对于我们实际使用到的数据是在dremio 的space (或者nessie 数据源)中
以下进行一个简单的说明

dremio dbt 配置

一个参考配置,可以看到我们需要对象存储的信息,以及space 信息(当然也可以全部使用nessie 进行纳管)

 
dremio:
  outputs:
    dev:
      password: <password>
      port: <port>
      software_host: <host>
      object_storage_source: s3 # s3 source
      object_storage_path:  dbt # 建议s3 bucket
      dremio_space: nessie  # nessie 的source
      dremio_space_folder: dbtv2.biz # nessie 的folder
      threads: 3
      type: dremio
      use_ssl: false
      user:  <user>
  target: dev

database 以及schema 的调整

进行了重写,会基于配置的信息(对象存储以及space), 主要是基于dbt 的macro
database 的处理

{% macro dremio__generate_database_name(custom_database_name=none, node=none) -%}
  {%- set default_database = target.database if not is_datalake_node(node)
    else target.datalake -%}
  {%- set custom_database_name = custom_database_name if not is_datalake_node(node)
    else node.config.datalake -%}
  {{ generate_database_name_impl(default_database, custom_database_name, node) }}
{%- endmacro %}
 
{% macro generate_database_name_impl(default_database, custom_database_name=none, node=none) -%}
  {%- if custom_database_name is none -%}
 
      {{ default_database }}
 
  {%- else -%}
 
      {{ custom_database_name }}
 
  {%- endif -%}
{%- endmacro %}

schema 类似
实际对象存储中的数据才是我们可以进行实际操作的(比如crud),当然实际使用的业务数据可以通过source 配置

物化处理

物化实际上包含了多种模式比如view,table,当然dremio 还支持自己特有的反射,对于view 以及table 的处理dremio 使用了
多次执行模式(不像传统adapter),先是在对象存储中创建一个必须的,然后是在space 中创建对应的vds ,view 模式的与dbt
的类似,对于table 模式的会先按照类似dbt 的物化表模式,然后同时还会创建一个vds,dremio dbt 中的macro

  • view 处理
{% materialization view, adapter='dremio' %}
  {%- set identifier = model['alias'] -%}
  {%- set twin_strategy = config.get('twin_strategy', validator=validation.any[basestring]) or 'clone' -%}
  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}
 
  {%- set exists_as_view = (old_relation is not none and old_relation.is_view) -%}
 
  {%- set target_relation = api.Relation.create(
      identifier=identifier, schema=schema, database=database, type='view') -%}
 
  {% set grant_config = config.get('grants') %}
 
  {{ run_hooks(pre_hooks) }}
 
  -- If there's a table with the same name and we weren't told to full refresh,
  -- that's an error. If we were told to full refresh, drop it. This behavior differs
  -- for Snowflake and BigQuery, so multiple dispatch is used.
  {%- if old_relation is not none and old_relation.is_table -%}
    {{ handle_existing_table(should_full_refresh(), old_relation) }}
  {%- endif -%}
 
  -- build model
  {% call statement('main') -%}
    {{ create_view_as(target_relation, external_query(sql)) }}
  {%- endcall %}
   # 应用策略
  {{ apply_twin_strategy(target_relation) }}
 
  {{ enable_default_reflection() }}
 
  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}
 
  {{ run_hooks(post_hooks) }}
 
  {{ return({'relations': [target_relation]}) }}
 
{% endmaterialization %}
  • table
    实际上与view 类似
{% materialization table, adapter = 'dremio' %}
 
  {%- set identifier = model['alias'] -%}
  {%- set format = config.get('format', validator=validation.any[basestring]) or 'iceberg' -%}
  {%- set old_relation = adapter.get_relation(database=database, schema=schema, identifier=identifier) -%}
  {%- set target_relation = api.Relation.create(identifier=identifier,
                                                schema=schema,
                                                database=database,
                                                type='table') -%}
  {% set grant_config = config.get('grants') %}
  {{ run_hooks(pre_hooks) }}
 
  -- setup: if the target relation already exists, drop it
  -- in case if the existing and future table is delta, we want to do a
  -- create or replace table instead of dropping, so we don't have the table unavailable
  {% if old_relation is not none -%}
    {{ adapter.drop_relation(old_relation) }}
  {%- endif %}
 
  -- build model
  {% call statement('main') -%}
    {{ create_table_as(False, target_relation, external_query(sql)) }}
  {%- endcall %}
 
  {{ refresh_metadata(target_relation, format) }}
 
  {{ apply_twin_strategy(target_relation) }}
 
  {% do persist_docs(target_relation, model) %}
 
  {% do apply_grants(target_relation, grant_config, should_revoke=should_revoke) %}
 
  {{ run_hooks(post_hooks) }}
 
  {{ return({'relations': [target_relation]})}}
 
{% endmaterialization %}

apply_twin_strategy 对于dremio 的table 模式物化很重要,处理如下,当然view 也是会执行这个的

{%- macro apply_twin_strategy(target_relation) -%}
  {%- set twin_strategy = config.get('twin_strategy', validator=validation.any[basestring]) or 'clone' -%}
  {%- if target_relation.type == 'view' -%}
    {%- if twin_strategy != 'allow' -%}
      {%- set table_relation = api.Relation.create(
          identifier=generate_alias_name_impl(model.name, config.get('file', validator=validation.any[basestring]), model),
          schema=generate_schema_name_impl(target.root_path, config.get('root_path', validator=validation.any[basestring]), model),
          database=generate_database_name_impl(target.datalake, config.get('datalake', validator=validation.any[basestring]), model),
          type='table') -%}
      {{ adapter.drop_relation(table_relation) }}
    {%- endif -%}
  {%- elif target_relation.type == 'table' -%}
    {%- if twin_strategy in ['prevent', 'clone'] -%}
      {%- set view_relation = api.Relation.create(
          identifier=generate_alias_name_impl(model.name, config.get('alias', validator=validation.any[basestring]), model),
          schema=generate_schema_name_impl(target.schema, config.get('schema', validator=validation.any[basestring]), model),
          database=generate_database_name_impl(target.database, config.get('database', validator=validation.any[basestring]), model),
          type='view') -%}
      {%- if twin_strategy == 'prevent' -%}
        {{ adapter.drop_relation(view_relation) }}
      {%- elif twin_strategy == 'clone' -%}
        {%- set sql_view -%}
          select *
          from {{ render_with_format_clause(target_relation) }}
        {%- endset -%}
        {% call statement('clone_view') -%}
          # 对于table 模式的关系会进行vds 的创建,这个也是我们看到的尽管是物化table,但是模型都会在一个space 中
          {{ create_view_as(view_relation, sql_view) }}
        {%- endcall %}
      {%- endif -%}
    {%- endif -%}
  {%- endif -%}
{%- endmacro -%}

说明

dremio dbt adapter 在处理上重写了不少dbt macro,确保创建的模型都会在space 中存在,对于数据的物化是在对象存储中的,比较符合dremio 的玩法,当然对于基于了nessie catalog 数据源,那么我们就可以all-in-one 了就类似普通的数据库了,以上是一个简单介绍说明下
dremio dbt 实现上的一些细节,方便学习使用,当然官方也有一个简单的使用介绍可以参考

参考资料

https://github.com/dremio/dbt-dremio
https://www.dremio.com/blog/using-dbt-to-manage-your-dremio-semantic-layer/

posted on 2024-04-19 06:59  荣锋亮  阅读(12)  评论(0编辑  收藏  举报

导航