복합 타입 예제 - Unnest
복합 타입 예제 - Unnest (Complex Type Examples (Unnest))
복합 타입 처리를 실제 JSON 레코드와 스키마, 테이블 구성으로 보여 주는 예제 모음이에요.
본문
복합 타입 처리를 보여 주는 추가 예제입니다.
루트 레벨 컬렉션 Unnest
이 예제에서는 루트 레벨의 단일 키로 묶인 JSON 레코드를 unnest합니다. ComplexType 구성을 사용해 각 학생 레코드를 Pinot의 개별 행으로 저장합니다.
샘플 JSON 레코드
{
"students": [
{
"firstName": "Jane",
"id": "100",
"scores": {
"physics": 91,
"chemistry": 93,
"maths": 99
}
},
{
"firstName": "John",
"id": "101",
"scores": {
"physics": 97,
"chemistry": 98,
"maths": 99
}
},
{
"firstName": "Jen",
"id": "102",
"scores": {
"physics": 96,
"chemistry": 95,
"maths": 100
}
}
]
}
Pinot 스키마
{
"schemaName": "students001",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "students.firstName",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.id",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.scores",
"dataType": "JSON",
"notNull": false,
"fieldType": "DIMENSION"
}
],
"dateTimeFieldSpecs": [
{
"name": "ts",
"fieldType": "DATE_TIME",
"dataType": "LONG",
"format": "1:MILLISECONDS:EPOCH",
"granularity": "1:MILLISECONDS"
}
],
"metricFieldSpecs": []
}
Pinot 테이블 구성
{
"ingestionConfig": {
"complexTypeConfig": {
"fieldsToUnnest": [
"students"
]
}
}
}
Pinot 속 데이터
수집 후 학생 레코드는 Pinot에서 개별 레코드로 나타납니다. 중첩 필드 scores는 JSON 필드로 캡처됩니다.
형제 컬렉션 Unnest
이 예제에서는 형제 컬렉션인 "student"와 "teacher"를 unnest합니다.
샘플 JSON 레코드
{
"student": [
{
"name": "John"
},
{
"name": "Jane"
}
],
"teacher": [
{
"physics": "Kim"
},
{
"chemistry": "Lu"
},
{
"maths": "Walsh"
}
]
}
Pinot 스키마
{
"schemaName": "students002",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "student.name",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
},
{
"name": "teacher.physics",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
},
{
"name": "teacher.chemistry",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
},
{
"name": "teacher.maths",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
}
]
}
Pinot 테이블 구성
"complexTypeConfig": {
"fieldsToUnnest": [
"student",
"teacher"
]
}
중첩 컬렉션 Unnest
이 예제에서는 중첩 컬렉션 "students.grades"를 unnest합니다.
샘플 JSON 레코드
{
"students": [
{
"name": "Jane",
"grades": [
{
"physics": "A+"
},
{
"maths": "A-"
}
]
},
{
"name": "John",
"grades": [
{
"physics": "B+"
},
{
"maths": "B-"
}
]
}
]
}
Pinot 스키마
{
"schemaName": "students003",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "students.name",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
},
{
"name": "students.grades.physics",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
},
{
"name": "students.grades.maths",
"dataType": "STRING",
"fieldType": "DIMENSION",
"notNull": false
}
]
}
Pinot 테이블 구성
"complexTypeConfig": {
"fieldsToUnnest": [
"students",
"students.grades"
]
}
다중 레벨 배열 Unnest
이 예제에서는 배열 "students" 안에 위치한 배열 "finalExam"을 unnest합니다.
샘플 JSON 레코드
{
"students": [
{
"name": "John",
"grades": {
"finalExam": [
{
"physics": "A+"
},
{
"maths": "A-"
}
]
}
},
{
"name": "Jane",
"grades": {
"finalExam": [
{
"physics": "B+"
},
{
"maths": "B-"
}
]
}
}
]
}
Pinot 스키마
{
"schemaName": "students004",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "students.name",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.grades.finalExam.physics",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.grades.finalExam.maths",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
}
]
}
Pinot 테이블 구성
"complexTypeConfig": {
"fieldsToUnnest": [
"students",
"students.grades.finalExam"
]
}
내부 컬렉션 변환
이 예제에서는 내부 컬렉션 "grades"를 멀티-밸류 문자열 컬럼으로 변환합니다.
샘플 JSON 레코드
{
"students": [
{
"name": "John",
"grades": [
{
"physics": "A+"
},
{
"maths": "A"
}
]
},
{
"name": "Jane",
"grades": [
{
"physics": "B+"
},
{
"maths": "B-"
}
]
}
]
}
Pinot 스키마
{
"schemaName": "students005",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "students.name",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.grades",
"dataType": "STRING",
"notNull": false,
"isSingleValue": false,
"fieldType": "DIMENSION"
}
]
}
Pinot 테이블 구성
"complexTypeConfig": {
"fieldsToUnnest": [
"students"
]
}
프리미티브 배열을 JSON 문자열로 변환
이 예제에서는 프리미티브 배열 "extra\_curricular"를 JSON 문자열로 변환합니다.
샘플 JSON 레코드
{
"students": [
{
"name": "John",
"extra_curricular": [
"piano", "soccer"
]
},
{
"name": "Jane",
"extra_curricular": [
"violin", "music"
]
}
]
}
Pinot 스키마
{
"schemaName": "students006",
"enableColumnBasedNullHandling": false,
"dimensionFieldSpecs": [
{
"name": "students.name",
"dataType": "STRING",
"notNull": false,
"fieldType": "DIMENSION"
},
{
"name": "students.extra_curricular",
"dataType": "JSON",
"notNull": false,
"fieldType": "DIMENSION"
}
]
}
Pinot 테이블 구성
"complexTypeConfig": {
"fieldsToUnnest": [
"students"
],
"collectionNotUnnestedToJson": "ALL"
}
JsonArrayString 컬렉션 Unnest
이 예제에서 데이터는 STRING 타입이고, 내용은 문자열로 인코딩된 JSON ARRAY입니다.
이 경우 STRING 필드에서는 Unnest가 자동으로 일어나지 않습니다.
사용자는 먼저 STRING 필드를 ARRAY 또는 MAP 필드로 변환한 후 unnest를 수행해야 합니다. 단계는 다음과 같습니다:
enrichmentConfigs를 사용해jsonStringToListOrMap(data_for_unnesting)함수로 중간 컬럼recordArray를 만듭니다.
"enrichmentConfigs": [
{
"enricherType": "generateColumn",
"properties": {"fieldToFunctionMap":{"recordArray":"jsonStringToListOrMap(data_for_unnesting)"}},
"preComplexTypeTransform": true
}
],
- 외부 필드
recordArray를 unnest하도록complexTypeConfig를 구성해recordArray||name필드를 생성합니다.
"complexTypeConfig": {
"fieldsToUnnest": [
"recordArray"
],
"delimiter": "||"
},
샘플 레코드
{
"key": "value",
"data_for_unnesting": [
{
"name": "record1"
},
{
"name": "record2"
},
{
"name": "record3"
}
],
"event_time": "2025-04-24T20:45:56.721936"
}
Pinot 스키마
참고: 수집할 필드는
data_for_unnesting||name가 아니라recordArray||name입니다.
{
"schemaName": "testUnnest",
"enableColumnBasedNullHandling": true,
"dimensionFieldSpecs": [
{
"name": "key",
"dataType": "STRING",
"fieldType": "DIMENSION"
},
{
"name": "recordArray||name",
"dataType": "STRING",
"fieldType": "DIMENSION"
}
],
"dateTimeFieldSpecs": [
{
"name": "event_time",
"dataType": "LONG",
"fieldType": "DATE_TIME",
"format": "EPOCH|MILLISECONDS|1",
"granularity": "MILLISECONDS|1"
}
]
}
Pinot 테이블 구성
{
"tableName": "testUnnest_OFFLINE",
"tableType": "OFFLINE",
"segmentsConfig": {
"deletedSegmentsRetentionPeriod": "0d",
"segmentPushType": "APPEND",
"timeColumnName": "event_time",
"retentionTimeUnit": "DAYS",
"retentionTimeValue": "180",
"minimizeDataMovement": false,
"replication": "1"
},
"tenants": {
"broker": "DefaultTenant",
"server": "DefaultTenant"
},
"tableIndexConfig": {
"aggregateMetrics": false,
"optimizeDictionary": false,
"autoGeneratedInvertedIndex": false,
"enableDefaultStarTree": false,
"nullHandlingEnabled": true,
"skipSegmentPreprocess": false,
"optimizeDictionaryType": false,
"enableDynamicStarTreeCreation": false,
"columnMajorSegmentBuilderEnabled": true,
"createInvertedIndexDuringSegmentGeneration": true,
"optimizeDictionaryForMetrics": false,
"noDictionarySizeRatioThreshold": 0,
"loadMode": "MMAP",
"rangeIndexVersion": 2,
"invertedIndexColumns": [
"key"
],
"varLengthDictionaryColumns": [
"key"
]
},
"metadata": {},
"ingestionConfig": {
"transformConfigs": [],
"enrichmentConfigs": [
{
"enricherType": "generateColumn",
"properties": {"fieldToFunctionMap":{"recordArray":"jsonStringToListOrMap(data_for_unnesting)"}},
"preComplexTypeTransform": true
}
],
"continueOnError": true,
"rowTimeValueCheck": true,
"complexTypeConfig": {
"fieldsToUnnest": [
"recordArray"
],
"delimiter": "||"
},
"retryOnSegmentBuildPrecheckFailure": false,
"segmentTimeValueCheck": false
},
"isDimTable": false
}