데이터 기반 모듈 만들기

Cortex Framework는 SAP (cortex.sap)와 같은 엔터프라이즈 ERP 시스템을 위한 기본 제공 데이터 기반 모듈을 제공하지만 커스텀 네임스페이스 내에서 새로운 커스텀 데이터 기반 모듈을 만들 수도 있습니다. 이렇게 하면 커스텀 빌드 동작을 정의하고 새로운 소스 시스템으로 지원을 확장할 수 있습니다. 여기에는 원시 데이터를 BigQuery로 복제하는 PostgreSQL, MySQL 등과 같은 데이터베이스 관리 시스템이 포함될 수 있습니다.

이 가이드에서는 데이터 (customers, tickets, ticketlogitem 테이블)가 PostgreSQL 데이터베이스에서 ticketing_data_raw라는 원시 BigQuery 데이터 세트로 복제된 고객 서비스 티켓팅 시스템 을 위한 새로운 데이터 기반 모듈을 만드는 엔드 투 엔드 예를 안내합니다.

커스텀 데이터 기반 모듈을 만들 때는 Cortex Framework 아티팩트에서 확장 프로그램과 맞춤설정을 분리하여 수명 주기 관리를 개선하기 위해 전용 커스텀 네임스페이스를 사용하는 것이 좋습니다.

예시 시나리오 개요

이 둘러보기에서는 다음 작업을 수행합니다.

  1. 데이터 기반 애셋을 격리하기 위해 전용 커스텀 네임스페이스 ticketing을 만듭니다.
  2. 경로 ticketing.ticketing.foundations.ticketing_system의 새 데이터 기반 모듈을 정의합니다.
  3. customers, tickets, ticketlogitem 테이블의 테이블 설정 (table_settings.default.yaml)을 구성합니다.
  4. 각 테이블에 열 및 필드 수준 메타데이터 주석을 만듭니다.
  5. config/config.yaml에서 원시 데이터 소스 (ticketing_data_raw), 대상 정규화된 데이터 세트 (data_foundation_ticketing), 새 기반 모듈을 등록합니다.

모듈 폴더 및 파일 구조

새 데이터 기반 모듈의 모든 실제 파일은 src/data_modules/ 아래의 커스텀 네임스페이스 내에 있습니다. 다음 표와 디렉터리 트리는 각 파일을 배치할 위치를 간략하게 보여줍니다.

config/
└── config.yaml                                           # Global configuration & module registration
src/data_modules/ticketing/ticketing/foundations/ticketing_system/
├── manifest.yaml                                         # Declares module category, type, and builder
├── table_settings.default.yaml                           # Table materialization, bigQueryLabels, dataformTags, and layouts
├── builder.py                                            # (Optional) Custom Dataform generator class for this module
└── annotations/                                          # Field and column-level schema descriptions
    ├── customers.yaml
    ├── tickets.yaml
    └── ticketlogitem.yaml

중요: 시작하기 전에 처리할 소스 테이블이 원시 레이어 데이터 세트에 있는지 확인합니다.

