AWS 기술 블로그

HAQM DataZone에서 Custom Asset Type을 활용하여 외부 자산(Tableau) 통합 및 데이터 계보 관리하기

배경

데이터 중심 조직은 AWS 내 서비스와 Tableau, MicroStrategy 같은 외부 BI 도구를 함께 활용하는 하이브리드 환경에서 운영되는 경우가 많습니다. 이러한 환경에서 조직들은 다음과 같은 니즈를 가지고 있습니다.

  • 통합 데이터 자산 카탈로그 : Tableau 대시보드와 같은 외부 자산도 함께 등록하여 모든 데이터 자산을 한 곳에서 검색 및 관리
  • End-to-End 데이터 계보(Lineage) : Tableau 대시보드가 어떤 데이터 소스를 활용하는지, 특정 데이터 세트가 어떤 외부 보고서에 활용되는지 등 계보를 추적
  • 전체 데이터 자산의 거버넌스 : AWS와 외부 시스템을 포괄하는 일관된 메타데이터 관리 및 거버넌스 체계 확립

HAQM DataZone은 기본적으로 AWS 내 데이터 자산을 위한 강력한 카탈로그 솔루션을 제공하지만, Custom Asset Type 기능을 활용하면 외부 BI 도구의 자산까지 효과적으로 통합 관리할 수 있습니다. 이 블로그에서는 이 기능을 활용하여 Tableau와 같은 외부 BI 도구의 대시보드를 데이터 자산으로 등록하고, AWS 데이터 소스와의 계보 관계를 시각화하는 End-to-end 솔루션을 구축하는 방법을 단계별로 설명합니다. 이 접근 방식을 통해 조직은 데이터 소스부터 최종 시각화까지의 전체 데이터 흐름을 파악하고, AWS 내부와 외부 시스템의 모든 데이터 자산을 한 곳에서 통합적으로 관리할 수 있게 됩니다.

솔루션 구현 단계 및 아키텍처

이 블로그에서는 다음 단계를 따라 솔루션을 구현합니다.

  1. Custom Asset Type 생성 (Tableau 대시보드를 표현할 Custom Asset Type 정의)
  2. Tableau 대시보드를 Custom Asset으로 등록
  3. 자산의 비즈니스 메타데이터 업데이트 (메타데이터 양식 및 용어집 활용)
  4. 자산 식별자 업데이트 (데이터 계보 작성을 위한 준비)
  5. OpenLineage 이벤트를 활용한 데이터 계보 구성

그리고, 이 블로그에서 구현한 솔루션 아키텍처는 다음과 같습니다.

위 아키텍처는 HAQM DataZone과 Tableau 간의 통합 구성을 보여줍니다. 이 솔루션은 Tableau Server에 있는 대시보드 정보를 AWS로 가져와 HAQM DataZone에서 관리할 수 있도록 합니다.

  1. Tableau Server Repository (meta DB) : PostgreSQL 데이터베이스로 Tableau 대시보드 메타데이터를 저장합니다. 보안 연결을 위해 VPN 연결과 게이트웨이를 통해 AWS 환경과 통신합니다.
  2. AWS Lambda 함수 : Tableau 메타데이터를 HAQM DataZone 자산으로 변환하는 비즈니스 로직을 처리합니다. 주요 작업으로는 HAQM DataZone에 대시보드 자산 생성 및 메타데이터 업데이트, 계보 이벤트를 게시합니다.
  3. HAQM EventBridge: Lambda 함수를 정기적으로 실행하여 대시보드 정보를 동기화합니다.
  4. HAQM DataZone: Custom Asset Type을 정의하고, 외부 대시보드를 데이터 자산으로 등록하며, 데이터 계보를 시각화합니다.
  5. AWS Secrets Manager : Tableau 데이터베이스 접속 정보를 안전하게 저장합니다.

사전 준비사항

다음과 같은 사항이 사전에 준비되어야 합니다.

  • Tableau 서버가 설치되어 있어야 합니다.
  • 설치된 Tableau 서버에 접근 가능한 네트워크가 준비되어 있어야 합니다.
  • HAQM DataZone의 도메인과 데이터 소스로 사용될 자산들이 등록되어 있어야 합니다.
  • CloudShell에서 HAQM DataZone API를 실행할 수 있는 AWS IAM Role이 생성되어 있어야 합니다. (이 AWS IAM Role은 HAQM DataZone 프로젝트에서 자산을 생성하고 수정할 권한이 필요하므로, 최소한 프로젝트 기여자로 등록되어야 합니다.)

