UDF 정의 YAML과 자료형
UDF 정의는 src/main/resources/udfs/definitions/ 아래의 YAML 파일에 둡니다. 여러 UDF는 같은 디렉터리에 정의 파일을 추가하여 관리합니다. 이름과 스키마로 생성한 Java 인터페이스가 구현 코드의 계약이 됩니다.
최상위 필드
| 필드 | 지정 여부와 의미 |
|---|---|
name | UDF 이름입니다. 생성 클래스 이름, deployment.yml의 참조와 Builder 변환 이름에 사용합니다. |
customTypes | 선택적 재사용 자료형 정의입니다. 내부에 types 블록이 필요합니다. |
inputSchema | 입력 행이 따라야 하는 스키마입니다. 실제 데이터셋에 열이 더 있어도 런타임이 필요한 스키마를 선택할 수 있으면 입력으로 사용할 수 있습니다. |
outputSchema | 반환하거나 방출할 행의 스키마입니다. |
arguments | 빌드 때 사용자가 지정할 인자의 이름과 정의를 담는 map입니다. 인자가 없으면 빈 map으로 둡니다. |
description | Row map 등 해당 정의 유형의 선택적 설명입니다. Builder에서 기능을 이해하도록 표시합니다. |
type | Row map, flat map 또는 async 계열의 정의 유형입니다. 생략한 기본값은 row map입니다. |
keyColumns | Keyed process UDF의 파티션 키 열 이름 목록입니다. 열들이 입력 스키마에 있어야 합니다. |
eventTimeColumn | Keyed process UDF의 이벤트 시각 열입니다. 입력 스키마에 있어야 합니다. |
일반 정의의 type 열거값은 DEFAULT, FLAT_MAP_UDF, ASYNC_DEPLOYED_APP_UDF, ASYNC_CUSTOM_UDF입니다. Async 값이 정의 형식에 존재해도 Pipeline Builder의 게시 지원과 같지는 않습니다. 현재 Builder는 async 두 유형을 지원하지 않습니다.
각 인자에는 required Boolean과 type의 FieldType이 필요하며 선택적 description을 붙일 수 있습니다. 인자 이름은 정의 안에서 고유해야 합니다. 사용 목적과 값을 바꿨을 때의 영향을 설명하는 것이 권장됩니다.
행 스키마
| 필드 | 의미 |
|---|---|
name | 프로젝트에서 고유한 스키마 이름입니다. 생성 객체의 이름에 사용합니다. |
description | 선택적 설명이며 Builder의 스키마 문맥에 표시합니다. |
fields | 필드 정의 목록입니다. |
각 필드는 로컬에서 고유한 name, null 가능성을 나타내는 nullable과 자료형 객체인 type을 가집니다. 생성 Java의 accessor는 camelCase를 사용합니다. 예를 들어 argument_one은 argumentOne()이 됩니다.
기본 FieldType
각 자료형은 바깥 type discriminator와 같은 이름의 설정 객체를 함께 사용합니다.
| 자료형 | YAML의 FieldType 값 |
|---|---|
| Binary | {type: binary, binary: {}} |
| Boolean | {type: boolean, boolean: {}} |
| Byte | {type: byte, byte: {}} |
| Date | {type: date, date: {}} |
| Double | {type: double, double: {}} |
| Float | {type: float, float: {}} |
| Integer | {type: integer, integer: {}} |
| Long | {type: long, long: {}} |
| Short | {type: short, short: {}} |
| String | {type: string, string: {}} |
| Timestamp | {type: timestamp, timestamp: {}} |
Decimal
Precision은 1~38, scale은 0~precision 범위를 포함합니다. 다음은 전체 12자리 중 소수 두 자리를 쓰는 예입니다.
type: decimal
decimal:
precision: 12
scale: 2
Array
elementType에는 원소의 FieldType과 원소 null 가능성을 지정합니다. 다음은 null이 아닌 String 원소 배열입니다. 배열 자체가 null인지 여부는 이 유형을 사용하는 필드의 nullable로 정합니다.
type: array
array:
elementType:
type:
type: string
string: {}
nullable: false
Map
keyType, valueType 각각에 유형과 nullable 정보를 둡니다. 다음은 String 키와 nullable Double 값의 map입니다. 실제 Foundry 및 Spark 데이터셋의 map 키는 null을 허용하지 않는 계약을 따라야 합니다.
type: map
map:
keyType:
type:
type: string
string: {}
nullable: false
valueType:
type:
type: double
double: {}
nullable: true
Struct
Struct의 fields도 같은 필드 정의 목록입니다.
type: struct
struct:
fields:
- name: doubleField
nullable: false
type:
type: double
double: {}
Flat map 정의 예
다음 DuplicateRows.yml은 두 행 방출 구현에 필요한 입력과 출력을 정의합니다. key는 String, value는 Double이며 둘 다 null이 아닙니다.
name: DuplicateRows
description: Emit each input row twice.
type: FLAT_MAP_UDF
arguments: {}
inputSchema:
name: InputRow
fields:
- name: key
nullable: false
type:
type: string
string: {}
- name: value
nullable: false
type:
type: double
double: {}
outputSchema:
name: OutputRow
fields:
- name: key
nullable: false
type:
type: string
string: {}
- name: value
nullable: false
type:
type: double
double: {}
이 정의를 저장한 뒤 코드 생성을 실행하고 생성한 입력, 출력 및 factory 인터페이스를 구현합니다. 생성된 클래스가 없는 일반 Java 프로젝트에 구현 코드만 복사하는 방식으로 실행할 수는 없습니다.
Custom type
기본형, array, map과 struct 모두에 별칭을 붙일 수 있습니다. 특히 같은 struct가 입력과 출력에서 반복될 때 유용합니다. customTypes.types를 생략하지 않아야 합니다.
다음은 같은 구조체를 두 스키마에서 재사용하는 전체 정의 예입니다.
name: StructMapping
type: DEFAULT
arguments: {}
customTypes:
types:
customStruct:
type: struct
struct:
fields:
- name: doubleField
nullable: false
type:
type: double
double: {}
inputSchema:
name: Input
fields:
- name: inputStruct
nullable: false
type:
type: custom
custom: customStruct
outputSchema:
name: Output
fields:
- name: outputStruct
nullable: false
type:
type: custom
custom: customStruct
type: custom의 custom 값은 위에서 정의한 이름입니다. 이 경우 생성기는 별도 InputStruct와 OutputStruct 대신 같은 CustomStruct 클래스를 재사용합니다. 입력의 input.inputStruct()가 반환한 유형을 출력의 output.outputStruct(...)도 받을 수 있어 구조가 같은 객체를 별도 클래스로 다시 변환할 필요가 없습니다.