파일 또는 디렉터리 경로 목적 및 설명
config/config.yaml ticketing 네임스페이스, PostgreSQL 원시 데이터 소스, 대상 BigQuery 데이터 세트, 기반 모듈 인스턴스를 등록합니다.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml 컴파일 중에 사용되는 모듈 메타데이터, 표시 이름, 카테고리 (예: foundation), 모듈 유형 (예: generic), 생성기 빌더 클래스를 선언합니다.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml BigQuery 최적화 dataformTags, bigQueryLabels, 파티션 세부정보, 클러스터 세부정보와 함께 ticketing_data_raw의 정규화해야 하는 소스 테이블을 구성합니다.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/*.yaml 테이블 및 필드 정의를 설명하는 다양한 YAML 메타데이터를 포함합니다. 이러한 메타데이터는 컴파일된 Dataform 정의에 자동으로 병합되므로 BigQuery 테이블 메타데이터에 설명이 유지됩니다.
src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py 선택사항. 컴파일 중에 소스 데이터베이스에 커스텀 데이터 정리 또는 언어별 SQL 변환이 필요한 경우 여기에서 모듈 수준 빌더 클래스를 정의할 수 있습니다.

1단계: config.yaml에서 네임스페이스, 데이터 소스, 대상을 등록합니다.

실제 파일을 만들기 전에 배포 구성 파일 (config/config.yaml)을 열고 커스텀 네임스페이스, 원시 PostgreSQL 소스 데이터 세트, 정규화된 테이블이 생성될 대상 데이터 세트를 선언합니다.

data:
  namespaces:
    - name: cortex
      path: ../src/data_modules/cortex
    - name: ticketing                              # <-- Name of custom namespace
      path: ../src/data_modules/ticketing          # <-- Points to subdirectory under 'src/data_modules/'

  datasets:
    - id: ticketing_data_raw                       # <-- Unique source ID
      projectId: "source_project_id"
      datasetId: ticketing_data_raw                # <-- Raw dataset containing PostgreSQL replication tables
    - id: data_foundation_ticketing                # <-- Unique target ID
      projectId: "target_project_id"
      datasetId: data_foundation_ticketing         # <-- Target dataset for conformed foundation tables

2단계: config.yaml에서 데이터 기반 모듈을 등록합니다.

config/config.yamldata.modules.foundations 섹션에서 데이터 소스 (ticketing_data_raw)를 데이터 대상 (data_foundation_ticketing)에 연결하여 새 데이터 기반 모듈 인스턴스를 등록합니다.

data:
  modules:
    foundations:
      - moduleId: ticketing_foundation
        modulePath: ticketing.ticketing.foundations.ticketing_system   # Format: {namespace}.{systemtype}.{module_type:foundations}.{subsystemtype}
        dataSourceId: ticketing_data_raw
        dataTargetId: data_foundation_ticketing
        # Custom table settings file relative to 'config/' directory
        # Recommended path: '{namespace_dir}/{system_type}/foundations/{system_sub_type}/table_settings.yaml'
        # If omitted, defaults to "../src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml"
        tableSettings: "ticketing/ticketing/foundations/ticketing_system/table_settings.yaml"

3단계: 모듈 매니페스트 파일 만들기

모듈 메타데이터를 선언하는 매니페스트 파일 src/data_modules/ticketing/ticketing/foundations/ticketing_system/manifest.yaml을 만듭니다.

displayName: Ticketing System Data Foundation
description: Conformed foundation tables for PostgreSQL raw ticketing database.
category: foundation
type: generic
builder: ticketing_foundation

4단계: 테이블 설정 파일 (table_settings.default.yaml) 만들기

기본 테이블 구성 파일 src/data_modules/ticketing/ticketing/foundations/ticketing_system/table_settings.default.yaml을 만듭니다. 이 파일은 복제된 PostgreSQL 테이블 (customers, tickets, ticketlogitem)이 BigQuery 내에서 구체화, 파티션 나누기, 클러스터링되는 방식을 정의합니다.

common:
  - source:
      tableName: customers
    target:
      bigQueryLabels:
        - key: data_class
          value: master
      dataformTags: [ticketing, foundation, masterdata]
      clusterDetails:
        columns: [customer_id]

  - source:
      tableName: tickets
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: created_at
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, customer_id]

  - source:
      tableName: ticketlogitem
    target:
      bigQueryLabels:
        - key: data_class
          value: transactional
      dataformTags: [ticketing, foundation, transactional]
      partitionDetails:
        column: log_timestamp
        partitionType: time
        timeGrain: day
      clusterDetails:
        columns: [ticket_id, log_id]

5단계: 필드 수준 메타데이터 주석 만들기

정규화된 테이블에 BigQuery의 명확한 문서가 포함되도록 하려면 src/data_modules/ticketing/ticketing/foundations/ticketing_system/annotations/ 내의 각 테이블에 주석 YAML 파일을 만듭니다. 파일 이름은 소스 테이블 이름과 정확히 일치해야 합니다.

annotations/customers.yaml

description: "Customer master data conformed from PostgreSQL raw ticketing database."
fields:
  - name: "customer_id"
    description: "Unique customer identifier, PK"
  - name: "email"
    description: "Primary email address associated with the customer"
  - name: "full_name"
    description: "Customer full name or account contact name"
  - name: "created_at"
    description: "Timestamp when the customer record was originally created in PostgreSQL"

annotations/tickets.yaml

description: "Customer service tickets conformed from PostgreSQL raw ticketing database."
fields:
  - name: "ticket_id"
    description: "Unique ticket identifier, PK"
  - name: "customer_id"
    description: "Foreign key referencing customers.customer_id"
  - name: "subject"
    description: "Summary or subject line of the customer inquiry"
  - name: "status"
    description: "Current ticket lifecycle status (e.g., OPEN, IN_PROGRESS, RESOLVED, CLOSED)"
  - name: "priority"
    description: "Priority severity level (e.g., LOW, MEDIUM, HIGH, URGENT)"
  - name: "created_at"
    description: "Timestamp when the ticket was created"
  - name: "updated_at"
    description: "Timestamp when the ticket was last modified"

annotations/ticketlogitem.yaml

description: "Audit log history and activity events for customer service tickets."
fields:
  - name: "log_id"
    description: "Unique log event identifier, PK"
  - name: "ticket_id"
    description: "Foreign key referencing tickets.ticket_id"
  - name: "action"
    description: "Action or event performed on the ticket"
  - name: "description"
    description: "Notes and description on performed events on the ticket"
  - name: "performed_by"
    description: "User, agent, or automated system that performed the action"
  - name: "log_timestamp"
    description: "Exact timestamp when the activity log event occurred"

6단계: (선택사항) 커스텀 기반 빌더 정의

PostgreSQL 데이터 기반에 컴파일 중에 로직 (예: 자동 데이터 유형 변환, 타임스탬프 변환 또는 모든 테이블의 데이터 정리 규칙)이 필요한 경우 이 모듈로 범위가 지정된 커스텀 빌더를 정의할 수 있습니다.

src/data_modules/ticketing/ticketing/foundations/ticketing_system/builder.py를 만듭니다.

import logging
import pathlib
import yaml
from common.builders.base import FoundationBuilder, Source
from common.registry import builder_registry
from common.schemas import config_schema, manifest_schema

logger = logging.getLogger(__name__)

@builder_registry.register("ticketing_foundation")
class TicketingFoundationBuilder(FoundationBuilder[config_schema.BaseModuleConfig]):
    """Custom Dataform generator for PostgreSQL ticketing data foundation."""

    def build(
        self,
        *,
        module_id: str,
        module_config: config_schema.BaseModuleConfig,
        global_config: config_schema.GlobalConfig,
        manifest: manifest_schema.ManifestConfig,
        base_dir: pathlib.Path,
        annotations_dir: pathlib.Path,
        output_dir: pathlib.Path,
        module_dir_name: str,
        sources_registry: set[Source],
        table_settings_file: pathlib.Path | None = None,
        required_tables: set[str] | None = None,
    ) -> None:
        logger.info("Building ticketing data foundation for module: %s", module_id)
        
        # 1. Load table settings
        if not table_settings_file or not table_settings_file.exists():
            logger.warning("No valid table settings found for %s", module_id)
            return

        with open(table_settings_file, encoding="utf-8") as f:
            settings = yaml.safe_load(f) or {}

        tables = settings.get("common", [])
        source_config = global_config.get_data_source(module_config.data_source_id)
        target_dataset = global_config.get_data_target(module_config.data_target_id)

        # 2. Generate Dataform .sqlx files for each table
        for table_item in tables:
            source_table = table_item["source"]["tableName"]
            if required_tables and source_table not in required_tables and not table_item.get("deployAlways"):
                continue

            # Register source table for centralized source generation
            sources_registry.add(Source(source_config.project_id, source_config.dataset_id, source_table))

            # Retrieve labels if configured
            bigquery_config = {}
            if "bigQueryLabels" in table_item["target"]:
                labels_dict = {label["key"]: label["value"] for label in table_item["target"]["bigQueryLabels"]}
                bigquery_config["labels"] = labels_dict

            dataform_tags = table_item["target"].get("dataformTags", ["ticketing", "foundation"])

            sqlx_content = f"""config {{
  type: "table",
  schema: "{target_dataset.dataset_id}",
  name: "{source_table}",
  tags: {dataform_tags}"""
            
            if bigquery_config:
                sqlx_content += f",\n  bigquery: {bigquery_config}"
                
            sqlx_content += f"""
}}

SELECT *
FROM `${{source_config.project_id}}.${{source_config.dataset_id}}.{source_table}`
"""
            out_file = output_dir / f"{source_table}.sqlx"
            out_file.write_text(sqlx_content, encoding="utf-8")
            logger.info("Generated %s", out_file)

새 기반 모듈 확인

새로 만든 데이터 기반 모듈을 확인하고 배포하려면 다음 단계를 따르세요.

  1. Cortex Framework 빌드 및 배포 스크립트: bash uv run cortex-build-and-deploy --config "config/config.yaml"를 실행합니다.
  2. Dataform 컴파일이 오류 없이 성공했고 .sqlx 스크립트가 customers, tickets, ticketlogitem에 대해 생성되었는지 확인합니다.
  3. 배포 후 단계에 따라 Dataform 파이프라인 작업을 실행하고 BigQuery의 data_foundation_ticketing 데이터 세트 내에서 정규화된 레코드를 확인합니다.

커스텀 데이터 기반 모듈이 컴파일되고 배포되는지 확인하려면 데이터 제품 확장성 페이지의 확인 섹션을 참고하세요.