incremental: 증분 실행 계약
transforms.api.incremental은 출력 데이터셋의 빌드 이력을 읽어 마지막 빌드 당시의 입력 상태를 파악합니다. 이 상태를 기준으로 입력, 출력과 실행 맥락을 증분 대응 객체로 변환합니다. Transform 또는 ContainerTransform을 감싸는 데코레이터입니다.
transforms.api.incremental(
require_incremental=False, semantic_version=1, snapshot_inputs=None,
allow_retention=False, allow_user_deletes=False,
strict_append=False, v2_semantics=False,
)
설정
| 인자 | 형식 | 기본값과 동작 |
|---|---|---|
require_incremental | bool | False. True이면 비증분 실행을 거부하되 최초 실행은 예외 |
semantic_version | int | 1. 기존 출력을 무효화하는 논리 변경 때 바꾸며, 변경 후 다음 실행은 비증분으로 수행 |
snapshot_inputs | list[str] | None. SNAPSHOT 갱신이 기존 출력을 무효화하지 않는 입력 이름 목록 |
allow_retention | bool | False. True이면 foundry-retention이 수행한 삭제가 증분성을 깨지 않음 |
allow_user_deletes | bool | False. True이면 foundry-retention 이외의 삭제가 증분성을 깨지 않음 |
strict_append | bool | False. 증분 실행의 기반 트랜잭션을 APPEND로 제한 |
v2_semantics | bool | False. True이면 v2 증분 의미론 사용 |
require_incremental의 최초 실행 예외는 모든 출력 데이터셋에 커밋된 트랜잭션이 없다는 조건으로 판단합니다. semantic_version은 변환 로직의 의미를 나타내는 번호이며 라이브러리 버전과 별개입니다.
스냅샷 입력
예를 들어 참조 테이블이 SNAPSHOT으로 갱신되어도 이미 계산한 출력의 정확성을 깨지 않는다면 해당 입력을 snapshot_inputs에 지정할 수 있습니다. 이 목록을 제외한 모든 입력에 추가 데이터만 있거나 새 데이터가 없으면 변환을 증분 실행할 수 있습니다.
스냅샷 입력의 IncrementalTransformInput은 입력 데이터셋의 현재 뷰만 노출합니다. 참조 테이블이라는 이름만으로 지정하지 말고, 그 갱신이 기존 출력을 무효화하지 않는지에 따라 선택합니다.
v2 의미론과 삭제
일반적인 증분 동작은 v1과 v2 사이에서 달라지지 않도록 하며 v2_semantics=True 사용이 권장됩니다. 미디어 집합 같은 비-Catalog 증분 입출력은 v2 의미론에서만 지원합니다.
allow_user_deletes=True에는 v2_semantics=True가 필요하며 경량 변환에서는 지원하지 않습니다. foundry-retention 삭제를 허용하는 allow_retention과 일반 삭제를 허용하는 설정은 별개입니다.
v2 의미론에서는 Input의 transaction_limit으로 증분 입력에서 한 작업이 읽을 트랜잭션 수를 제한할 수 있습니다. 누적 트랜잭션이 많은 입력을 나누어 처리할 때 사용합니다.
strict_append
strict_append가 True이고 증분 실행 중이면 기반 Foundry 트랜잭션 유형은 APPEND입니다. 비증분 실행에서 APPEND 트랜잭션을 강제하려면 require_incremental도 True여야 합니다.
APPEND 쓰기는 어떤 파일도 덮어쓰지 않아야 합니다. Parquet 요약 메타데이터나 Hadoop 성공 표시 파일 같은 보조 파일도 이 제약에 포함됩니다. 사용하는 Foundry 형식의 증분 쓰기도 이 조건을 충족해야 합니다.
Spark와 경량 예시
다음은 추가 입력 행만으로 추가 출력 행을 계산하는 가상 변환입니다. 경로는 실제 데이터셋으로 지정합니다.
from transforms.api import Input, Output, incremental, transform
@incremental(v2_semantics=True)
@transform(
first_input=Input("/path/to/first/input/dataset"),
first_output=Output("/path/to/first/output/dataset"),
)
def my_compute_function(first_input, first_output):
first_output.write_dataframe(first_input.dataframe())
경량 실행에서는 Spark를 사용하지 않습니다. pandas를 run 의존성으로 추가한 저장소의 예시입니다.
from transforms.api import Input, Output, incremental, transform
@incremental(v2_semantics=True)
@transform.using(
my_input=Input("/path/to/input"),
my_output=Output("/path/to/output"),
)
def compute_func(my_input, my_output):
my_output.write_pandas(my_input.pandas())
Spark에서는 TransformInput, TransformOutput, TransformContext가 각각 IncrementalTransformInput, IncrementalTransformOutput, IncrementalTransformContext로 바뀝니다.
DataFrame 데코레이터의 기본 모드
transform_df와 transform_pandas도 incremental로 감쌀 수 있습니다. 이 데코레이터는 입력의 dataframe 또는 pandas 메서드를 인자 없이 호출하므로 읽기 모드는 항상 added이고 쓰기 모드는 incremental이 결정합니다. 다른 읽기나 쓰기 모드가 필요하면 transform을 사용합니다.
추가 출력이 추가 입력만의 함수일 때는 기본 모드로 올바른 증분 계산을 구성할 수 있습니다. 조인, 집계나 distinct처럼 과거 상태와의 관계가 필요한 연산은 증분 로직을 별도로 검토해야 합니다. 데코레이터를 붙이는 것만으로 그러한 계산의 증분 정확성을 보장하지 않습니다.
오류와 버전
지원하는 변환 객체를 감싸지 않으면 TransformTypeError가 발생합니다. 지정한 snapshot 입력이 변환에 없으면 TransformKeyError가 발생합니다.
incremental은 1.7.0에 추가되었고 snapshot_inputs는 1.35.0, strict_append는 1.312.0에 추가되었습니다.