Apache Parquet 파일 구조
Apache Parquet는 컬럼 지향형(columnar) 저장 형식을 채택한 고성능 분석용 파일 포맷임.
분산 시스템(예: Hadoop, Spark)에서 효율적인 저장 및 분석 작업을 하기 위해 설계되었으며, 적절한 인덱싱과 압축, 인코딩 방식을 결합함으로써 높은 성능을 제공함.
내부 구조는 크게 File Header, File Footer, 그리고 그 사이를 구성하는 Row Group(안에는 여러 column chunk 및 page가 존재)으로 나눌 수 있음.
전체적인 파일 구조
Parquet 파일은 논리적으로 다음과 같은 구성을 가짐.
+-------------------+--------------------------+-----------------+
| File Header | Row Groups | File Footer |
| |(각각 내부에 Column Chunks | (Metadata, |
| | + Pages) | Schema 정보 등) |
+-------------------+--------------------------+-----------------+
1. File Header
매직 넘버(“PAR1”)와 같은 시그니처 정보를 통해 파일이 Parquet 파일임을 식별할 수 있음.
일반적으로 파일을 열었을 때 가장 처음에 등장하는 4바이트 매직 넘버가 PAR1로 설정되어 있음.
파일 접근 시, 이 시그니처를 통해 포맷이 맞는지 빠르게 검증할 수 있음.
2. Row Groups
Parquet 파일은 하나 이상의 Row Group을 가짐.
Row Group은 논리적으로 비슷한(연속된) 레코드들의 묶음이며, 일반적으로 개별 Row Group 단위로 처리가 이루어짐.
분산 환경에서 Row Group 단위로 읽기/쓰기가 이루어지므로 큰 파일을 여러 작업자(Task)가 병렬로 처리하기에 용이함.
각 Row Group 안에는 여러 Column Chunk가 있으며, 각각의 Column Chunk는 한 컬럼의 데이터를 모아서 저장함.
3. File Footer
파일의 끝 부분에 존재하며, 전체 파일 메타데이터(스키마, 컬럼 통계, 각 Row Group의 메타데이터 등)가 기록됨.
File Footer에는 다시 한 번 매직 넘버 “PAR1”이 뒤집힌 형태(“1RAP”)로 기록되어 있으며, Footer의 길이 정보도 들어 있어 랜덤 접근이 가능함.
분석 엔진은 Footer의 메타데이터를 참조해 필요한 컬럼 및 Row Group을 빠르게 찾고, 선택적으로 읽을 수 있음.
Row Group과 Column Chunk
1. Row Group
Row Group은 Parquet의 기본 단위임.
보통 수백 MB(예: 128MB ~ 1GB 수준) 정도의 데이터를 한 Row Group으로 묶는 경우가 많음.
Row Group 내에는 테이블(혹은 데이터셋)의 모든 컬럼에 대한 Column Chunk가 동일한 ‘행 범위’를 기준으로 저장됨.
예컨대 1억 건의 레코드가 있을 때, 8천만 ~ 9천만 번 레코드가 한 Row Group에 포함된다고 하면, 그 구간에 해당하는 모든 컬럼이 함께 묶여 있음.
2. Column Chunk
Row Group 내에서 특정 컬럼만을 모은 저장 단위임.
즉 “Row Group N번에서 컬럼 C를 담는 Chunk”가 하나의 Column Chunk가 됨.
Parquet가 컬럼 지향 방식을 채택한다는 것은 실제로 디스크에 쓰일 때 Row Group 단위로 구분된 컬럼 데이터가 각각 순차적으로 저장된다는 의미임.
Column Chunk는 한 컬럼의 데이터만 저장하므로, 압축 및 인코딩 등에 유리함.
예를 들어, 문자열 컬럼에는 사전(dictionary) 인코딩을 적용하거나, 반복되는 작은 정수형 컬럼에 대해 RLE(run-length encoding) 등을 적용할 수 있게 됨.
Page 구조
각 Column Chunk는 또 더 작은 단위인 Page들로 나뉨.
페이지들은 보통 약 수백 KB(예: 8KB ~ 1MB) 단위로 잘려 저장되며, 적절한 크기로 잘라야 검색과 디스크 I/O 효율이 좋아짐.
1. Data Page
실제 해당 컬럼의 행 데이터가 저장되는 페이지임.
Page Header(데이터가 어떤 방식으로 인코딩, 압축되었는지 등 메타데이터), Data Body(실제 인코딩/압축된 데이터)로 구성됨.
Parquet V2 기준으로는 Data Page V2가 정의되어 있어, null mask나 데이터/인덱스/디코딩 방식 등을 효율적으로 표현하고 있음.
2. Dictionary Page
사전(dictionary) 인코딩을 사용하고 있을 때, 사전에 해당하는 실제 유니크 문자열(또는 값들) 목록이 별도의 페이지로 저장됨.
이후 Data Page에서는 사전에 대한 인덱스(예: 0번, 1번, 2번 …)만 기록하여 저장 공간을 크게 절약할 수 있음.
사전 페이지는 보통 해당 Column Chunk에서 최초로 등장하는 페이지로 저장됨.
3. Index Page (선택적)
Parquet 형식에서는 일부 구현에서 컬럼별 통계(최솟값, 최댓값, null count 등)를 보다 세밀히 관리하기 위해 Index Page 개념을 사용할 수 있음.
데이터의 빠른 검색(skip)을 위해 Page 단위의 범위 정보를 별도로 저장하기도 함.
요약하면, 한 Column Chunk 내에는 사전 페이지(옵션), 인덱스 페이지(옵션), 여러 개의 데이터 페이지들이 순서대로 존재할 수 있음.
메타데이터 구조
1. File Metadata (File Footer)
파일의 Footer에는 전체 파일에 대한 메타데이터가 저장되어 있음.
구체적으로 다음 정보가 포함됨.
1-1. Schema
각 컬럼의 데이터 타입, 중첩 스키마(Parquet는 중첩 구조 지원), 각 필드의 Repetition Level / Definition Level 등의 정보가 들어 있음.
1-2. Row Group 메타데이터
파일에 존재하는 모든 Row Group에 대한 리스트가 있음.
각 Row Group이 어떤 바이트 오프셋(offset) 구간을 갖는지, 총 몇 개의 레코드가 들어 있는지, 각 컬럼별 Chunk의 압축/인코딩/통계 정보 등이 기록됨.
1-3. Column Statistics
각 컬럼의 최솟값/최댓값, Null 개수, Distinct 개수(선택적)와 같은 통계 정보가 들어 있음.
쿼리 엔진이 이런 메타데이터를 이용해 빠르게 프루닝(pruning)할 수 있음.
예를 들어, “WHERE 컬럼C > 1000”인 경우, 최댓값이 999인 Row Group은 스킵할 수 있음.
1-4. Key-Value Metadata(사용자 정의 메타데이터)
사용자 혹은 라이브러리에서 임의로 삽입할 수 있는 추가 메타데이터가 저장될 수 있음.
예를 들어, Spark에서의 특정 Job 정보나, 라이브러리 버전 정보 등.
2. Column Metadata
각 Column Chunk마다 별도의 메타데이터 구조가 존재하며, 다음과 같은 항목들을 갖음.
2-1. Type (예: INT32, INT64, FLOAT, DOUBLE, BYTE_ARRAY 등)
2-2. Encodings (PLAIN, RLE, BIT_PACKED, DELTA, DICTIONARY 등)
2-3. Path in Schema (중첩 스키마를 지원할 경우, “message > nested1 > fieldX”처럼 경로로 표현)
2-4. Statistics (최솟값, 최댓값, null 수 등)
2-5. Compression (SNAPPY, GZIP, ZSTD, LZ4 등)
2-6. Data Page 정보 (각 페이지의 크기, 개수, 오프셋 등)
Parquet에서의 인코딩 및 압축
1. 인코딩(Encoding)
1-1. PLAIN
기본적으로 원본 바이너리 표현 그대로를 저장하는 방식임. (예: 32비트 정수 그대로)
1-2. Dictionary Encoding
문자열처럼 중복이 많을 때, 고유한 값들을 “사전 페이지”에 저장하고 각 행 값은 사전의 인덱스만 기록하여 공간을 절약함.
1-3. RLE (Run-length Encoding)
같은 값이 연속되는 구간을 [반복 길이, 값] 형식으로 압축함.
특히 Parquet는 Definition Level이나 Repetition Level에서 RLE/비트패킹을 적극 사용함.
1-4. DELTA Encoding
숫자(정수) 데이터를 인접 값의 차이(Δ)로 저장하여, 많은 경우 차이가 작으면 더 짧은 길이로 인코딩할 수 있음.
1-5. BIT_PACKED
특정 열의 범위가 작을 때, 정해진 비트만으로 값을 표현해 압축률을 높이는 기법임.
2. 압축(Compression)
각 페이지는 별도의 압축 코덱을 통해 추가로 압축될 수 있음.
Parquet은 컬럼 단위로 압축을 적용하므로, 서로 다른 컬럼에 대해 다른 압축을 적용하는 것도 가능함.
예컨대 문자열 컬럼엔 SNAPPY, 정수형 컬럼에는 GZIP를 사용할 수도 있음.
대표적으로 다음 코덱이 많이 사용됨.
2-1. SNAPPY: 구글에서 만든 빠른 압축 알고리즘, 데이터 웨어하우스/분산 환경에서 많이 쓰임
2-2. GZIP: 전통적이지만 높은 압축률, CPU 사용량이 다소 많음
2-3. LZ4: 빠른 압축 및 압축 해제 속도
2-4. ZSTD: 다양한 압축 레벨을 지원하며, 성능과 압축률이 모두 우수
Parquet 장점 요약
1. 컬럼 지향 저장: 특정 컬럼만 읽어도 되기 때문에, SELECT 쿼리에서 필요한 컬럼만 효율적으로 로딩할 수 있어 I/O가 절감됨.
2. Row Group 기반 병렬 처리: 여러 Row Group을 병렬로 읽고 쓸 수 있으므로 대규모 분산 처리에 적합함.
3. 효과적인 압축/인코딩: 컬럼 단위로 한 종류의 데이터가 모여 있어, 반복 패턴을 찾기 쉬우며 높은 압축률을 기대할 수 있음.
4. 풍부한 메타데이터 활용: 파일 Footer와 Column Chunk 통계 정보를 기반으로, 필요 없는 데이터 범위를 건너뛰는 등 쿼리 최적화가 가능해짐.
5. 대규모 처리 엔진과의 호환성: Spark, Hive, Impala 등 다양한 빅데이터 프레임워크가 Parquet을 기본으로 지원함.
정리
Apache Parquet 파일은 크게 Header, Row Group, Footer로 구성됨.
1. Header: 매직 넘버 “PAR1”
2. Row Group: 동일한 범위의 행들을 모아두는 묶음, 내부에 컬럼별 Column Chunk가 존재
3. Column Chunk: 같은 컬럼의 데이터를 페이지(Page) 단위로 저장
4. Page: Data Page, Dictionary Page, (선택적으로) Index Page 등으로 구성
5. Footer: 전체 스키마, Row Group 메타데이터, 컬럼 통계, 사용자 정의 키-값 메타데이터 등
컬럼 지향 구조로써 효율적 압축, 인코딩, 통계 정보 기반의 스킵 처리를 통해 대규모 분석 환경에서 성능을 극대화함.
이런 내부 구조를 이해하면, 더 나은 클러스터 구성, I/O 최적화, 쿼리 성능 향상 등에 많은 도움이 됨.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Apache Iceberg (2) | 2025.03.14 |
---|---|
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |
[Spark] Spark Application 실행 과정 (1) | 2025.03.08 |
[Spark] Adaptive Query Execution (0) | 2025.01.17 |
[Spark] Apache Spark의 Job, Stage, Task 구조 (0) | 2025.01.17 |
Apache Parquet 파일 구조
Apache Parquet는 컬럼 지향형(columnar) 저장 형식을 채택한 고성능 분석용 파일 포맷임.
분산 시스템(예: Hadoop, Spark)에서 효율적인 저장 및 분석 작업을 하기 위해 설계되었으며, 적절한 인덱싱과 압축, 인코딩 방식을 결합함으로써 높은 성능을 제공함.
내부 구조는 크게 File Header, File Footer, 그리고 그 사이를 구성하는 Row Group(안에는 여러 column chunk 및 page가 존재)으로 나눌 수 있음.
전체적인 파일 구조
Parquet 파일은 논리적으로 다음과 같은 구성을 가짐.
+-------------------+--------------------------+-----------------+
| File Header | Row Groups | File Footer |
| |(각각 내부에 Column Chunks | (Metadata, |
| | + Pages) | Schema 정보 등) |
+-------------------+--------------------------+-----------------+
1. File Header
매직 넘버(“PAR1”)와 같은 시그니처 정보를 통해 파일이 Parquet 파일임을 식별할 수 있음.
일반적으로 파일을 열었을 때 가장 처음에 등장하는 4바이트 매직 넘버가 PAR1로 설정되어 있음.
파일 접근 시, 이 시그니처를 통해 포맷이 맞는지 빠르게 검증할 수 있음.
2. Row Groups
Parquet 파일은 하나 이상의 Row Group을 가짐.
Row Group은 논리적으로 비슷한(연속된) 레코드들의 묶음이며, 일반적으로 개별 Row Group 단위로 처리가 이루어짐.
분산 환경에서 Row Group 단위로 읽기/쓰기가 이루어지므로 큰 파일을 여러 작업자(Task)가 병렬로 처리하기에 용이함.
각 Row Group 안에는 여러 Column Chunk가 있으며, 각각의 Column Chunk는 한 컬럼의 데이터를 모아서 저장함.
3. File Footer
파일의 끝 부분에 존재하며, 전체 파일 메타데이터(스키마, 컬럼 통계, 각 Row Group의 메타데이터 등)가 기록됨.
File Footer에는 다시 한 번 매직 넘버 “PAR1”이 뒤집힌 형태(“1RAP”)로 기록되어 있으며, Footer의 길이 정보도 들어 있어 랜덤 접근이 가능함.
분석 엔진은 Footer의 메타데이터를 참조해 필요한 컬럼 및 Row Group을 빠르게 찾고, 선택적으로 읽을 수 있음.
Row Group과 Column Chunk
1. Row Group
Row Group은 Parquet의 기본 단위임.
보통 수백 MB(예: 128MB ~ 1GB 수준) 정도의 데이터를 한 Row Group으로 묶는 경우가 많음.
Row Group 내에는 테이블(혹은 데이터셋)의 모든 컬럼에 대한 Column Chunk가 동일한 ‘행 범위’를 기준으로 저장됨.
예컨대 1억 건의 레코드가 있을 때, 8천만 ~ 9천만 번 레코드가 한 Row Group에 포함된다고 하면, 그 구간에 해당하는 모든 컬럼이 함께 묶여 있음.
2. Column Chunk
Row Group 내에서 특정 컬럼만을 모은 저장 단위임.
즉 “Row Group N번에서 컬럼 C를 담는 Chunk”가 하나의 Column Chunk가 됨.
Parquet가 컬럼 지향 방식을 채택한다는 것은 실제로 디스크에 쓰일 때 Row Group 단위로 구분된 컬럼 데이터가 각각 순차적으로 저장된다는 의미임.
Column Chunk는 한 컬럼의 데이터만 저장하므로, 압축 및 인코딩 등에 유리함.
예를 들어, 문자열 컬럼에는 사전(dictionary) 인코딩을 적용하거나, 반복되는 작은 정수형 컬럼에 대해 RLE(run-length encoding) 등을 적용할 수 있게 됨.
Page 구조
각 Column Chunk는 또 더 작은 단위인 Page들로 나뉨.
페이지들은 보통 약 수백 KB(예: 8KB ~ 1MB) 단위로 잘려 저장되며, 적절한 크기로 잘라야 검색과 디스크 I/O 효율이 좋아짐.
1. Data Page
실제 해당 컬럼의 행 데이터가 저장되는 페이지임.
Page Header(데이터가 어떤 방식으로 인코딩, 압축되었는지 등 메타데이터), Data Body(실제 인코딩/압축된 데이터)로 구성됨.
Parquet V2 기준으로는 Data Page V2가 정의되어 있어, null mask나 데이터/인덱스/디코딩 방식 등을 효율적으로 표현하고 있음.
2. Dictionary Page
사전(dictionary) 인코딩을 사용하고 있을 때, 사전에 해당하는 실제 유니크 문자열(또는 값들) 목록이 별도의 페이지로 저장됨.
이후 Data Page에서는 사전에 대한 인덱스(예: 0번, 1번, 2번 …)만 기록하여 저장 공간을 크게 절약할 수 있음.
사전 페이지는 보통 해당 Column Chunk에서 최초로 등장하는 페이지로 저장됨.
3. Index Page (선택적)
Parquet 형식에서는 일부 구현에서 컬럼별 통계(최솟값, 최댓값, null count 등)를 보다 세밀히 관리하기 위해 Index Page 개념을 사용할 수 있음.
데이터의 빠른 검색(skip)을 위해 Page 단위의 범위 정보를 별도로 저장하기도 함.
요약하면, 한 Column Chunk 내에는 사전 페이지(옵션), 인덱스 페이지(옵션), 여러 개의 데이터 페이지들이 순서대로 존재할 수 있음.
메타데이터 구조
1. File Metadata (File Footer)
파일의 Footer에는 전체 파일에 대한 메타데이터가 저장되어 있음.
구체적으로 다음 정보가 포함됨.
1-1. Schema
각 컬럼의 데이터 타입, 중첩 스키마(Parquet는 중첩 구조 지원), 각 필드의 Repetition Level / Definition Level 등의 정보가 들어 있음.
1-2. Row Group 메타데이터
파일에 존재하는 모든 Row Group에 대한 리스트가 있음.
각 Row Group이 어떤 바이트 오프셋(offset) 구간을 갖는지, 총 몇 개의 레코드가 들어 있는지, 각 컬럼별 Chunk의 압축/인코딩/통계 정보 등이 기록됨.
1-3. Column Statistics
각 컬럼의 최솟값/최댓값, Null 개수, Distinct 개수(선택적)와 같은 통계 정보가 들어 있음.
쿼리 엔진이 이런 메타데이터를 이용해 빠르게 프루닝(pruning)할 수 있음.
예를 들어, “WHERE 컬럼C > 1000”인 경우, 최댓값이 999인 Row Group은 스킵할 수 있음.
1-4. Key-Value Metadata(사용자 정의 메타데이터)
사용자 혹은 라이브러리에서 임의로 삽입할 수 있는 추가 메타데이터가 저장될 수 있음.
예를 들어, Spark에서의 특정 Job 정보나, 라이브러리 버전 정보 등.
2. Column Metadata
각 Column Chunk마다 별도의 메타데이터 구조가 존재하며, 다음과 같은 항목들을 갖음.
2-1. Type (예: INT32, INT64, FLOAT, DOUBLE, BYTE_ARRAY 등)
2-2. Encodings (PLAIN, RLE, BIT_PACKED, DELTA, DICTIONARY 등)
2-3. Path in Schema (중첩 스키마를 지원할 경우, “message > nested1 > fieldX”처럼 경로로 표현)
2-4. Statistics (최솟값, 최댓값, null 수 등)
2-5. Compression (SNAPPY, GZIP, ZSTD, LZ4 등)
2-6. Data Page 정보 (각 페이지의 크기, 개수, 오프셋 등)
Parquet에서의 인코딩 및 압축
1. 인코딩(Encoding)
1-1. PLAIN
기본적으로 원본 바이너리 표현 그대로를 저장하는 방식임. (예: 32비트 정수 그대로)
1-2. Dictionary Encoding
문자열처럼 중복이 많을 때, 고유한 값들을 “사전 페이지”에 저장하고 각 행 값은 사전의 인덱스만 기록하여 공간을 절약함.
1-3. RLE (Run-length Encoding)
같은 값이 연속되는 구간을 [반복 길이, 값] 형식으로 압축함.
특히 Parquet는 Definition Level이나 Repetition Level에서 RLE/비트패킹을 적극 사용함.
1-4. DELTA Encoding
숫자(정수) 데이터를 인접 값의 차이(Δ)로 저장하여, 많은 경우 차이가 작으면 더 짧은 길이로 인코딩할 수 있음.
1-5. BIT_PACKED
특정 열의 범위가 작을 때, 정해진 비트만으로 값을 표현해 압축률을 높이는 기법임.
2. 압축(Compression)
각 페이지는 별도의 압축 코덱을 통해 추가로 압축될 수 있음.
Parquet은 컬럼 단위로 압축을 적용하므로, 서로 다른 컬럼에 대해 다른 압축을 적용하는 것도 가능함.
예컨대 문자열 컬럼엔 SNAPPY, 정수형 컬럼에는 GZIP를 사용할 수도 있음.
대표적으로 다음 코덱이 많이 사용됨.
2-1. SNAPPY: 구글에서 만든 빠른 압축 알고리즘, 데이터 웨어하우스/분산 환경에서 많이 쓰임
2-2. GZIP: 전통적이지만 높은 압축률, CPU 사용량이 다소 많음
2-3. LZ4: 빠른 압축 및 압축 해제 속도
2-4. ZSTD: 다양한 압축 레벨을 지원하며, 성능과 압축률이 모두 우수
Parquet 장점 요약
1. 컬럼 지향 저장: 특정 컬럼만 읽어도 되기 때문에, SELECT 쿼리에서 필요한 컬럼만 효율적으로 로딩할 수 있어 I/O가 절감됨.
2. Row Group 기반 병렬 처리: 여러 Row Group을 병렬로 읽고 쓸 수 있으므로 대규모 분산 처리에 적합함.
3. 효과적인 압축/인코딩: 컬럼 단위로 한 종류의 데이터가 모여 있어, 반복 패턴을 찾기 쉬우며 높은 압축률을 기대할 수 있음.
4. 풍부한 메타데이터 활용: 파일 Footer와 Column Chunk 통계 정보를 기반으로, 필요 없는 데이터 범위를 건너뛰는 등 쿼리 최적화가 가능해짐.
5. 대규모 처리 엔진과의 호환성: Spark, Hive, Impala 등 다양한 빅데이터 프레임워크가 Parquet을 기본으로 지원함.
정리
Apache Parquet 파일은 크게 Header, Row Group, Footer로 구성됨.
1. Header: 매직 넘버 “PAR1”
2. Row Group: 동일한 범위의 행들을 모아두는 묶음, 내부에 컬럼별 Column Chunk가 존재
3. Column Chunk: 같은 컬럼의 데이터를 페이지(Page) 단위로 저장
4. Page: Data Page, Dictionary Page, (선택적으로) Index Page 등으로 구성
5. Footer: 전체 스키마, Row Group 메타데이터, 컬럼 통계, 사용자 정의 키-값 메타데이터 등
컬럼 지향 구조로써 효율적 압축, 인코딩, 통계 정보 기반의 스킵 처리를 통해 대규모 분석 환경에서 성능을 극대화함.
이런 내부 구조를 이해하면, 더 나은 클러스터 구성, I/O 최적화, 쿼리 성능 향상 등에 많은 도움이 됨.
'Data Engineering > Spark' 카테고리의 다른 글
[Spark] Apache Iceberg (2) | 2025.03.14 |
---|---|
[Spark] Apache ORC 파일 구조 (0) | 2025.03.09 |
[Spark] Spark Application 실행 과정 (1) | 2025.03.08 |
[Spark] Adaptive Query Execution (0) | 2025.01.17 |
[Spark] Apache Spark의 Job, Stage, Task 구조 (0) | 2025.01.17 |