단계 1: Custom Asset Type 생성 및 자산 등록

HAQM DataZone을 사용하기 위해서는 먼저 도메인에 접속하고 프로젝트를 생성해야 합니다.

HAQM DataZone 도메인 접속 및 프로젝트 생성

이 단계에서는 HAQM DataZone 도메인에 접속하고 Tableau 대시보드를 관리할 프로젝트를 생성합니다

1. HAQM DataZone 콘솔에서 데이터 포털 열기를 선택합니다.

2. 데이터 포털 메인 화면에서 프로젝트 생성을 선택합니다.

3. 프로젝트 생성 화면에서 다음 정보를 입력하고, 프로젝트 생성 버튼을 클릭합니다.

  • 이름: dashboard
  • 도메인 단위: 프로젝트를 생성할 도메인 단위 선택

4. 프로젝트가 아래와 같이 생성되면, 이제 Custom Asset Type을 정의하고 Tableau 대시보드를 자산으로 등록할 준비가 완료됩니다.

Custom Asset Type 생성

HAQM DataZone에서 Custom Asset을 생성하기 위해서는 먼저 Custom Asset Type을 정의해야 합니다.
1. dashboard 프로젝트 → 데이터 탭 → 데이터 관리 하위의 자산 유형을 선택합니다.
2. 자산 유형 화면에서 자산 유형 생성 버튼을 클릭합니다.

3. 새 자산 유형의 세부 정보를 다음과 같이 입력한 후, 만들기 버튼을 클릭합니다.

  • 이름: dashboard_asset_type (공백은 포함할 수 없습니다.)
  • 설명: 대시보드 자산 유형

Custom Asset 수동 등록

생성한 Custom Asset Type을 사용하여 자산을 수동으로 등록할 수 있습니다.

1. 데이터 탭 → 데이터 게시 하위의 데이터 소스를 선택합니다.
2. 데이터 소스 화면에서 우측 상단의 데이터 자산 생성 버튼을 클릭합니다.

3. 자산 정의는 아래와 같이 입력하고 생성합니다.

  • 이름: Sales Performance Dashboard (대시보드 이름)

  • 자산 유형: 위에서 생성한 dashboard_asset_type 선택

Custom Asset 자동 등록

위에서 Custom Asset을 수동으로 등록하는 방법을 설명했습니다. 실제 운영 환경에서는 이러한 자산을 자동으로 등록해야하기 때문에 자동화하기 위한 스크립트를 구성합니다. 이를 위해 브라우저 기반 Shell인 AWS CloudShell을 사용하여 HAQM DataZone에 생성한 프로젝트에 자산을 자동으로 등록하는 방법을 설명합니다. 코드에서 실행되는 과정은 아래와 같습니다.

  • Tableau 데이터베이스에서 대시보드 정보를 조회
    • Tableau 서버와 연동하여 직접 로드하는 경우, 아래 쿼리를 활용하여 등록된 모든 대시보드 정보를 로드할 수 있습니다.
query = """
    SELECT 
        w.id AS id,
        w.name AS name,
        w.created_at AS created_at,
        w.updated_at AS updated_at
    FROM _workbooks w
"""
    • 이 블로그 예제에서는 아래 Tableau 대시보드 정보를 가지고 자산을 생성합니다.
dashboards = [
    {
        'id': '1',
        'name': 'Sales Performance Dashboard',
        'created_at': datetime.now(),
        'updated_at': datetime.now()
    },
    # 추가 대시보드 데이터는 여기에 추가
]
  • Tableau에서 조회된 대시보드 정보를 기반으로 HAQM DataZone에 자산 생성을 생성합니다. CreateAsset API를 통해 자산을 생성할 수 있으며, typeIdentifier에는 단계 1에서 생성한 Custom Asset Type 이름을 입력해야 합니다.
# 자산 이름 설정
asset_name = dashboard_info['name']

# 자산 생성 API 호출
response = datazone_client.create_asset(
    domainIdentifier=DATAZONE_DOMAIN_ID,
    formsInput=[],
    name=asset_name,
    description='',
    owningProjectIdentifier=DATAZONE_PROJECT_ID,
    predictionConfiguration={
        'businessNameGeneration': {
            'enabled': False
        }
    },
    typeIdentifier=DATAZONE_ASSET_TYPE
)

이제 AWS CloudShell을 사용하여 자산을 등록해보겠습니다.
1. create_custom_asset.py 파일을 다운로드 합니다.
2. 다운로드한 파일에서 아래 부분에 자신의 환경에 맞는 파라미터 값을 입력하고 저장합니다.

