dbt-osmosisで遊んでみる


## dbt-osmosisとは
`dbt-osmosis`とは、上流テーブルのカラムのdescriptionやデータ型を下流へ継承(※)してくれるツールです。
本記事では、`dbt-osmosis`のインストールから挙動の検証を行います。

### 継承
ドキュメントより抜粋

:::note
`dbt-osmosis`の最も強力な機能の 1 つは、複数レベルの列ドキュメントの継承です。つまり、列に関連するすべてのタグ、description、メタフィールドを、任意の上流ノードから現在のモデルにカスケードできます。
:::

https://z3z1ma.github.io/dbt-osmosis/docs/intro

## 動作環境
DBはpostgresqlを利用しています。
``` sh
$ psql -V
psql (PostgreSQL) 14.15 (Ubuntu 14.15-0ubuntu0.22.04.1)

$ dbt -V
Core:
  - installed: 1.9.2

Plugins:
  - postgres: 1.9.0 - Up to date!

$ dbt-osmosis --version
dbt-osmosis, version 1.1.13
```

## ディレクトリ構造
過去の記事で作成したプロジェクトをもとに`dbt-osmosis`の検証を行っていきます。

https://qiita.com/s_rokuemon/items/cad73651613b82d647be

```
.
├── dbt_project.yml
├── models
│   ├── intermediates
│   │   └── marketing
│   │       ├── _int_marketing__models.yml
│   │       ├── int_dim_customers.sql
│   │       ├── int_dim_dates.sql
│   │       ├── int_dim_products.sql
│   │       └── int_fact_sales.sql
│   ├── marts
│   │   └── marketing
│   │       ├── _marketing__models.yml
│   │       └── obt_sales.sql
│   └── staging
│       └── adventureworks
│           ├── _adventureworks__models.yml
│           ├── _adventureworks__sources.yml
│           ├── stg_adventureworks__stg_addresses.sql
│           ├── stg_adventureworks__stg_customers.sql
│           ├── stg_adventureworks__stg_dates.sql
│           ├── stg_adventureworks__stg_order_details.sql
│           ├── stg_adventureworks__stg_order_headers.sql
│           └── stg_adventureworks__stg_products.sql
├── seeds
│   └── adventureworks
│       ├── _adventureworks__seed.yml
│       ├── raw_addresses.csv
│       ├── raw_customers.csv
│       ├── raw_dates.csv
│       ├── raw_order_details.csv
│       ├── raw_order_headers.csv
│       └── raw_products.csv
```

## パッケージのインストールと設定
コマンド1つでインストールができます！
```python
pip install dbt-osmosis
```

続いて、dbt_project.ymlに`dbt-osmosis`の設定を追加します。

```dbt_project.yml
models:
  dbt_modeling: # プロジェクト名
    staging: # サブディレクトリ名
      adventureworks:
        +materialized: view
        +dbt-osmosis: "_adventureworks__models.yml" # "_{model}.yml"
        +schema: stg_schema
    intermediates:
      marketing:
        +materialized: view
        +dbt-osmosis: "_int_marketing__models.yml"
        +schema: int_schema
    marts:
      marketing:
        +materialized: table
        +dbt-osmosis: "_marketing__models.yml"
        +schema: mart_schema
```

seedsも同様の記法で設定できます。
```yaml
seeds:
  dbt_modeling:
    adventureworks: # サブディレクトリ名
      +dbt-osmosis: "_adventureworks__seed.yml" 
```

### sources
オプションで`sources`も`dbt-osmosis`の配下に加えられます。
```yaml
vars:
  dbt-osmosis:
    sources:
      src_adventureworks: # sources.name属性と一致させる
        path: "staging/adventureworks/_adventureworks__sources.yml"
```
`sources`を`dbt-osmosis`管理配下に追加する方法に関するはこちらです。

https://z3z1ma.github.io/dbt-osmosis/docs/tutorial-yaml/configuration#sources

## dbt-osmosisの挙動を確認する
挙動を確認してみます！

