SELECT TRANSFORM
ステートメントを使用すると、指定した子プロセスを開始し、標準入力を使用して必要な形式でデータを入力できます。 次に、子プロセスの標準出力を解析して出力データを取得できます。 SELECT TRANSFORM
ステートメントを使用すると、ユーザー定義のテーブル値関数 (UDTF) を記述することなく、他のプログラミング言語でスクリプトを実行できます。
説明
SELECT TRANSFORM
とUDTFのパフォーマンスは、シナリオによって異なります。 比較テストの結果は、少量のデータをクエリすると、SELECT TRANSFORM
がUDTFよりもパフォーマンスが優れていることを示しています。 ただし、大量のデータをクエリする場合、UDTFはSELECT TRANSFORMよりも優れています。 SELECT TRANSFORM
は開発が簡単で、アドホッククエリに適しています。
SELECT TRANSFORM
は、さまざまなプログラミング言語と互換性があります。 このステートメントでは、単純な機能を実装するためのスクリプトをコマンドに記述できます。 AWK、Python、Perl、Shellなどのプログラミング言語がこの操作をサポートしています。 これにより、スクリプトファイルの書き込みやリソースのアップロードなどの追加操作を実行する必要がなくなります。 これは、開発プロセスを単純化する。 複雑な機能を実装するには、スクリプトファイルをアップロードします。 詳細については、「Pythonスクリプトの呼び出し例」および「Javaスクリプトの呼び出し例」をご参照ください。
次の表は、UDTFとSELECT TRANSFORM
の異なる次元での比較結果を示しています。
カテゴリ |
| UDTF |
データ型 | 子プロセスは、標準の入力と出力を使用してデータを送信します。 すべてのデータは文字列として処理されます。 | UDTFの出力結果と入力パラメーターは、複数のデータ型をサポートします。 |
データ伝送 | データ伝送は、オペレーティングシステムのパイプラインに基づいています。 ただし、パイプラインのキャッシュサイズはわずか4 KBであり、変更することはできません。 パイプラインが空または完全に占有されている場合、 SELECT TRANSFORMは、データ送信中にデータを読み書きするために、基盤となるシステムを呼び出します。 このステートメントは、Javaプログラムよりもデータ転送のパフォーマンスが向上します。 | パイプラインキャッシュに制限は課されない。 |
定数パラメータの送信 | 一定のパラメータを送信する必要がある。 | 定数パラメータはオプションで送信される。 |
Process | SELECT TRANSFORMは、親プロセスと子プロセスをサポートします。 コンピューティングリソースの使用量が多く、データスループットが低い場合、 | 単一のプロセスが使用される。 |
パフォーマンス |
| パフォーマンスは低いです。 |
制限事項
PHPとRubyはMaxComputeコンピューティングクラスターにデプロイされていません。 したがって、MaxComputeでPHPまたはRubyスクリプトを呼び出すことはできません。
構文
select transform(<arg1>, <arg2> ...)
[(row format delimited (fields terminated by <field_delimiter> (escaped by <character_escape>)) (null defined as <null_value>))]
using '<unix_command_line>'
(resources '<res_name>' (',' '<res_name>')*)
[(as <col1>, <col2> ...)]
(row format delimited (fields terminated by <field_delimiter> (escaped by <character_escape>)) (null defined as <null_value>))
SELECT TRANSFORMキーワード: required。 このキーワードを、同じセマンティクスを使用するキーワード
map
またはreduce
に置き換えることができます。 構文を明確にするために、SELECT TRANSFORMを使用することを推奨します。arg1、arg2…: required。 これらのパラメータは、入力データを指定する。 これらのパラメーターの形式は、
SELECT
ステートメントと同じです。 既定の形式を使用する場合、各パラメーターの式の結果は暗黙的にSTRING型の値に変換されます。 次に、パラメーターは\t
と結合され、指定された子プロセスに渡されます。ROW FORMAT句: オプション。 この句では、入力データと出力データの形式をカスタマイズできます。
2つのROW FORMAT句が構文で使用されます。 最初の句は入力データの形式を指定し、2番目の句は出力データの形式を指定します。 デフォルトでは、列の区切り文字として
\t
が使用され、行の区切り文字として\n
が使用され、null値を表すために\N
が使用されます。説明field_delimiterまたはcharacter_escapeとして使用できる文字は1つだけです。 これらのパラメーターに文字列を指定すると、文字列の最初の文字が使用されます。
MaxComputeは、
inputRecordReader
、outputRecordReader
、SerDe
など、Apache Hiveで指定された形式の構文をサポートしています。 これらの構文を使用するには、Hive互換データ型エディションを有効にする必要があります。 Hive互換データ型エディションを有効にするには、SQL文の前にse t odps.sql.hive.com patible=true;
を追加します。 Apache Hiveでサポートされている構文の詳細については、「Hiveドキュメント」をご参照ください。Apache Hiveでサポートされている構文 (
inputRecordReader
やoutputRecordReader
など) を指定すると、SQL文の実行速度が低下する可能性があります。
USING句: 必須です。 この句は、子プロセスを開始するために使用されるコマンドを指定します。
ほとんどのMaxCompute SQL文では、USING句はリソースを指定します。 ただし、SELECT TRANSFORMステートメントのUSING句では、子プロセスを開始するコマンドを指定します。 USING句は、Apache Hiveの構文との互換性を確保するために使用されます。
USING句の構文は、シェルスクリプトの構文に似ています。 ただし、USING句は、シェルスクリプトを実行する代わりに、指定したコマンドに基づいて子プロセスを作成します。 したがって、入力と出力のリダイレクト、パイプライン、ループなど、一部のシェル機能は使用できません。 シェルスクリプトは、必要に応じて子プロセスを開始するコマンドとして使用できます。
RESOURCES句: オプション。 この句は、子プロセスがアクセスできるリソースを指定します。 次のいずれかの方法を使用して、子プロセスがアクセスできるリソースを指定できます。
RESOURCES句を使用して、
using 'sh foo.sh bar.txt 'resources 'foo.sh','bar.txt'
などのリソースを指定します。set odps.sql.session.resourcesを使用してリソースを指定します。 たとえば、SQL文の前に
set odps.sql.session.resources=foo.sh,bar.txt;
フラグを追加してリソースを指定できます。このグローバル設定が適用されると、すべてのSELECT TRANSFORMステートメントがリソースにアクセスできます。 複数のリソースファイルをコンマ (,) で区切ります。
AS句: オプション。 この句は、出力列とそのデータ型 (
as(col1 bigint, col2 boolean)
) を指定します。出力列のデータ型を指定しない場合は、デフォルトのデータ型STRINGが使用されます。 たとえば、
AS(col1, col2)
は、出力列がSTRING型であることを示します。出力データは、子プロセスの標準出力を解析することによって得られる。 指定されたデータがSTRING型でない場合、MaxComputeは暗黙的に
CAST
関数を呼び出してデータ型をSTRINGに変換します。 変換中にランタイム例外が発生する可能性があります。(col1, col2:bigint)
など、指定した一部の列にのみデータ型を指定することはできません。AS
句を省略した場合、標準出力データの最初の\t
の前のフィールドがキーになり、以降の部分はすべて値になります。 これはAS(key, value)
に相当します。
シェルコマンドの呼び出し例
シェルコマンドを実行して、1から50までの50行のデータを生成します。 出力はdata
フィールドです。 シェルコマンドの出力をSELECT TRANSFORM
の入力として使用します。サンプル文:
select transform(script) using 'sh' as (data)
from (
select 'for i in `seq 1 50`; do echo $i; done' as script
) t
;
-- The preceding statement is equivalent to the following statement:
select transform('for i in `seq 1 50`; do echo $i; done') using 'sh' as (data);
次の応答が返されます。
+------------+
| data |
+------------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 |
| 24 |
| 25 |
| 26 |
| 27 |
| 28 |
| 29 |
| 30 |
| 31 |
| 32 |
| 33 |
| 34 |
| 35 |
| 36 |
| 37 |
| 38 |
| 39 |
| 40 |
| 41 |
| 42 |
| 43 |
| 44 |
| 45 |
| 46 |
| 47 |
| 48 |
| 49 |
| 50 |
+------------+
Pythonコマンドの呼び出し例
Pythonコマンドを使用して、1から50までの50行のデータを生成します。 出力はdata
フィールドです。 Pythonコマンドの出力をSELECT TRANSFORM
の入力として使用します。サンプル文:
select transform(script) using 'python' as (data)
from (
select 'for i in xrange(1, 51): print i;' as script
) t
;
-- The preceding statement is equivalent to the following statement:
select transform('for i in xrange(1, 51): print i;') using 'python' as (data);
次の応答が返されます。
+------------+
| data |
+------------+
| 1 |
| 2 |
| 3 |
| 4 |
| 5 |
| 6 |
| 7 |
| 8 |
| 9 |
| 10 |
| 11 |
| 12 |
| 13 |
| 14 |
| 15 |
| 16 |
| 17 |
| 18 |
| 19 |
| 20 |
| 21 |
| 22 |
| 23 |
| 24 |
| 25 |
| 26 |
| 27 |
| 28 |
| 29 |
| 30 |
| 31 |
| 32 |
| 33 |
| 34 |
| 35 |
| 36 |
| 37 |
| 38 |
| 39 |
| 40 |
| 41 |
| 42 |
| 43 |
| 44 |
| 45 |
| 46 |
| 47 |
| 48 |
| 49 |
| 50 |
+------------+
AWKコマンドの呼び出し例
テストテーブルを作成します。 AWKコマンドを実行して、テストテーブルの2番目の列を出力として指定します。 出力データはdata
フィールドです。 AWKコマンドの出力をSELECT TRANSFORM
の入力として使用します。サンプル文:
-- Create a test table.
create table testdata(c1 bigint,c2 bigint);
-- Insert test data into the test table.
insert into table testdata values (1,4),(2,5),(3,6);
-- Execute the SELECT TRANSFORM statement.
select transform(*) using "awk '//{print $2}'" as (data) from testdata;
次の応答が返されます。
+------------+
| data |
+------------+
| 4 |
| 5 |
| 6 |
+------------+
Perlコマンドの呼び出し例
テストテーブルを作成します。 Perlコマンドを実行して、テストテーブルのデータを出力として提供します。 出力データはdata
フィールドです。 Perlコマンドの出力をSELECT TRANSFORM
の入力として使用します。サンプル文:
-- Create a test table.
create table testdata(c1 bigint,c2 bigint);
-- Insert test data into the test table.
insert into table testdata values (1,4),(2,5),(3,6);
-- Execute the SELECT TRANSFORM statement.
select transform(testdata.c1, testdata.c2) using "perl -e 'while($input = <STDIN>){print $input;}'" from testdata;
次の応答が返されます。
+------------+------------+
| key | value |
+------------+------------+
| 1 | 4 |
| 2 | 5 |
| 3 | 6 |
+------------+------------+
Pythonスクリプトの呼び出し例
myplus.pyファイルを作成します。 サンプル文:
#!/usr/bin/env python import sys line = sys.stdin.readline() while line: token = line.split('\t') if (token[0] == '\\N') or (token[1] == '\\N'): print '\\N' else: print str(token[0]) +'\t' + str(token[1]) line = sys.stdin.readline()
Python スクリプトファイルをリソースとして MaxCompute に追加します。
add py ./myplus.py -f;
説明DataWorksコンソールを使用して、Pythonファイルをリソースとして追加することもできます。 詳細については、「MaxComputeリソースの作成と使用」をご参照ください。
SELECT TRANSFORM
ステートメントを実行して、このファイルを呼び出します。-- Create a test table. create table testdata(c1 bigint,c2 bigint); -- Insert test data into the test table. insert into table testdata values (1,4),(2,5),(3,6); -- Execute the SELECT TRANSFORM statement. select transform (testdata.c1, testdata.c2) using 'python myplus.py' resources 'myplus.py' as (result1,result2) from testdata; -- The preceding statements are equivalent to the following statements: set odps.sql.session.resources=myplus.py; select transform (testdata.c1, testdata.c2) using 'python myplus.py' as (result1,result2) from testdata;
次の応答が返されます。
+------------+------------+ | result1 | result2 | +------------+------------+ | 1 | 4 | | | NULL | | 2 | 5 | | | NULL | | 3 | 6 | | | NULL | +------------+------------+
Javaスクリプトの呼び出し例
Javaスクリプトを記述し、Sum.jarファイルとしてエクスポートします。 サンプルJavaコード:
package com.aliyun.odps.test; import java.util.Scanner; public class Sum { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while (sc.hasNext()) { String s = sc.nextLine(); String[] tokens = s.split("\t"); if (tokens.length < 2) { throw new RuntimeException("illegal input"); } if (tokens[0].equals("\\N") || tokens[1].equals("\\N")) { System.out.println("\\N"); } System.out.println(Long.parseLong(tokens[0]) + Long.parseLong(tokens[1])); } } }
ファイルをリソースとしてMaxComputeに追加します。
add jar ./Sum.jar -f;
SELECT TRANSFORM
ステートメントを実行して、このファイルを呼び出します。-- Create a test table. create table testdata(c1 bigint,c2 bigint); -- Insert test data into the test table. insert into table testdata values (1,4),(2,5),(3,6); -- Execute the SELECT TRANSFORM statement. select transform(testdata.c1, testdata.c2) using 'java -cp Sum.jar com.aliyun.odps.test.Sum' resources 'Sum.jar' as cnt from testdata; -- The preceding statements are equivalent to the following statements: set odps.sql.session.resources=Sum.jar; select transform(testdata.c1, testdata.c2) using 'java -cp Sum.jar com.aliyun.odps.test.Sum' as cnt from testdata;
次の応答が返されます。
+-----+ | cnt | +-----+ | 5 | | 7 | | 9 | +-----+
JavaとPythonには既製のUDTFフレームワークがあります。 ただし、SELECT TRANSFORM
を使用すると、スクリプトを簡単に作成できます。 SELECT TRANSFORMは、追加の依存関係を必要とせず、フォーマット要件もなく、オフラインスクリプトを直接使用することもできます。 オフラインJavaスクリプトを保存するディレクトリは、環境変数JAVA_HOME
から取得できます。 オフラインPythonスクリプトを保存するためのディレクトリは、PYTHON_HOME
環境変数から取得できます。
スクリプトをシリーズで呼び出す例
SELECT TRANSFORM
ステートメントを連続して実行できます。 この操作を実行するには、DISTRIBUTE BY
およびSORT BY
句を使用して入力データを前処理します。 例:
select transform(key, value) using '<cmd2>' from
(
select transform(*) using '<cmd1>' from
(
select * from testdata distribute by c2 sort by c1
) t distribute by key sort by value
) t2;
cmd1
およびcmd2
は、子プロセスを起動するためのコマンドです。
map
キーワードとreduce
キーワードを使用して、SELECT TRANSFORMステートメントを連続して実行することもできます。
@a := select * from data distribute by col2 sort by col1;
@b := map * using 'cmd1' distribute by col1 sort by col2 from @a;
reduce * using 'cmd2' from @b;