AWS_REGION = '{AWS Region 입력}'
# HAQM DataZone의 도메인에서 생성한 dashboard 프로젝트를 클릭하면, 브라우저 주소창(URL)에서 <도메인 ID>와 <프로젝트 ID>를 확인할 수 있습니다. 
# 예시) http://<도메인 ID>.datazone.<Region>.on.aws/projects/<프로젝트 ID>/overview
DATAZONE_DOMAIN_ID = '{DataZone 도메인 ID 입력}' 
DATAZONE_PROJECT_ID = '{DataZone 프로젝트 ID 입력}'  
DATAZONE_ASSET_TYPE = 'dashboard_asset_type'        # 생성한 자산 유형 이름
DB_SECRET_NAME = ''                                 # (선택사항) Tableau 서버에 연결해서 대시보드 정보를 로드하기 위한 DB 연결 정보가 저장된 Secret 이름

3. HAQM DataZone 콘솔에서 AWS CloudShell을 실행합니다.

4. 작업 메뉴에서, 파일 업로드를 선택합니다.

5. create_custom_asset.py 파일을 업로드합니다.
6. 아래 명령어를 실행합니다.

python create_custom_asset.py

다음 결과가 표시됩니다. 다음 단계 실행을 위해 생성된 자산 ID를 미리 복사해둡니다.

자산이 생성되면 아래와 같이 dashboard_asset_type 유형의 Sales Performance Dashboard 자산을 확인할 수 있습니다.

단계 2: 자산의 비즈니스 메타데이터 업데이트

대시보드 자산을 등록했으니, 자산의 상세 화면에 메타데이터를 업데이트해야 합니다. 메타데이터를 업데이트하기 위해서는 표현 가능한 영역에 어떤 메타데이터를 보여줄지 먼저 정의하고, 정의한 내용을 기반으로 필요한 정보들을 로드하여 메타데이터를 구성합니다.

자산의 메타데이터 정의

HAQM DataZone 자산에는 다음과 같은 메타데이터 영역이 있습니다.

이미지의 위에서부터 순서대로 각 영역에 대한 설명은 아래와 같습니다.

  • Display 영역: 자산의 표시 이름, 설명 등 기본 정보를 표시합니다.
  • README 영역: 자산에 대한 상세 설명, 관련 문서 등을 마크다운 형태로 제공합니다.
  • 용어집 영역: 자산과 연결된 비즈니스 용어를 표시합니다.
  • 비즈니스 메타데이터 영역: 자산에 대한 추가 비즈니스 컨텍스트를 제공하는 커스텀 메타데이터를 표시합니다.

메타데이터 양식 및 용어집 생성

위에서 정의한 영역 중 비즈니스 메타데이터 영역과 용어집 영역은 다음과 같이 사전에 구성이 필요합니다.

용어집 생성

용어집 생성 및 용어 추가 방법에 대한 자세한 내용은 HAQM DataZone 용어집 관리 문서를 참조하세요.
1. dashboard 프로젝트 → 데이터 탭 → 데이터 관리 하위의 비즈니스 용어집을 선택합니다.
2. 그리고 화면의 용어집 생성 버튼을 클릭하여 새 용어집을 생성합니다.

  • 이름: bi_asset_glossary
  • 설명: BI 자산 관련 용어 모음

3. 생성한 용어집에 용어 생성 버튼을 클릭하여 하위 용어를 생성합니다.

  • BI 유형에 대한 용어
    • tableau: Tableau BI 도구
  • 비즈니스 도메인에 대한 용어
    • sales: 매출 및 판매 관련 데이터
    • customer: 고객 관계 및 서비스 관련 정보
    • operations: 운영 프로세스 및 자원 관리 데이터

메타데이터 양식 생성

메타데이터 양식 생성에 대한 자세한 내용은 HAQM DataZone 메타데이터 양식 생성 문서를 참조하세요.

1. dashboard 프로젝트 → 데이터 탭 → 데이터 관리 하위의 메타데이터 양식을 선택합니다.
2. 그리고 화면의 메타데이터 양식 생성 버튼을 클릭하여 새 메타데이터 양식을 생성합니다.

  • 표시 이름: BI 자산 비즈니스 메타데이터
  • 기술 이름: bi_asset_metadata
  • 설명: BI 자산 메타데이터 양식

3. 생성한 메타데이터 양식에 필드 생성 버튼을 클릭하여 하위 필드 목록을 생성합니다.