```sh
$ dbt-osmosis yaml refactor
```

### before
```_int_marketing__models.yaml
version: 2
models:
  - name: int_dim_dates
    columns:
      - name: date_key
      - name: date
      - name: day_of_week
      - name: month
      - name: year

```

### after
`sources`で定義した、`data_type`と`description`が伝播していることがわかります！
```diff
# _int_marketing__models.yaml
version: 2
models:
  - name: int_dim_dates
    columns:
      - name: date_key
        # models.sql内でcastしたデータ型が反映されている
+       data_type: bigint
      - name: date
+       data_type: date
        # sourcesレイヤ（中間層よりも上流)で定義したdescriptionが継承されている
+       description: add_description_from_sources:The date of the order 
      - name: day_of_week
+       data_type: character varying
      - name: month
+       data_type: integer
      - name: year
+       data_type: integer

```

### 動かしながらわかってきたこと
- モデル内で明示的に`CAST`することで、そのデータ型が`schema.yml`に反映されます
    - この際、`dbt run`を事前に実行し、モデルを実体化しておく必要があります
```sql
with stg_dates as (
    select 
        date
        , day_of_week
        , month::smallint
        , year
    from {{ source('public','raw_dates') }}
)
select * from stg_dates
```
```diff
version: 2
models:
  - name: stg_jaffle_shop__stg_dates
    columns:
      - name: month
-        data_type: integer
+        data_type: smallint
    ...
```
- `sedds.yml`内でカラムのメタデータとして`description`を定義しても、下流の`sources.yml`へ伝播されない？？
    - これはどうやってもうまくいきませんでした。検証の仕方がダメなのか。。。
<br>

- 下記ドキュメントの通りDB側で`description`を追加して`dbt-osmosis`を実行してみましたが、`sources.yml`内で自動で生成されることはありませんでした。
    - Postgresql以外のDBエンジンではうまくいかも？
 > ソース yaml ファイルはデータベースから生成されます。スキーマ yaml ファイルは、継承されたメタデータを使用して dbt モデルから生成されます。

- `sedds.yml`と`sources.yml`内では`columns`の属性として`data_type`は存在しないが、推測されたデータ型が付与される
    - 存在しないプロパティが自動で付与されるのは挙動的に気持ち悪い...
```diff
version: 2
sources:
  - name: public
    tables:
      - name: raw_dates
        columns:
          - name: date
            description: add_description_from_sources:The date of the order
+           data_type: date
          - name: day_of_week
+           data_type: character
          - name: month
+           data_type: integer
          - name: year
+           data_type: integer
```

- model contractsの補完と伝播
    - typeを入力しておくだけで、それ以外のプロパティを勝手に補完してくれる
    - ただし下流のモデルに`constraints`は伝播しない
```diff
# _jaffle_shop__models.yml
version: 2
models:
  - name: stg_jaffle_shop__stg_dates
    config:
      constract:
        enforced: true
    columns:
      - name: date
        description: add_description_from_sources:The date of the order
        data_type: date
        constraints:
          - type: not_null
          　# typeを入力しておくだけで、それ以外のプロパティを勝手に補完してくれる
+           name:
+           expression:
+           warn_unenforced: true
+           warn_unsupported: true
+           to:
+           to_columns: []
```

```diff
# _int_marketing__models.yml
version: 2
models:
  - name: int_dim_dates
    config:
      constract:
        enforced: true
    columns:
      - name: date_key
        data_type: smallint
      - name: date
        description: add_description_from_sources:The date of the order
        data_type: date
        # 下流のモデルにconstraintsは伝播しない
```

## 最後に
まだまだ勉強途中のため内容に誤りがあれば申し訳ありません。ご指摘いただけますと幸いです。

扱いが難しい挙動はあるものの、メタデータ管理を楽にする強力なツールだと思いました！

検証しきれていないコマンドやオプションがまだまだあるので、それらについても調べて記事を更新していきたいと思います。


## ドキュメント

https://z3z1ma.github.io/dbt-osmosis/docs/intro/