このトピックでは、Parquet 形式の OSS 外部テーブルの作成、読み取り、書き込み方法について説明します。
前提条件
Alibaba Cloud アカウント、RAM ユーザー、または RAM ロールが OSS 外部テーブルにアクセスするために必要な権限を持っていることを確認します。 権限付与の詳細については、「OSS の STS 権限付与」をご参照ください。
(オプション) OSS バケット、ディレクトリ、およびデータファイルを準備します。 詳細については、「バケットの作成」、「ディレクトリの管理」、および「シンプルアップロード」をご参照ください。
MaxCompute は OSS 内のディレクトリを自動的に作成できます。 1 つの SQL 文を使用して、UDF を使用する外部テーブルからデータを読み書きできます。 ディレクトリの手動作成は不要になりましたが、従来の方法は引き続きサポートされています。
MaxCompute プロジェクトが作成されている。 詳細については、「MaxCompute プロジェクトの作成」をご参照ください。
MaxCompute は特定のリージョンにのみデプロイされています。 リージョン間のデータ接続の問題を防ぐために、MaxCompute プロジェクトと同じリージョンにあるバケットを使用することをお勧めします。
Alibaba Cloud アカウントまたは RAM ユーザーがプロジェクトに対する CreateTable 権限を持っている。 テーブル操作権限の詳細については、「MaxCompute の権限」をご参照ください。
制限事項
cluster 属性は OSS 外部テーブルではサポートされていません。
単一ファイルは 3 GB を超えることはできません。 ファイルがこの制限を超える場合は、分割することをお勧めします。
注意事項
Parquet ファイルのスキーマが外部テーブルスキーマと一致しない場合:
列数が一致しない: Parquet ファイルの列数が外部テーブルの DDL 文の列数よりも少ない場合、Parquet データの読み取り時に、不足している列の値に NULL が入力されます。 Parquet ファイルの列数が多い場合は、余分な列データは破棄されます。
列の型が一致しない: Parquet ファイルの列の型が外部テーブルの DDL 文の対応する列の型と一致しない場合、Parquet データの読み取り時にエラーが報告されます。 たとえば、STRING (または INT) 型を使用して、Parquet ファイルから INT (または STRING) 型のデータを読み取ると、
ODPS-0123131:User defined function exception - Traceback:xxxエラーが報告されます。
データ型のサポート
次の表で、
はサポートを示し、
はサポートされていないことを示します。
MaxCompute データ型の詳細については、「データ型 (V1.0)」および「データ型 (V2.0)」をご参照ください。
JNI モード:
set odps.ext.parquet.native=false。 外部テーブルからデータを読み取るときに、システムは元のオープンソースの Java ベースの実装を使用して Parquet データファイルを解析します。 このモードは、読み取り操作と書き込み操作をサポートしています。ネイティブモード:
set odps.ext.parquet.native=true。 外部テーブルからデータを読み取るときに、システムは新しい C++ ベースのネイティブ実装を使用して Parquet データファイルを解析します。 このモードは読み取り操作のみをサポートしています。データ型
JNI モードでサポート (読み取り/書き込み)
ネイティブモードでサポート (読み取り専用)
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 ファイルの読み書きを行う場合は、CREATE TABLE 文に with serdeproperties 属性を追加します。 詳細については、「with serdeproperties パラメーター」をご参照ください。
MaxCompute は、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 | 圧縮形式で OSS に Parquet データを書き込む必要がある場合は、このプロパティを追加します。 | Parquet 圧縮プロパティ。 デフォルトでは、Parquet データは圧縮されません。 |
| なし |
mcfed.parquet.compression.codec.zstd.level |
| レベル値が高いほど、圧縮率が高くなります。 ただし、テストでは、高レベルではデータの削減は最小限ですが、時間とリソースの消費が大幅に増加することが示されています。 このトレードオフにより、費用対効果が低下します。 したがって、大きな圧縮 Parquet ファイルの読み取りと書き込みを伴うシナリオでは、低い zstd 圧縮レベル (レベル 3 ~レベル 5) が最適な結果をもたらします。 例: | 有効な値: 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 形式の組み込みオープンソースデータパーサーを使用するシナリオ用です。 MaxCompute が圧縮データを読み取ることができるように、このパラメーターを設定します。 そうしないと、MaxCompute はデータを読み取ることができません。 | com.aliyun.odps.io.compress.SnappyRawCodec | なし |
データの書き込み
MaxCompute の書き込み構文の詳細については、「書き込み構文」をご参照ください。
クエリ分析
SELECT 構文の詳細については、「クエリ構文」をご参照ください。
クエリプランの最適化の詳細については、「クエリの最適化」をご参照ください。
LOCATION で指定されたファイルから直接データを読み取るには、「機能:スキーマレスクエリ」をご参照ください。
例
この例では、ZSTD を使用して圧縮された Parquet ファイルの外部テーブルを作成し、テーブルからデータを読み書きする方法を示します。
次のサンプルコードを実行する際は、
<uid>を Alibaba Cloud アカウント ID に置き換えてください。以下の例で使用されているロールは
aliyunodpsdefaultroleです。 別のロールを使用する場合は、aliyunodpsdefaultroleをターゲットロールの名前に置き換え、ターゲットロールに OSS へのアクセス権限を付与します。
ZSTD 形式のデータファイルを準備します。
サンプルデータ で説明されている
oss-mc-testバケットに、parquet_zstd_jni/dt=20230418フォルダー階層を作成し、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/';パーティションを検出します。 外部テーブルがパーティション分割されている場合は、次のコマンドを実行して、基になる OSS の場所からパーティションを検出して登録する必要があります。 詳細については、「OSS 外部テーブルにパーティションデータを追加するための構文」をご参照ください。
-- パーティションデータを検出します。 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 dt = '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 | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+------------+
FAQ
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 に変更します。