캐스케이딩 reindexing
캐스케이딩 reindexing (Cascading reindexing)
캐스케이딩 reindexing은 데이터가 오래될수록 서로 다른 컴팩션 설정을 자동으로 적용하게 해주는 컴팩션 supervisor 템플릿이에요. 데이터소스 전체에 단일 평면 컴팩션 설정을 쓰는 대신, "X보다 오래된 데이터에는 설정 Y를 적용해" 같은 나이 기반 규칙을 정의해요.
출처: 문서
본문
info
캐스케이딩 reindexing은 Druid 37에서 도입된 실험적 기능이에요. API는 향후 릴리스에서 변경될 수 있어요. 이 기능은 MSQ task engine을 사용하는 컴팩션 supervisor를 이용한 자동 컴팩션 전용이에요.
캐스케이딩 reindexing은 데이터가 오래될수록 서로 다른 컴팩션 설정을 자동으로 적용하게 해주는 컴팩션 supervisor 템플릿이에요. 데이터소스 전체에 단일 평면 컴팩션 설정을 쓰는 대신, "X보다 오래된 데이터에는 설정 Y를 적용해" 같은 나이 기반 규칙을 정의해요. Reindexing은 컴팩션보다 더 포괄적인 용어예요. Reindexing은 같은 스키마·파티셔닝을 가진 segment를 병합할 수 있을 뿐 아니라, segment의 스키마·파티셔닝·인코딩까지 바꿀 수 있어요. 캐스케이딩 reindexing은 데이터가 시간에 따라 어떻게 진화할지 미세하게 제어할 수 있게 해줘요.
예를 들어 다음과 같은 작업을 하고 싶을 수 있어요:
- 최근 데이터는 시간 단위 segment로 두되, 90일이 지나면 일 단위 segment로 굵게(coarsen) 만들어 segment 수와 저장 공간을 줄이기
- 30일보다 오래된 데이터에서 원치 않는 일부 행 삭제하기
- 오래된 데이터의 압축 설정 변경하기
- 오래된 데이터를 더 굵은 query granularity로 roll up하기
캐스케이딩 reindexing은 컴팩션 interval 타임라인을 생성하고 각 interval에 적절한 규칙을 적용해서 이 모든 것을 자동으로 처리해요.
사전 요구사항 (Prerequisites)
캐스케이딩 reindexing을 사용하기 전에 클러스터가 다음 요구사항을 충족하는지 확인하세요:
- MSQ 컴팩션 엔진: 컴팩션 dynamic config 또는 supervisor spec에서
engine을msq로 설정해요. - 컴팩션 task 슬롯 2개 이상: MSQ task engine은 최소 2개의 task(컨트롤러 1개, 워커 1개)가 필요해요.
캐스케이딩 reindexing이 동작하는 방식
규칙 기반 설정
캐스케이딩 reindexing은 규칙 기반 시스템을 사용해요. 각 규칙은 컴팩션의 특정 측면을 제어하고, 적용되는 나이 임계값(age threshold)을 지정해요. interval에 대한 컴팩션 config 출력의 상호 독립적인 측면을 각각 제어하는 네 가지 규칙 타입이 있어요:
| Rule type | 규제 대상 | Additive? |
|---|---|---|
| Partitioning rules | Segment granularity, partitions spec, 범위 파티셔닝용 선택적 virtual columns | No |
| Deletion rules | segment에서 제거할 행 | Yes |
| Index spec rules | 압축 및 인코딩 설정 | No |
| Data schema rules | Dimensions, metrics, query granularity, rollup, projections | No |
모든 규칙에는 olderThan 필드가 있는데, 나이 임계값을 정의하는 ISO 8601 period예요. "olderThan": "P30D"인 규칙은 interval이 현재 시간보다 30일 이전에 끝나는 데이터에 적용돼요.
Additive vs non-additive 규칙
Non-additive 규칙(partitioning, index spec, data schema): interval당 각 타입의 규칙 하나만 적용돼요. 같은 타입의 규칙이 여러 개 일치하면, 임계값이 가장 오래된(period가 가장 큰) 규칙이 우선해요.
Additive 규칙(deletion): 같은 interval에 여러 deletion 규칙이 적용될 수 있어요. 이 경우 NOT(A OR B OR C)로 결합되는데, A·B·C는 각 규칙의 deleteWhere 필터예요. 즉, 컴팩션된 데이터는 어떤 deletion 필터와도 일치하지 않는 행만 유지해요.
타임라인 생성 (Timeline generation)
캐스케이딩 reindexing 템플릿은 겹치지 않는 search interval의 타임라인을 생성해요. 각 interval에는 자신에게 적용되는 규칙 집합이 있어요. 타임라인이 구성되는 방식은 다음과 같아요:
partitioning 규칙으로 기본 타임라인을 만든다. 각 partitioning 규칙은 segment granularity와 나이 임계값을 정의해요. 템플릿은 임계값 순서로 규칙을 정렬하고(가장 오래된 것 먼저), 각 규칙의 segment granularity에 정렬된 경계로 interval을 생성해요.
partitioning이 아닌 규칙의 임계값에서 분할한다. deletion·index spec·data schema 규칙의 임계값이 기본 interval 안에 들어오면, 템플릿은 그 임계값에서 interval을 분할해요(interval의 segment granularity에 정렬). 이렇게 하면 규칙이 최대한 정확하게 적용돼요.
granularity 순서를 검증한다. 템플릿은 과거에서 현재로 갈수록 segment granularity가 같거나 더 세밀해지는지 검증해요. 예를 들어 오래된 데이터에 DAY, 최근 데이터에 HOUR는 유효하지만, 오래된 데이터에 HOUR, 최근 데이터에 DAY는 유효하지 않아요.
타임라인 생성 예시
현재 시간이 2026-03-26T00:00:00Z이고 다음 규칙을 설정했다고 가정해 봐요:
- Partitioning rule A:
olderThan: P7D,segmentGranularity: HOUR - Partitioning rule B:
olderThan: P90D,segmentGranularity: DAY - Deletion rule C:
olderThan: P30D,deleteWhere: isRobot = true
템플릿은 다음 search interval들을 생성해요:
| Search interval | Segment granularity | Source | Active rules |
|---|---|---|---|
[-inf, 2025-12-26) |
DAY | Partitioning rule B | B, C |
[2025-12-26, 2026-02-24) |
DAY | Default (from template) | C |
[2026-02-24, 2026-03-19) |
HOUR | Partitioning rule A | A |
단계별로 살펴보면:
- Partitioning rule B(
olderThan: P90D)는 DAY granularity로 interval[-inf, 2025-12-26)을 만들고, Partitioning rule A(olderThan: P7D)는 HOUR granularity로[2025-12-26, 2026-03-19)을 만들어요. - Deletion rule C(
olderThan: P30D)의 임계값은2026-02-24예요. 이는 규칙 A의 interval 안에 들어오므로, 그 interval을2026-02-24에서 분할해요(이미 DAY 정렬되어 있음). 더 오래된 하위 interval[2025-12-26, 2026-02-24)은 deletion rule C를 적용받고, 더 새로운 하위 interval[2026-02-24, 2026-03-19)은 적용받지 않아요. - DAY(오래된)에서 HOUR(최신)로 가는 granularity 검증이 유효하므로 통과해요 — 현재 방향으로 갈수록 granularity가 더 세밀해지거든요.
기본값이 동작하는 방식
템플릿은 defaultSegmentGranularity와 defaultPartitionsSpec을 요구해요. 이 값들은 일치하는 partitioning 규칙이 없는 모든 interval에 사용돼요. 다음과 같은 두 시나리오에서 발생해요:
- partitioning 규칙이 전혀 정의되지 않은 경우. deletion·index spec·data schema 규칙만 정의하면, 모든 interval이 기본 granularity와 partitions spec을 사용해요.
- partitioning이 아닌 규칙이 가장 최신 partitioning 규칙보다 더 최신 임계값을 가진 경우. 예를 들어 partitioning 규칙이
olderThan: P90D하나뿐인데 deletion 규칙이olderThan: P30D라면, 30일과 90일 사이의 interval은 기본값을 사용해요.
Supervisor spec 참조
캐스케이딩 reindexing supervisor를 제출하려면 템플릿 spec을 컴팩션 supervisor spec 안에 감싸세요:
{
"type": "autocompact",
"spec": {
"type": "reindexCascade",
"dataSource": "wikipedia",
"ruleProvider": { ... },
"defaultSegmentGranularity": "DAY",
"defaultPartitionsSpec": {
"type": "dynamic",
"maxRowsPerSegment": 5000000
}
}
}
템플릿 속성
reindexCascade 템플릿의 속성을 설명하는 표는 다음과 같아요:
| Field | Description | Required | Default |
|---|---|---|---|
type |
reindexCascade여야 해요. |
Yes | |
dataSource |
컴팩션할 데이터소스 | Yes | |
ruleProvider |
reindexing 규칙을 공급하는 설정 | Yes | |
defaultSegmentGranularity |
일치하는 partitioning 규칙이 없는 interval에 사용되는 segment granularity. 지원 값: MINUTE, FIFTEEN_MINUTE, HOUR, DAY, MONTH, QUARTER, YEAR. |
Yes | |
defaultPartitionsSpec |
일치하는 partitioning 규칙이 없는 interval에 사용되는 partitions spec. 지원되는 partitioning 타입은 MSQ task engine limitations을 참고해요. | Yes | |
defaultPartitioningVirtualColumns |
defaultPartitionsSpec range partitioning 정의가 virtual columns를 참조할 때 사용되는 선택적 virtual columns |
No | |
taskPriority |
컴팩션 task의 우선순위 | No | 25 |
inputSegmentSizeBytes |
컴팩션 task당 최대 총 입력 segment 크기(바이트) | No | 100000000000000 |
taskContext |
컴팩션 task에 전달되는 context map. maxNumTasks 같은 MSQ context parameters를 설정하는 데 사용해요. |
No | |
skipOffsetFromLatest |
ISO 8601 period. 최신 segment 끝에서 이 offset보다 새로운 데이터를 건너뛰어요. skipOffsetFromNow와 상호 배타적이에요. |
No | |
skipOffsetFromNow |
ISO 8601 period. 현재 시간에서 이 offset보다 새로운 데이터를 건너뛰어요. skipOffsetFromLatest와 상호 배타적이에요. |
No | |
tuningConfig |
컴팩션 task의 Tuning config. tuningConfig 안에 partitionsSpec을 설정할 수 없어요 — partitioning은 규칙과 supervisor 기본값이 제어해요. |
No |
Rule provider 타입
rule provider는 reindexing 규칙을 템플릿에 공급해요. Druid는 두 가지 provider 타입을 지원해요.
Inline provider
Inline provider(type: inline)는 규칙을 supervisor spec에 직접 정의해요. 현재 유일한 구체적 구현이에요.
{
"type": "inline",
"partitioningRules": [ ... ],
"deletionRules": [ ... ],
"indexSpecRules": [ ... ],
"dataSchemaRules": [ ... ]
}
| Field | Description | Required | Default |
|---|---|---|---|
type |
inline이어야 해요. |
Yes | |
partitioningRules |
Partitioning 규칙 목록 | No | [] |
deletionRules |
Deletion 규칙 목록 | No | [] |
indexSpecRules |
Index spec 규칙 목록 | No | [] |
dataSchemaRules |
Data schema 규칙 목록 | No | [] |
모든 규칙 목록을 합쳐 최소 하나의 규칙이 정의되어야 해요.
Composing provider
Composing provider(type: composing)는 여러 rule provider를 first-wins 의미론으로 연결해요. 각 규칙 타입에 대해 Druid는 해당 타입의 규칙이 비어 있지 않은 첫 번째 provider의 규칙을 사용해요.
이 rule provider는 앞으로 커뮤니티가 기여할 provider(예: Druid Catalog에서 규칙을 가져오는 provider)를 대비해 만들어졌어요.
{
"type": "composing",
"providers": [
{ "type": "inline", "partitioningRules": [ ... ] },
...
]
}
| Field | Description | Required | Default |
|---|---|---|---|
type |
composing이어야 해요. |
Yes | |
providers |
순서가 있는 provider 목록. provider 순서가 우선순위를 결정해요. | Yes |
composing provider는 모든 하위 provider가 ready일 때만 ready 상태가 돼요.
Reindexing 규칙 타입
모든 규칙 타입은 다음 공통 필드를 공유해요:
| Field | Description | Required |
|---|---|---|
id |
규칙의 고유 식별자 | Yes |
description |
사람이 읽을 수 있는 설명 | No |
olderThan |
나이 임계값을 정의하는 ISO 8601 period. 규칙은 현재 시간에서 이 period를 뺀 것보다 오래된 데이터에 적용돼요. 음수면 안 돼요. | Yes |
Partitioning 규칙
Partitioning 규칙은 데이터가 segment로 물리적으로 배치되는 방식을 제어해요. 여기에는 시간 버킷팅(segment granularity)과 시간 버킷 내 데이터 분할 방식(partitions spec)이 포함돼요.
이는 non-additive 규칙이라 interval당 partitioning 규칙 하나만 적용돼요.
| Field | Description | Required |
|---|---|---|
id |
규칙 식별자 | Yes |
description |
사람이 읽을 수 있는 설명 | No |
olderThan |
ISO 8601 period | Yes |
segmentGranularity |
segment 버킷의 시간 granularity. 지원 값: MINUTE, FIFTEEN_MINUTE, HOUR, DAY, MONTH, QUARTER, YEAR. |
Yes |
partitionsSpec |
각 시간 버킷 내 데이터를 segment로 분할하는 방식을 정의해요. dynamic과 range 타입을 지원해요. |
Yes |
virtualColumns |
중첩·파생 필드로 파티셔닝하기 위한 virtual columns | No |
예시:
{
"id": "daily-range-30d",
"olderThan": "P30D",
"segmentGranularity": "DAY",
"partitionsSpec": {
"type": "range",
"targetRowsPerSegment": 5000000,
"partitionDimensions": ["channel", "countryName"]
},
"description": "Compact to daily segments with range partitioning for data older than 30 days"
}
Deletion 규칙
Deletion 규칙은 컴팩션 중 제거할 행을 지정해요. deleteWhere 필드는 삭제할 행과 일치하는 Druid filter를 정의해요. 처리 중 Druid는 이 필터들을 NOT 논리로 감싸서, 컴팩션된 데이터는 필터와 일치하지 않는 행을 유지해요.
이는 additive 규칙이라 같은 interval에 여러 deletion 규칙을 적용할 수 있어요.
| Field | Description | Required |
|---|---|---|
id |
규칙 식별자 | Yes |
description |
사람이 읽을 수 있는 설명 | No |
olderThan |
ISO 8601 period | Yes |
deleteWhere |
제거할 행과 일치하는 Druid filter | Yes |
virtualColumns |
중첩·파생 필드로 필터링하기 위한 virtual columns. virtual column 이름은 규칙 평가 전반에 걸쳐 고유하고 일관되어야 해요. | No |
작성한 것과 실제로 일어나는 일:
deletion 규칙 두 개를 정의했다고 가정해 봐요:
- 규칙 1:
deleteWhere: isRobot = true - 규칙 2:
deleteWhere: countryName = null
Druid는 이를 NOT(isRobot = true OR countryName = null)로 적용해요. 컴팩션된 segment는 isRobot이 true가 아니고 countryName이 null이 아닌 행만 유지해요.
예시:
{
"id": "remove-robots-90d",
"olderThan": "P90D",
"deleteWhere": {
"type": "equals",
"column": "isRobot",
"matchValueType": "STRING",
"matchValue": "true"
},
"description": "Remove robot traffic from data older than 90 days"
}
Index spec 규칙
Index spec 규칙은 파티셔닝과 무관하게 컴팩션된 segment의 압축 및 인코딩 설정을 제어해요.
이는 non-additive 규칙이라 interval당 index spec 규칙 하나만 적용돼요.
| Field | Description | Required |
|---|---|---|
id |
규칙 식별자 | Yes |
description |
사람이 읽을 수 있는 설명 | No |
olderThan |
ISO 8601 period | Yes |
indexSpec |
비트맵 타입, metric 압축 및 기타 인코딩 설정을 정의하는 IndexSpec 객체 | Yes |
예시:
{
"id": "compressed-90d",
"olderThan": "P90D",
"indexSpec": {
"bitmap": { "type": "roaring" },
"metricCompression": "lz4"
},
"description": "Use roaring bitmaps and lz4 compression for data older than 90 days"
}
Data schema 규칙
Data schema 규칙은 컴팩션된 segment의 스키마를 제어해요. 여기에는 dimensions, metrics, query granularity, rollup, projections가 포함돼요.
이는 non-additive 규칙이라 interval당 data schema 규칙 하나만 적용돼요. 선택 필드 중 최소 하나는 null이 아니어야 해요.
| Field | Description | Required |
|---|---|---|
id |
규칙 식별자 | Yes |
description |
사람이 읽을 수 있는 설명 | No |
olderThan |
ISO 8601 period | Yes |
dimensionsSpec |
컴팩션된 segment의 Dimensions config | No |
metricsSpec |
rollup metrics용 aggregator factories 배열 | No |
queryGranularity |
컴팩션된 segment의 Query granularity | No |
rollup |
rollup 활성화 여부. metricsSpec이 정의된 경우에만 true로 설정해요. |
No |
projections |
aggregate projections 목록 | No |
예시:
{
"id": "rollup-30d",
"olderThan": "P30D",
"queryGranularity": "HOUR",
"rollup": true,
"metricsSpec": [
{ "type": "longSum", "name": "added", "fieldName": "added" },
{ "type": "longSum", "name": "deleted", "fieldName": "deleted" }
],
"description": "Roll up to hourly query granularity for data older than 30 days"
}
예시
다음 예시는 wikipedia 데이터소스를 사용하며, partitioning 규칙과 deletion 규칙 하나를 가진 캐스케이딩 reindexing supervisor를 보여줘요. 동작은 다음과 같아요:
- 30일보다 오래된 데이터는 일 단위 range-partitioned segment로 컴팩션돼요.
isRobot컬럼 값이true인 행은 90일보다 오래된 데이터에서 삭제돼요.skipOffsetFromLatest설정이 가장 최근 하루치 데이터를 건너뛰어요.
curl --location --request POST 'http://localhost:8081/druid/indexer/v1/supervisor' \
--header 'Content-Type: application/json' \
--data-raw '{
"type": "autocompact",
"spec": {
"type": "reindexCascade",
"dataSource": "wikipedia",
"defaultSegmentGranularity": "HOUR",
"defaultPartitionsSpec": {
"type": "dynamic",
"maxRowsPerSegment": 5000000
},
"skipOffsetFromLatest": "P1D",
"ruleProvider": {
"type": "inline",
"partitioningRules": [
{
"id": "daily-30d",
"olderThan": "P30D",
"segmentGranularity": "DAY",
"partitionsSpec": {
"type": "range",
"targetRowsPerSegment": 5000000,
"partitionDimensions": ["channel", "countryName"]
},
"description": "Compact to daily range-partitioned segments after 30 days"
}
],
"deletionRules": [
{
"id": "remove-bots-90d",
"olderThan": "P90D",
"deleteWhere": {
"type": "equals",
"column": "isRobot",
"matchValueType": "STRING",
"matchValue": "true"
},
"description": "Remove robot edits from data older than 90 days"
}
]
},
"taskContext": {
"maxNumTasks": 3
}
}
}'
이 설정은 세 개의 타임라인 interval을 만들어요:
[-inf, now - 90D): DAY granularity, 봇 편집 삭제됨.[now - 90D, now - 30D): DAY granularity, 삭제 없음.[now - 30D, now - 1D): HOUR granularity(기본값), 삭제 없음. 최근 하루치 데이터는 건너뜀.
제약 사항 (Limitations)
- MSQ task engine 전용. 캐스케이딩 reindexing은 MSQ task engine이 필요해요. native engine은 지원하지 않아요.
- 컴팩션 supervisor 전용. 이 기능은 Coordinator duty를 이용한 자동 컴팩션에서는 사용할 수 없어요.
tuningConfig에partitionsSpec불가. 파티셔닝은 규칙과 기본값이 독점적으로 제어해요.tuningConfig안에partitionsSpec을 설정하면 검증 오류가 발생해요.- 현재 방향으로 갈수록 granularity가 굵어지면 안 됨. 오래된 데이터에서 최신 데이터로 갈수록 segment granularity가 같거나 더 세밀해져야 해요. 예를 들어 DAY에서 HOUR는 유효하지만 HOUR에서 DAY는 유효하지 않아요.
skipOffsetFromLatest와skipOffsetFromNow는 상호 배타적. 둘 중 하나만 설정할 수 있어요.ALLsegment granularity는 지원하지 않아요. 표준 자동 컴팩션과 같은 제약이에요.
더 알아보기 (Learn more)
자세한 내용은 다음 주제를 참고하세요:
- Automatic compaction — 일반적인 자동 컴팩션 설정.
- Auto-compaction using compaction supervisors — supervisor 설정과 관리.
- MSQ task engine for auto-compaction — MSQ 엔진 요구사항과 제약.
- Compaction — Druid의 컴팩션 개요.