표시 이름 기술 이름 필드 유형
BI 유형 bi_type 용어집
비즈니스 도메인 biz_domain 용어집
주요 태그 tags 문자열
참고사항 notes 문자열
담당자 owner 문자열
마지막 업데이트 시점 last_timestamp 문자열

4. 메타데이터 양식 우측 상단에 활성화됨 버튼을 클릭하여 활성화 합니다.

메타데이터 업데이트

이 예제에서는 브라우저 기반 Shell인 AWS CloudShell을 사용하여 HAQM DataZone에 생성된 Tableau 대시보드 자산의 메타데이터를 자동으로 업데이트하는 명령을 실행합니다. 코드에서 실행되는 과정은 아래와 같습니다.

  • HAQM DataZone에서 용어집(glossary) 정보 조회
def get_glossary():
    all_items = []
    next_token = None
    search_params = {
        'domainIdentifier': DATAZONE_DOMAIN_ID,
        'searchScope': 'GLOSSARY_TERM'
    }
    
    # 페이지네이션을 처리하며 모든 용어집 용어 가져오기
    while True:
        if next_token:
            search_params['nextToken'] = next_token

        response = datazone_client.search(**search_params)
        all_items.extend(response['items'])

        if 'nextToken' not in response:
            break
        next_token = response['nextToken']

    # glossaryId로 그룹화
    glossary_groups = {}
    for item in all_items:
        glossary_id = item['glossaryTermItem']['glossaryId']
        if glossary_id not in glossary_groups:
            glossary_groups[glossary_id] = {}

        term_name = item['glossaryTermItem']['name']
        term_id = item['glossaryTermItem']['id']
        glossary_groups[glossary_id][term_name] = term_id

    # glossary 이름으로 매핑
    glossary_name_map = {}
    for glossary_id, terms in glossary_groups.items():
        glossary_info = datazone_client.get_glossary(
            domainIdentifier=DATAZONE_DOMAIN_ID,
            identifier=glossary_id
        )
        glossary_name = glossary_info['name']
        glossary_name_map[glossary_name] = terms

    return glossary_name_map
    • 용어집 이름과 ID가 다음과 같이 출력됩니다.
{
    'bi_asset_glossary': {
        'operations': 'cuh4fno8z7jo9k', 
        'customer': 'b2ii1tqs3xnx94', 
        'sales': 'bentq41a237gns', 
        'tableau': 'c5x1f99cmhvlso'
     }
}
  • Tableau 대시보드 메타 정보 로드
    • Tableau 서버와 연동하여 직접 로드하는 경우, 아래 쿼리를 활용하여 특정 대시보드의 사이트 정보, 소유자, 크기, URL 등 관련 메타 정보를 로드할 수 있습니다.
query = """
SELECT 
    s.name AS site_name,
    w.id AS id,
    w.name AS name,
    u.friendly_name AS owner,
    w.created_at AS created_date,
    w.updated_at AS last_updated_date,
    w.view_count AS total_views,
    ROUND(w.size / (1024.0 * 1024.0), 2) AS size,
    w.workbook_url AS url,
    w.description AS description
FROM _workbooks w
LEFT JOIN sites s ON w.site_id = s.id
LEFT JOIN _users u ON w.owner_id = u.id and w.site_id = u.site_id 
WHERE w.id = %s 
"""
    • 이번 예제에서는 아래와 같이 Tableau 대시보드의 예시 메타 정보를 활용합니다.
dashboard_info = {
    'site_name': 'sales',
    'id': '1',
    'name': 'Sales Performance Dashboard',
    'description': '목표 대비 판매 실적을 분석하고 매장별, 제품별, 기간별 성과를 시각화하는 대시보드',
    'owner': '영업팀_홍길동',
    'size': '3.1',
    'last_updated_date': '2025-04-11 08:30:00',
    # 비즈니스 메타데이터 
    'status_notes': '매일 새벽 3시에 전날 판매 데이터로 자동 업데이트됨',
    'biz_domain': 'sales',
    'tags': 'performance, targets, analytics, revenue'
}
  • 조회된 정보를 기반으로 HAQM DataZone 자산의 각 메타데이터 영역에 대한 폼을 구성합니다.
# 1. Display 이름 및 설명 설정
display_name = f"[{dashboard_info['site_name'].upper()}] {dashboard_info['name']}"
description = dashboard_info.get('description', '')

