Apache Parquet는 분석 워크로드를 대상으로 하는 열 기반 스토리지 형식이지만 모든 유형의 구조화된 데이터를 저장하는 데 사용할 수 있어 다양한 사용 사례를 처리합니다.
가장 주목할만한 기능 중 하나는 처리 프로세스의 두 단계에서 서로 다른 압축 기술을 사용하여 데이터를 효율적으로 압축하는 기능입니다. 이를 통해 스토리지 비용이 절감되고 읽기 성능이 향상됩니다.
이 기사에서는 Java에서 Parquet의 파일 압축을 설명하고 사용 예를 제공하며 성능을 분석합니다.
기존 행 기반 스토리지 형식과 달리 Parquet는 열 기반 접근 방식을 사용하므로 동일한 유형의 데이터에 대한 지역성과 가치 중복성을 기반으로 보다 구체적이고 효율적인 압축 기술을 사용할 수 있습니다.
Parquet는 정보를 바이너리 형식으로 기록하고 각각 다른 기술을 사용하는 두 가지 수준에서 압축을 적용합니다.
압축 알고리즘은 파일 수준에서 구성되지만 각 열의 인코딩은 내부 경험적 방법을 사용하여 자동으로 선택됩니다(적어도 parquet-java 구현에서는).
다양한 압축 기술의 성능은 데이터에 크게 좌우되므로 가장 빠른 처리 시간과 가장 낮은 스토리지 소비를 보장하는 만능 솔루션은 없습니다. 직접 테스트를 수행해야 합니다.
구성은 간단하며 작성 시 명시적인 설정만 필요합니다. 파일을 읽을 때 Parquet는 어떤 압축 알고리즘이 사용되는지 검색하고 해당 압축 해제 알고리즘을 적용합니다.
프로토콜 버퍼와 Avro를 사용하는 Carpet 및 Parquet에서 압축 알고리즘을 구성하려면 빌더의 withCompressionCodec 메소드를 호출하면 됩니다.
카펫
<code class="language-java">CarpetWriter<T> writer = new CarpetWriter.Builder<>(outputFile, clazz) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
아브로
<code class="language-java">ParquetWriter<Organization> writer = AvroParquetWriter.<Organization>builder(outputFile) .withSchema(new Organization().getSchema()) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
프로토콜 버퍼
<code class="language-java">ParquetWriter<Organization> writer = ProtoParquetWriter.<Organization>builder(outputFile) .withMessage(Organization.class) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
값은 CompressionCodecName 열거에서 사용 가능한 값 중 하나여야 합니다: UNCOMPRESSED, SNAPPY, GZIP, LZO, BROTLI, LZ4, ZSTD 및 LZ4_RAW(LZ4는 더 이상 사용되지 않으며 LZ4_RAW를 사용해야 함).
일부 압축 알고리즘은 압축 수준을 미세 조정하는 방법을 제공합니다. 이 수준은 일반적으로 반복 패턴을 찾는 데 필요한 노력과 관련이 있습니다. 압축 수준이 높을수록 압축 프로세스에 더 많은 시간과 메모리가 필요합니다.
기본값이 제공되지만 각 코덱마다 다른 키를 사용하더라도 Parquet의 일반 구성 메커니즘을 사용하여 수정할 수 있습니다.
또한 선택하는 값은 표준이 아니며 각 코덱에 따라 다르므로 각 레벨이 제공하는 내용을 이해하려면 각 알고리즘에 대한 설명서를 참조해야 합니다.
ZSTD
참조 레벨 구성을 위해 ZSTD 코덱은 상수 ZstandardCodec.PARQUET_COMPRESS_ZSTD_LEVEL
를 선언합니다.
가능한 값은 1~22이며, 기본값은 3입니다.
<code class="language-java">CarpetWriter<T> writer = new CarpetWriter.Builder<>(outputFile, clazz) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
LZO
참조 레벨 구성을 위해 LZO 코덱은 LzoCodec.LZO_COMPRESSION_LEVEL_KEY
상수를 선언합니다.
가능한 값은 1~9, 99, 999이며, 기본값은 '999'입니다.
<code class="language-java">ParquetWriter<Organization> writer = AvroParquetWriter.<Organization>builder(outputFile) .withSchema(new Organization().getSchema()) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
GZIP
상수를 선언하지 않으며 "zlib.compress.level" 문자열을 직접 사용해야 하며, 가능한 값은 0~9까지, 기본값은 "6"입니다.
<code class="language-java">ParquetWriter<Organization> writer = ProtoParquetWriter.<Organization>builder(outputFile) .withMessage(Organization.class) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
다양한 압축 알고리즘의 성능을 분석하기 위해 다양한 유형의 데이터가 포함된 두 개의 공개 데이터세트를 사용하겠습니다.
Parquet Java에서 활성화된 일부 압축 알고리즘(UNCOMPRESSED, SNAPPY, GZIP, LZO, ZSTD, LZ4_RAW)을 평가하겠습니다.
예상대로 parquet-java에서 제공하는 기본 구성과 각 알고리즘의 기본 압축 수준으로 Carpet을 사용할 예정입니다.
GitHub에서 소스 코드를 찾을 수 있으며, 테스트는 AMD Ryzen 7 4800HS CPU 및 JDK 17이 설치된 노트북에서 수행되었습니다.
각 압축의 성능을 이해하기 위해 해당 CSV 파일을 참조로 사용합니다.
格式 | gov.it | 纽约出租车 |
---|---|---|
CSV | 1761 MB | 2983 MB |
未压缩 | 564 MB | 760 MB |
SNAPPY | 220 MB | 542 MB |
GZIP | **146 MB** | 448 MB |
ZSTD | 148 MB | **430 MB** |
LZ4_RAW | 209 MB | 547 MB |
LZO | 215 MB | 518 MB |
두 가지 테스트 중 GZip과 Zstandard를 사용한 압축이 가장 효율적이었습니다.
Parquet 인코딩 기술만 사용하면 파일 크기를 원래 CSV 크기의 25%-32%까지 줄일 수 있습니다. 추가 압축을 적용하면 CSV 크기의 9%~15%로 줄어듭니다.
정보를 압축하면 얼마나 많은 오버헤드가 발생하나요?
동일한 정보를 세 번 쓰고 평균 초를 계산하면 다음과 같은 결과를 얻습니다.
算法 | gov.it | 纽约出租车 |
---|---|---|
未压缩 | 25.0 | 57.9 |
SNAPPY | 25.2 | 56.4 |
GZIP | 39.3 | 91.1 |
ZSTD | 27.3 | 64.1 |
LZ4_RAW | **24.9** | 56.5 |
LZO | 26.0 | **56.1** |
SNAPPY, LZ4 및 LZO는 압축하지 않은 상태와 비슷한 시간을 달성하는 반면 ZSTD는 약간의 오버헤드를 추가합니다. GZIP은 쓰기 시간이 50% 느려지는 등 최악의 성능을 보였습니다.
파일을 읽는 것은 쓰는 것보다 계산이 덜 필요하기 때문에 더 빠릅니다.
파일의 모든 열을 읽는 데 걸리는 시간(초)은 다음과 같습니다.
算法 | gov.it | 纽约出租车 |
---|---|---|
未压缩 | 11.4 | 37.4 |
SNAPPY | **12.5** | **39.9** |
GZIP | 13.6 | 40.9 |
ZSTD | 13.1 | 41.5 |
LZ4_RAW | 12.8 | 41.6 |
LZO | 13.1 | 41.1 |
읽는 시간은 비압축 정보에 가깝고 압축 해제 오버헤드는 10~20%입니다.
읽기 및 쓰기 시간 측면에서 다른 알고리즘보다 훨씬 나은 알고리즘은 없으며 모두 비슷한 범위에 있습니다. 대부분의 경우 정보를 압축하면 공간 절약(및 전송) 시간 손실을 보상할 수 있습니다.
이 두 가지 사용 사례에서 하나 또는 다른 알고리즘을 선택하는 결정 요인은 아마도 달성된 압축 비율일 것입니다. ZSTD와 Gzip이 두드러집니다(그러나 쓰기 시간은 열등함).
각 알고리즘에는 장점이 있으므로 가장 좋은 옵션은 데이터로 이를 테스트하고 어떤 요소가 더 중요한지 고려하는 것입니다.
인생의 모든 것과 마찬가지로 절충안이 있으며 이를 가장 잘 보상하는 것이 무엇인지 확인해야 합니다. Carpet에서는 아무것도 구성하지 않으면 기본적으로 압축을 위해 Snappy를 사용합니다.
값은 CompressionCodecName 열거에서 사용 가능한 값 중 하나여야 합니다. 각 열거형 값과 연관된 것은 알고리즘을 구현하는 클래스의 이름입니다:
<code class="language-java">CarpetWriter<T> writer = new CarpetWriter.Builder<>(outputFile, clazz) .withCompressionCodec(CompressionCodecName.ZSTD) .build();</code>
Parquet는 리플렉션을 사용하여 CompressionCodec 인터페이스를 구현해야 하는 지정된 클래스를 인스턴스화합니다. 소스 코드를 보면 Parquet이 아닌 Hadoop 프로젝트에 있음을 알 수 있습니다. 이는 Java 구현에서 Parquet가 Hadoop과 얼마나 잘 결합되어 있는지 보여줍니다.
이러한 코덱 중 하나를 사용하려면 해당 구현이 포함된 JAR을 종속성으로 추가했는지 확인해야 합니다.
parquet-java를 추가할 때 모든 구현이 전이적 종속성에 존재하지 않거나 Hadoop 종속성을 너무 적극적으로 제외할 수 있습니다.
org.apache.parquet:parquet-hadoop 종속성에 SnappyCodec, ZstandardCodec 및 Lz4RawCodec의 구현을 포함합니다. 이는 이 세 가지 알고리즘의 실제 구현과 함께 snappy-java, zstd-jni 및 aircompressor 종속성을 전이적으로 가져옵니다. .
hadoop-common:hadoop-common 종속성에는 GzipCodec 구현이 포함되어 있습니다.
BrotliCodec 및 LzoCodec 구현은 어디에 있나요? Parquet 또는 Hadoop 종속성에 속하지 않습니다. 따라서 추가 종속성을 추가하지 않고 사용하면 애플리케이션에서 해당 형식으로 압축된 파일을 사용할 수 없습니다.
위 내용은 Parquet Java의 압축 알고리즘의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!