本文为您介绍Parquet格式的OSS外部表的创建、读取及写入方法。
前提条件
已具备访问OSS的权限。阿里云账号(主账号)、RAM用户或RAMRole身份可以访问OSS外部表,授权信息请参见OSS的STS模式授权。
(可选)已准备好OSS存储空间(Bucket)、OSS目录及OSS数据文件。具体操作请参见创建存储空间、管理目录和简单上传。
MaxCompute已支持在OSS侧自动创建目录,对于携带外部表及UDF的SQL语句,您可以通过一条SQL语句执行读写外部表及UDF的操作。原手动创建目录方式仍然支持。
已创建MaxCompute项目。具体操作请参见创建MaxCompute项目。
由于MaxCompute只在部分地域部署,跨地域的数据连通性可能存在问题,因此建议Bucket与MaxCompute项目所在地域保持一致。
已具备在MaxCompute项目中创建表(CreateTable)的权限。表操作的权限信息请参见MaxCompute权限。
使用限制
OSS外部表不支持cluster属性。
单个文件大小不能超过3 GB,如果文件过大,建议拆分。
数据类型支持
下表中表示支持,
表示不支持。
JNI模式:
set odps.ext.parquet.native=false
,表示读外部表解析Parquet数据文件时,使用原有基于Java的开源社区实现,支持读和写。Native模式:
set odps.ext.parquet.native=true
,表示读外部表解析Parquet数据文件时,使用新的基于C++的Native实现,仅支持读。数据类型
是否支持JNI模式(读写)
是否支持Native模式(只读)
TINYINT
SMALLINT
INT
BIGINT
BINARY
FLOAT
DOUBLE
DECIMAL(precision,scale)
VARCHAR(n)
CHAR(n)
STRING
DATE
DATETIME
TIMESTAMP
TIMESTAMP_NTZ
BOOLEAN
ARRAY
MAP
STRUCT
JSON
压缩格式支持
当您需要读写压缩属性的OSS文件时,需要在建表语句中添加with serdeproperties
属性配置,详情请参见with serdeproperties属性参数。
支持读写的数据文件格式:以ZSTD、SNAPPY、GZIP方式压缩的Parquet。
创建外部表
语法结构
各格式的外部表语法结构详情,请参见OSS外部表。
精简语法结构
CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> ( <col_name> <data_type>, ... ) [COMMENT <table_comment>] [PARTITIONED BY (<col_name> <data_type>, ...)] STORED AS parquet LOCATION '<oss_location>' [tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];
详细语法结构
CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name> ( <col_name> <data_type>, ... ) [COMMENT <table_comment>] [PARTITIONED BY (<col_name> <data_type>, ...)] ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' WITH serdeproperties( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole', 'mcfed.parquet.compression'='ZSTD/SNAPPY/GZIP' ) STORED AS parquet LOCATION '<oss_location>' ;
公共参数
公共参数说明请参见基础语法参数说明。
独有参数
with serdeproperties属性参数
property_name | 使用场景 | 说明 | property_value | 默认值 |
mcfed.parquet.compression | 当需要将Parquet数据以压缩方式写入OSS时,请添加该属性。 | Parquet压缩属性。Parquet数据默认不压缩。 |
| 无 |
mcfed.parquet.compression.codec.zstd.level | 当 | level值越大,压缩比越高,实测取值高时,写出数据的减少量非常有限,但时间和资源消耗快速增加,性价比明显降低,因此对于大数据读写压缩Parquet文件的场景,低level(level3~level5)的zstd压缩效果最好。例如: | 取值范围为1~22。 | 3 |
parquet.file.cache.size | 在处理Parquet数据场景中,如果需要提升读OSS数据文件性能,请添加该属性。 | 指定读OSS数据文件时,可缓存的数据量,单位为KB。 | 1024 | 无 |
parquet.io.buffer.size | 在处理Parquet数据场景中,如果需要提升读OSS数据文件性能,请添加该属性。 | 指定OSS数据文件大小超过1024 KB时,可缓存的数据量,单位为KB。 | 4096 | 无 |
tblproperties属性参数
property_name | 使用场景 | 说明 | property_value | 默认值 |
io.compression.codecs | 当OSS数据文件为Raw-Snappy格式时,请添加该属性。 | 内置的开源数据解析器SNAPPY格式场景。 配置该参数值为True时,MaxCompute才可以正常读取压缩数据,否则MaxCompute无法成功读取数据。 | com.aliyun.odps.io.compress.SnappyRawCodec | 无 |
写入数据
MaxCompute写入语法详情,请参见写入语法说明。
查询分析
SELECT语法详情,请参见查询语法说明。
优化查询计划详情,请参见查询优化。
若需要直读LOCATION文件,请参见特色功能:Schemaless Query。
场景示例
本示例将创建以ZSTD压缩的Parquet格式外表,并进行读取和写入操作。
执行下述示例代码时,请将代码中的
<uid>
替换为您的阿里云账号ID。下述示例中使用的角色为
aliyunodpsdefaultrole
,如果您想使用其他角色,需要将aliyunodpsdefaultrole
替换为目标角色名称,并为目标角色授予访问OSS的权限。
准备ZSTD格式数据文件。
在示例数据的
oss-mc-test
Bucket中创建parquet_zstd_jni/dt=20230418
目录层级,并将Parquet文件存放在分区目录dt=20230418
下。创建ZSTD压缩格式的Parquet外表。
CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_parquet_data_type_zstd ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING, direction STRING ) PARTITIONED BY (dt STRING ) ROW FORMAT SERDE 'org.apache.hadoop.hive.ql.io.parquet.serde.ParquetHiveSerDe' WITH serdeproperties( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole', 'mcfed.parquet.compression'='zstd' ) STORED AS parquet LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/parquet_zstd_jni/'; -- 引入分区数据 MSCK REPAIR TABLE mc_oss_parquet_data_type_zstd ADD PARTITIONS;
读取Parquet外表数据。
SELECT * FROM mc_oss_parquet_data_type_zstd WHERE dt='20230418' LIMIT 10;
部分返回结果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | dt | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+ | 1 | 12 | 76 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:10 | SW | 20230418 | | 1 | 1 | 51 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | S | 20230418 | | 1 | 2 | 13 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:01 | NE | 20230418 | | 1 | 3 | 48 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:02 | NE | 20230418 | | 1 | 4 | 30 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:03 | W | 20230418 | | 1 | 5 | 47 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:04 | S | 20230418 | | 1 | 6 | 9 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:05 | S | 20230418 | | 1 | 7 | 53 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:06 | N | 20230418 | | 1 | 8 | 63 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:07 | SW | 20230418 | | 1 | 9 | 4 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:08 | NE | 20230418 | | 1 | 10 | 31 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:09 | N | 20230418 | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
写入数据至Parquet外表。
INSERT INTO mc_oss_parquet_data_type_zstd PARTITION ( dt = '20230418') VALUES (1,16,76,1,46.81006,-92.08174,'9/14/2014 0:10','SW'); -- 查询新写入的数据 SELECT * FROM mc_oss_parquet_data_type_zstd WHERE ds = '20230606' AND recordId=16;
返回结果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | dt | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+ | 1 | 16 | 76 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:10 | SW | 20230418 | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
常见问题
Parquet文件列类型与外表DDL类型不一致
报错信息
ODPS-0123131:User defined function exception - Traceback: java.lang.ClassCastException: org.apache.hadoop.io.LongWritable cannot be cast to org.apache.hadoop.io.IntWritable at org.apache.hadoop.hive.serde2.objectinspector.primitive.WritableIntObjectInspector.getPrimitiveJavaObject(WritableIntObjectInspector.java:46)
错误描述
Parquet文件的LongWritable字段类型与外表DDL的INT类型不一致。
解决方案
外表DDL中的INT类型需要改为BIGINT类型。