# 2. README 양식 업데이트
tableau_url = f"http://{TABLEAU_SERVER_URL}/#/site/{dashboard_info['site_name']}/workbooks/{dashboard_info['id']}/views"
readme_content = f"""## {dashboard_info['name']} ([바로가기]({tableau_url}))

`바로가기`를 클릭하면 해당 Tableau 페이지로 이동합니다.

## 정보
- **설명**: {description}
- **워크북 소유자**: {dashboard_info['owner']}
- **워크북 마지막 업데이트 시간**: {dashboard_info['last_updated_date']}
- **워크북 크기**: {dashboard_info['size']} MB
"""
readme_dict = {"readMe": readme_content}
readme_form = {
    "content": json.dumps(readme_dict, indent=2, ensure_ascii=False),
    "formName": "AssetCommonDetailsForm"
}

# 3. 비즈니스 메타데이터 양식 업데이트
biz_domain = dashboard_info.get('biz_domain', '')
tags = dashboard_info.get('tags', None)
notes = dashboard_info.get('status_notes', None)
bi_metadata = {
    "bi_type": [],
    "biz_domain": [],
    "tags": tags,
    "notes": notes,
    "owner": dashboard_info['owner'],
    "last_timestamp": datetime.now().isoformat()
}
# 용어집에서 해당하는 용어 ID 추가
if DATAZONE_GLOSSARY_NAME in glossary_terms:
    if 'tableau' in glossary_terms[DATAZONE_GLOSSARY_NAME]:
        tableau_term_id = glossary_terms[DATAZONE_GLOSSARY_NAME]['tableau']
        bi_metadata["bi_type"].append(tableau_term_id)
    if biz_domain and biz_domain in glossary_terms[DATAZONE_GLOSSARY_NAME]:
        domain_term_id = glossary_terms[DATAZONE_GLOSSARY_NAME][biz_domain]
        bi_metadata["biz_domain"].append(domain_term_id)
        
bi_metadata = {k: v for k, v in bi_metadata.items() if v} # None 값 제거
metadata_form = {
    "content": json.dumps(bi_metadata, indent=2, ensure_ascii=False),
    "formName": DATAZONE_METADATA_FORM_NAME,
    "typeIdentifier": DATAZONE_METADATA_FORM_NAME
}

# 4. 용어집 용어 설정
glossary_term_ids = []
if DATAZONE_GLOSSARY_NAME in glossary_terms:
    if 'tableau' in glossary_terms[DATAZONE_GLOSSARY_NAME]:
        glossary_term_ids.append(glossary_terms[DATAZONE_GLOSSARY_NAME]['tableau'])
    if biz_domain and biz_domain in glossary_terms[DATAZONE_GLOSSARY_NAME]:
        glossary_term_ids.append(glossary_terms[DATAZONE_GLOSSARY_NAME][biz_domain])
  • 자산의 메타데이터 폼 구성이 완료되면, CreateAssetRevision API를 통해 메타데이터를 업데이트 합니다.
response = datazone_client.create_asset_revision(
    identifier=asset_id,
    domainIdentifier=DATAZONE_DOMAIN_ID,
    formsInput=[readme_form, metadata_form],
    glossaryTerms=glossary_term_ids,
    name=display_name,
    description=description
)

이제 AWS CloudShell을 사용하여 자산을 등록해보겠습니다.

1. update_biz_metadata.py 파일을 다운로드 합니다.
2. 다운로드한 파일에서 아래 부분에 자신의 환경에 맞는 파라미터 값을 입력하고 저장합니다.

AWS_REGION = '{AWS Region 입력}'
DATAZONE_DOMAIN_ID = '{DataZone 도메인 ID 입력}' 
DATAZONE_PROJECT_ID = '{DataZone 프로젝트 ID 입력}'  
DATAZONE_GLOSSARY_NAME = 'bi_asset_glossary'        # 생성한 용어집 이름
DATAZONE_METADATA_FORM_NAME = 'bi_asset_metadata'   # 생성한 메타데이터 양식 이름
DB_SECRET_NAME = ''                                 # (선택사항) Tableau 서버에 연결해서 메타데이터를 로드하기 위한 DB 연결 정보가 저장된 Secret 이름
TABLEAU_SERVER_URL = 'tableau.server.com'           # (예시) Tableau 서버 접속을 위한 URL 정보

3. HAQM DataZone 콘솔에서 AWS CloudShell을 실행합니다.
4. 작업 메뉴에서, 파일 업로드를 선택합니다.
5. update_biz_metadata.py 파일을 업로드합니다.
6. 아래 명령어를 실행합니다.

python update_biz_metadata.py --asset-id {자산 ID 입력}

다음 결과가 표시됩니다.

