캐스케이딩 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

단계별로 살펴보면:

  1. 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)을 만들어요.
  2. 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)은 적용받지 않아요.
  3. 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는 상호 배타적. 둘 중 하나만 설정할 수 있어요.
  • ALL segment granularity는 지원하지 않아요. 표준 자동 컴팩션과 같은 제약이에요.

더 알아보기 (Learn more)

자세한 내용은 다음 주제를 참고하세요: