아파치 수페셋: 버전 3.x–6.x에서 날짜 필터 제한을 우회하는 방법
아파치 수페셋은 차트 레벨에서 특정 시간 열에 날짜 필터를 바인딩할 수 없습니다. 대신 데이터셋 전체에 대해 필터 선택이 항상 글자 순서에 따라 결정됩니다. 이는 프로덕션 환경에서 심각한 문제를 야기합니다: 비즈니스 로직의 통제되지 않은 변경, 대시보드 간 충돌, 그리고 기본 시간 열이 수정될 때 숨겨진 회귀 문제가 발생합니다. 본 문서에서는 이러한 제한의 아키텍처적 원인, 테스트된 우회 방법, 그리고 현재 솔루션의 기술적 한계를 살펴봅니다.
왜 수페셋이 bot_profile__updated를 선택하는가—그리고 그 위험성
수페셋은 데이터셋 생성 시 자동으로 기본 시간 열을 할당하는데, 이는 오직 TIMESTAMP, DATETIME, 또는 DATE 타입의 열을 알파벳 순으로 정렬한 결과에만 기반합니다. 예를 들어, messages 데이터셋에서는 bot_profile__updated, ts, created_at, updated_at 중에서 bot_profile__updated가 알파벳 순서상 가장 먼저 나옵니다. 이 동작은 superset/datasets/models.py에 하드코딩되어 있으며, get_default_time_column() 메서드는 의미나 비즈니스 컨텍스트, 메타데이터를 고려하지 않고 sorted([col for col in dataset.columns if col.is_temporal])만 사용합니다.
주요 위험은 데이터셋의 기본 시간 열을 변경하면 이를 사용하는 모든 차트와 대시보드에 영향을 미친다는 점입니다. 심지어 논리적으로 서로 다른 시간 축을 가진 경우에도 마찬가지입니다. 예를 들어:
- ‘봇 활동’ 차트는
ts(이벤트 발생 시점)로 필터링되어야 합니다. - ‘프로필 업데이트’ 차트는
bot_profile__updated(엔티티가 업데이트된 시점)로 필터링되어야 합니다. - 두 차트 모두 같은
messages데이터셋을 사용합니다.
관리자가 기본 시간 열을 ts로 변경하면, 두 번째 차트는 잘못된 시간 축으로 데이터를 표시하기 시작합니다. 이는 오류, 로그, 경고 없이 발생하며, UI에 노란색 알림만 표시되어 사용자에게 해당 문제를 알려줄 뿐 실제로는 작업을 차단하지 않습니다.
시간 열 필터: 기능적 우회 방안이지만 체계적 한계가 존재
버전 3.0부터 수페셋은 시간 열 필터를 도입했는데, 이는 데이터셋 내 모든 시간 열을 드롭다운 형태로 표시하고 사용자가 하나를 선택하도록 하는 기능입니다. 그러나 이 구현은 해결책이라기보다는 기존 결함을 추상화한 것에 불과합니다:
시간 열 필터에서 선택한 값은 해당 대시보드의 모든 날짜 필터에 대해 전체적으로 기본 시간 열을 덮어씁니다;- 두 개의 독립적인 날짜 필터(예: ‘이벤트 기간’과 ‘처리 기간’)를 추가할 수 없으며, 두 필터 모두 동일한 선택값을 사용하게 됩니다;
- 이 필터는 조건식(
WHERE ts BETWEEN ... AND ... AND updated_at > ...)을 지원하지 않습니다; - SQL 쿼리의 집계에는 영향을 주지 않으며, 오직
WHERE를 통한 필터링에만 적용됩니다.
결과적으로 ‘필터 프록시’ 패턴이 나타나게 되며, 개발자는 로직을 분리하기 위해 서로 다른 default_time_columns을 가진 데이터셋을 복제해야 합니다. 이러한 접근법은 DRY 원칙을 위반하고 유지보수를 복잡하게 만들며, 메타데이터 부하를 증가시킵니다.
중급/고급 개발자를 위한 실용적인 기술적 해결책
프로덕션 환경에서 수페셋의 안정적인 운영을 보장하기 위해 다음과 같은 접근법을 권장합니다:
- SQL Lab을 통한 가상 데이터셋 생성
- 각각의 고유한 시간 컨텍스트에 맞춰 명시적인 SELECT ... AS time_dimension FROM ... 문으로 별도의 SQL 데이터셋을 생성합니다.
- 이름을 time_dimension으로 고정하여 모호성을 방지합니다;
- 예시:
SELECT
ts AS time_dimension,
user_id,
event_type,
payload
FROM messages
WHERE ts IS NOT NULL
extra_json를 이용한 강제 바인딩
- 데이터셋 편집기에서 Extra JSON 필드에 다음 내용을 입력합니다:
{"default_time_column": "ts"}
- 이는 해당 필드가 columns.extra에 존재해야만 작동하며, 스키마가 변경될 때마다 수동 업데이트가 필요합니다;
- 커스텀 이미지에서
Dataset.get_default_time_column()패칭
- 데이터베이스 주석(COMMENT ON COLUMN messages.ts IS 'time_dimension:primary')을 통해 주석 지원을 추가합니다;
- get_default_time_column()에서 이러한 주석을 파싱하도록 수정합니다;
- CI/CD 통합과 신규 버전과의 호환성 테스트가 필요합니다;
- 내장 필터를 포기하고 파라미터화된 SQL 차트 사용
- 모든 시간 필터를 차트의 WHERE 조건에 포함시키고 {{ filter_values('date_range') }}를 사용합니다;
- 이를 통해 여러 독립적인 필터와 복잡한 조건을 설정할 수 있습니다;
- 단점은 대시보드 UI에서 시각적 필터 인터페이스를 잃게 된다는 점입니다.
무엇이 중요한가
- 수페셋은 시간 열의 의미적 목적을 구분하지 않습니다:
ts,created_at,updated_at모두 정렬을 위해 동등한 문자열로 취급됩니다. - 데이터셋의
default_time_column을 변경하는 것은 안전한 작업이 아닙니다. 즉시 모든 종속 차트에 영향을 미치며, 어떠한 피드백도 제공되지 않습니다. 시간 열 필터는 특정 열에 바인딩하기 위한 메커니즘이 아니라 대시보드 전체의 글로벌 시간 스위치입니다.- 버전 5.x와 6.x도 근본 문제를 해결하지 못했습니다: 시간 선택 로직은 여전히
models.py에 남아 있으며, 필터링 아키텍처의 재설계는 이루어지지 않았습니다. - 유일한 신뢰할 수 있는 격리 방법은 데이터셋을 물리적으로 분리하거나 파라미터화된 SQL 시각화로 전환하는 것입니다.
아파치 수페셋에서 날짜 필터링은 여전히 아키텍처상 가장 취약한 부분 중 하나입니다. 데이터셋 레벨에서 다중 시간 축을 지원하지 않는 점, 필드 이름의 글자 순서에만 의존하는 경직된 구조, 그리고 열에 주석을 달 수 있는 메커니즘의 부재로 인해 여러 시간 차원을 가진 이벤트 스트림을 올바르게 모델링하는 것이 불가능합니다. 특히 IoT 분석, 금융 거래, 마이크로서비스 로그 등에서는 각 레코드에 최소 세 가지 타임스탬프(event_time, ingestion_time, processing_time)가 포함되므로 이 문제는 더욱 중요합니다. 커뮤니티에서는 이슈 #32496을 통해 해결 방안을 제안했지만, 아직 이를 구현한 PR은 없습니다. 현재로서는 각 데이터셋에 의미 있는 시간 열을 정확히 하나만 포함하도록 설계하거나, 내장 필터를 포기하고 관리되는 SQL 기반 솔루션을 사용하는 것이 최선의 실천 방안입니다.
— Editorial Team
아직 댓글이 없습니다.