Sales Performance Dashboard 자산의 상세화면은 정의한 메타데이터 영역대로 다음과 같이 업데이트 됩니다.

단계 3: Custom Asset 식별자 업데이트

데이터 계보를 구성하기 위해서는 먼저 자산의 소스 식별자를 업데이트해야 합니다. 소스 식별자는 OpenLineage 이벤트에서 데이터 계보 노드를 식별하는 데 사용됩니다. 코드에서 실행되는 과정은 아래와 같습니다.

  • 대시보드 이름과 ID를 결합하여 소스 식별자를 생성합니다.
# BI 타입을 namespace로, 대시보드 이름과 자산 ID를 name으로 구성
name = f"{asset_info['name']}_{asset_info['id']}"
source_identifier = f"{namespace}/{name}"
  • 등록된 자산의 소스 식별자를 업데이트하기 위해서는 기존 메타데이터 폼을 로드하여, 소스 식별자 부분만 수정하고 업데이트해야 합니다.
asset_info = datazone_client.get_asset(
    domainIdentifier=DATAZONE_DOMAIN_ID,
    identifier=asset_id
)
    • 자산의 메타데이터 폼(formsOutput)에서 소스 식별자가 저장된 AssetCommonDetailsForm을 업데이트 합니다.
# AssetCommonDetailsForm을 사용하여 소스 식별자 업데이트
forms_input = []

for form_output in asset_info['formsOutput']:
    # 원본 데이터를 변경하지 않기 위해 복사
    form_copy = form_output.copy()

    # typeRevision 필드 제거 (불필요)
    if 'typeRevision' in form_copy:
        del form_copy['typeRevision']

    # AssetCommonDetailsForm 양식 처리
    if form_copy['formName'] == 'AssetCommonDetailsForm':
        # typeName 필드 제거 (불필요)
        if 'typeName' in form_copy:
            del form_copy['typeName']

        # 소스 식별자 정보 추가
        content_dict = json.loads(form_copy['content'])
        content_dict['sourceIdentifier'] = source_identifier
        form_copy['content'] = json.dumps(content_dict, ensure_ascii=False)
    else:
        # 다른 양식의 경우 typeName을 typeIdentifier로 변경
        if 'typeName' in form_copy:
            form_copy['typeIdentifier'] = form_copy.pop('typeName')

    # 수정된 양식 추가
    forms_input.append(form_copy)
response = datazone_client.create_asset_revision(
    identifier=asset_id,
    domainIdentifier=DATAZONE_DOMAIN_ID,
    formsInput=forms_input,
    glossaryTerms=asset_info.get('glossaryTerms', []),
    name=asset_info['name'],
    description=asset_info.get('description', '')
)

publish_response = datazone_client.create_listing_change_set(
    action='PUBLISH',
    domainIdentifier=DATAZONE_DOMAIN_ID,
    entityIdentifier=asset_id,
    entityType='ASSET'
)

이제 AWS CloudShell을 사용하여 자산을 등록해보겠습니다.
1. update_source_identifier_of_asset.py 파일을 다운로드 합니다.
2. 다운로드한 파일에서 아래 부분에 자신의 환경에 맞는 파라미터 값을 입력하고 저장합니다.

AWS_REGION = '{AWS Region 입력}'
DATAZONE_DOMAIN_ID = '{DataZone 도메인 ID 입력}' 
DATAZONE_PROJECT_ID = '{DataZone 프로젝트 ID 입력}' 
TABLEAU_NAMESPACE = 'tableau'                       # Tableau 자산의 네임스페이스 기본값 

3. HAQM DataZone 콘솔에서 AWS CloudShell을 실행합니다.
4. 작업 메뉴에서, 파일 업로드을 선택합니다.
5. update_source_identifier_of_asset.py 파일을 업로드합니다.
6. 아래 명령어를 실행합니다.

python update_source_identifier_of_asset.py --asset-id {자산 ID 입력}

다음 결과가 표시됩니다.

Sales Performance Dashboard 자산의 상세화면에서 우측에 있는 자산 세부 정보에 아래와 같이 소스 ID 항목이 정의한 소스 식별자로 업데이트 된 것을 확인할 수 있습니다.

또한, 계보 탭으로 이동하면 데이터세트의 노드 이름이 소스 식별자에서 정의한 name 으로 표시됩니다.

단계4: 데이터 계보 작성 및 업데이트

