You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在EC2 Java服务中解压Hadoop Parquet+Snappy压缩文件?

正确解压Hadoop Parquet+Snappy文件的方法

问题根源

你直接用SnappyDecompressor或SnappyInputStream读取Parquet文件的方式是错误的:Parquet的Snappy压缩是针对文件内部的列数据块做的压缩,并非整个文件被Snappy包裹,不能直接用Snappy的基础解压工具读取。另外UnsatisfiedLinkError是因为Hadoop的Snappy实现依赖平台本地库(native library),EC2环境中可能缺少对应库或配置不当。

正确解决方案

1. 引入正确的依赖

在你的Java项目中,需要引入Parquet的读取依赖(因为你用AvroParquetWriter写入,优先用parquet-avro),同时确保Hadoop相关依赖正确:

Maven依赖示例:

<dependencies>
    <!-- Parquet Avro 读取依赖 -->
    <dependency>
        <groupId>org.apache.parquet</groupId>
        <artifactId>parquet-avro</artifactId>
        <version>1.14.0</version>
    </dependency>
    <!-- Hadoop Common 用于处理S3和压缩 -->
    <dependency>
        <groupId>org.apache.hadoop</groupId>
        <artifactId>hadoop-common</artifactId>
        <version>3.3.6</version>
        <exclusions>
            <!-- 排除冲突依赖,按需调整 -->
            <exclusion>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-log4j12</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
    <!-- AWS SDK 用于读取S3对象 -->
    <dependency>
        <groupId>software.amazon.awssdk</groupId>
        <artifactId>s3</artifactId>
        <version>2.25.0</version>
    </dependency>
</dependencies>

2. 使用ParquetReader读取文件(自动处理Snappy解压)

不需要手动调用Snappy解压工具,用AvroParquetReader可以直接读取用AvroParquetWriter写入的Parquet文件,框架会自动识别并处理Snappy压缩:

import org.apache.parquet.avro.AvroParquetReader;
import org.apache.parquet.hadoop.ParquetReader;
import org.apache.parquet.hadoop.util.HadoopInputFile;
import org.apache.hadoop.fs.Path;
import software.amazon.awssdk.auth.credentials.DefaultCredentialsProvider;
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.model.GetObjectRequest;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

// 假设你的Avro生成的类是MyRecord
public class ParquetSnappyReader {
    public static List<MyRecord> readParquetFromS3(String bucketName, String key) throws Exception {
        // 初始化S3客户端
        S3Client s3Client = S3Client.builder()
                .region(Region.US_EAST_1) // 替换为你的区域
                .credentialsProvider(DefaultCredentialsProvider.create())
                .build();

        // 获取S3对象输入流
        GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                .bucket(bucketName)
                .key(key)
                .build();
        InputStream s3InputStream = s3Client.getObject(getObjectRequest);

        // 将S3路径转换为Hadoop InputFile
        Path parquetPath = new Path("s3://" + bucketName + "/" + key);
        HadoopInputFile inputFile = HadoopInputFile.fromPath(parquetPath, new org.apache.hadoop.conf.Configuration());

        // 创建AvroParquetReader并读取数据
        try (ParquetReader<MyRecord> reader = AvroParquetReader.<MyRecord>builder(inputFile)
                .withConf(new org.apache.hadoop.conf.Configuration())
                .build()) {

            List<MyRecord> records = new ArrayList<>();
            MyRecord record;
            while ((record = reader.read()) != null) {
                records.add(record);
            }
            return records;
        } finally {
            s3InputStream.close();
            s3Client.close();
        }
    }
}

3. 解决UnsatisfiedLinkError的补充方案

如果运行时仍然出现本地库相关错误,需要在EC2实例上安装Snappy本地库,并配置Hadoop的native library路径:

  • 安装Snappy(以Amazon Linux 2为例):
sudo yum install snappy snappy-devel
  • 在Java启动参数中指定Hadoop本地库路径(路径根据你的Hadoop版本和安装位置调整):
-Djava.library.path=/usr/lib64/hadoop/lib/native/

或者在代码中配置:

System.setProperty("java.library.path", "/usr/lib64/hadoop/lib/native/");

关键注意事项

  • 不要直接用Snappy的基础解压工具处理Parquet文件,必须用Parquet专用读取框架。
  • 确保依赖版本匹配:parquet-avro、hadoop-common的版本尽量和Flink作业中使用的版本一致,避免兼容性问题。
  • EC2实例的IAM权限需要允许读取目标S3 bucket的对象。

内容的提问来源于stack exchange,提问作者priyadhingra19

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.21 14:15:13