HAQM DataZone은 OpenLineage 프레임워크 호환 이벤트를 사용하여 데이터 계보를 생성합니다. 이 예제는 Tableau 대시보드와 그 대시보드가 사용하는 원본 데이터 소스 간의 관계를 HAQM DataZone에 시각적으로 표현하기 위한 데이터 계보(Lineage)를 생성합니다. 코드에서 실행되는 과정은 아래와 같습니다.

  • 대시보드가 사용하는 데이터 소스 정보를 정의합니다. 이 부분은 Tableau 서버의 메타 DB에서 직접 로드할 수도 있지만, HAQM DataZone에 있는 기존 테이블 자산과 매핑하기 위해서는 반드시 namespace와 name의 조합인 소스 식별자를 동일하게 구성해야 합니다.
    • 아래 예시에는 총 3개의 데이터 소스가 정의되어 있으며, 이미 등록되어 있는 glue/biz.sales_analysisglue/biz.sales_target 테이블 자산과 외부 자산(HAQM DataZone에 등록되지 않은 자산) dw.product_info 테이블을 사용합니다.
datasources = [
    {
        'namespace': 'glue',
        'name': 'biz.sales_analysis'
    },
    {
        'namespace': 'glue',
        'name': 'biz.sales_target'
    },
    {
        'namespace': 'dw',
        'name': 'product_info'
    }
]
  • Input 노드 정의
# 입력 데이터셋 정의 (데이터 소스)
inputs = []
for source in datasources:
    # 기본 입력 데이터셋 정보
    input_dataset = {
        "namespace": source["namespace"],
        "name": source["name"]
    }

    # 소스 식별자 생성
    source_identifier = f'{source["namespace"]}/{source["name"]}'
    
    # 자산 ID 조회
    source_asset_id = get_asset_id_by_source_identifier(source_identifier, DATASOURCE_PROJECT_ID)

    # 자산 ID가 있는 경우 스키마 정보 추가
    if source_asset_id:
        asset_columns = get_asset_columns(source_asset_id)

        if asset_columns:
            # 컬럼 정보 변환 (OpenLineage 스키마에 맞게)
            formatted_columns = []
            for column in asset_columns:
                formatted_column = {
                    'type': column.get('dataType', 'unknown'),
                    'name': column.get('columnName', 'unknown')
                }
                # 설명 정보가 있으면 추가
                if 'description' in column and column['description']:
                    formatted_column['description'] = column['description']

                formatted_columns.append(formatted_column)
            
            # 스키마 정보 추가
            input_dataset['facets'] = {
                "schema": {
                    "_producer": "custom/glue-integration",
                    "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/SchemaFacet",
                    'fields': formatted_columns
                },
                "sourceDetails": {
                    "_producer": "custom/glue-integration",
                    "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/BaseFacet",
                }
            }

    inputs.append(input_dataset)
  • Output 노드 정의
# 자산 정보 로드
asset_info = get_asset(asset_id)

# 대시보드 자산 정보를 담은 출력 facet 정의
output_facets = {
    "dataZone": {
        "_producer": "custom",
        "_schemaURL": "http://raw.githubusercontent.com/OpenLineage/OpenLineage/main/spec/OpenLineage.json#/definitions/DataZoneFacet",
        "assetId": asset_info['id'],
        "assetName": asset_info['name'],
        "assetDescription": asset_info.get('description', '')
    }
}

# 출력 데이터셋 정의 (대시보드의 소스 식별자 구성)
source_identifier = get_source_identifier(asset_info['formsOutput'])
parts = source_identifier.split('/', 1)
namespace = parts[0]
name = parts[1]

# 출력 데이터셋 정의
outputs = [{
    "namespace": namespace,
    "name": name,
    "facets": output_facets
}]
  • OpenLineage 형식의 최종 계보 이벤트 생성
# 현재 시간 ISO 형식으로 생성
event_time = datetime.utcnow().isoformat() + "Z"

# 이벤트 UUID 생성
run_id = str(uuid.uuid4())
    
lineage_event = {
    "eventType": "COMPLETE",
    "producer": "custom/tableau-integration",
    "schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/RunEvent",
    "eventTime": event_time,
    "run": {
        "runId": run_id
    },
    "job": {
        "namespace": "tableau",
        "name": f"tableau_dashboard_job_{asset_id}"
    },
    "inputs": inputs,
    "outputs": outputs
}

다음은 완성된 OpenLineage 이벤트의 예시입니다.

{
  "eventType": "COMPLETE",
  "producer": "custom/tableau-integration",
  "schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/RunEvent",
  "eventTime": "2025-04-11T05:14:28.550609Z",
  "run": {
    "runId": "7b58051c-2871-4561-a9fe-02de231a7f9f"
  },
  "job": {
    "namespace": "tableau",
    "name": "tableau_dashboard_job_{자산 ID}"
  },
  "inputs": [
    {
      "namespace": "glue",
      "name": "biz.sales_analysis",
      "facets": {
        "schema": {
          "_producer": "custom/glue-integration",
          "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/SchemaFacet",
          "fields": [
            {
              "type": "int",
              "name": "sale_id"
            },
            ...
          ]
        },
        "sourceDetails": {
          "_producer": "custom/glue-integration",
          "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/BaseFacet"
        }
      }
    },
    {
      "namespace": "glue",
      "name": "biz.sales_target",
      "facets": {
        "schema": {
          "_producer": "custom/glue-integration",
          "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/SchemaFacet",
          "fields": [
            {
              "type": "int",
              "name": "sale_id"
            },
            ...
          ]
        },
        "sourceDetails": {
          "_producer": "custom/glue-integration",
          "_schemaURL": "http://openlineage.io/spec/2-0-2/OpenLineage.json#/$defs/BaseFacet"
        }
      }
    },
    {
      "namespace": "dw",
      "name": "product_info"
    }
  ],
  "outputs": [
    {
      "namespace": "tableau",
      "name": "[SALES] Sales Performance Dashboard_{자산 ID}",
      "facets": {
        ...
      }
    }
  ]
}
response = datazone_client.post_lineage_event(
    domainIdentifier=DATAZONE_DOMAIN_ID,
    event=json.dumps(lineage_event, ensure_ascii=False)
)

이제 AWS CloudShell을 사용하여 자산을 등록해보겠습니다.
1. post_lineage_event_of_asset.py 파일을 다운로드 합니다.
2. 다운로드한 파일에서 아래 부분에 자신의 환경에 맞는 파라미터 값을 입력하고 저장합니다.

AWS_REGION = '{AWS Region 입력}'
DATAZONE_DOMAIN_ID = '{DataZone 도메인 ID 입력}' 
DATAZONE_PROJECT_ID = '{DataZone 프로젝트 ID 입력}' 
DATASOURCE_PROJECT_ID = '{DataZone의 DataSource가 저장된 프로젝트 ID 입력}'

3. HAQM DataZone 콘솔에서 AWS CloudShell을 실행합니다.
4. 작업 메뉴에서, 파일 업로드를 선택합니다.
5. post_lineage_event_of_asset.py 파일을 업로드합니다.
6. 아래 명령어를 실행합니다.

python post_lineage_event_of_asset.py --asset-id {자산 ID 입력}

다음 결과가 표시됩니다.

Sales Performance Dashboard 자산의 계보 탭으로 이동하면 아래와 같이 데이터 자산과 대시보드 자산의 계보 이벤트를 확인할 수 있습니다.

결론

이 블로그에서는 HAQM DataZone의 Custom Asset Type 기능을 활용해 Tableau 대시보드를 AWS 환경에 통합하고 데이터 계보를 구축하는 방법을 살펴보았습니다. 이 솔루션은 하이브리드 데이터 환경을 위한 실질적인 접근 방식을 제공합니다. 이 통합 방식을 통해 조직은 AWS와 외부 시스템의 데이터 자산을 단일 플랫폼에서 관리할 수 있을 뿐만 아니라, 데이터의 원천부터 최종 시각화까지 계보를 추적함으로써 데이터 투명성과 신뢰성을 향상시킬 수 있습니다. 특히 변경 관리 측면에서 데이터 소스 수정이 어떤 대시보드에 영향을 미치는지 즉시 파악할 수 있어, 더욱 효과적인 데이터 거버넌스가 가능해집니다. 다음 단계로는 이 프레임워크를 다른 BI 도구로 확장하거나, 데이터 품질 지표와 사용 패턴을 통합하여 메타데이터를 더욱 풍부하게 만드는 방향을 고려해 볼 수 있습니다.

SueKyoung Lee

SueKyoung Lee

이수경 Data Architect는 AWS 클라우드 환경에서 고객들이 직면하는 데이터 관련 문제를 해결하는 데 도움을 주고 있습니다. 데이터의 이해, 처리 및 활용에 대한 전반적인 컨설팅 및 기술 지원을 제공합니다.

Daeyeol Seo

Daeyeol Seo

서대열IoT, Data Architect는 엔터프라이즈 고객들의 Workload에 맞는 IoT와 Data 서비스들을 소개하고 IoT 및 Data 서비스들을 적용한 최적의 아키텍처를 설계하고 구축하는 역할을 수행하고 있습니다.