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プログラムよりもデータ転送のパフォーマンスが向上します。 | パイプラインキャッシュに制限は課されない。 |
定数パラメータの送信 | 一定のパラメータを送信する必要がある。 | 定数パラメータはオプションで送信される。 |
処理中 | SELECT TRANSFORMは、親プロセスと子プロセスの2つのプロセスをサポートします。 コンピューティングリソースの使用量が多く、データスループットが低い場合、 | 単一のプロセスが使用される。 |
パフォーマンス |
| パフォーマンスは低いです。 |
制限事項
PHPとRubyはMaxComputeコンピューティングクラスターにデプロイされていません。 したがって、MaxComputeでPHPまたはRubyスクリプトを呼び出すことはできません。
構文
select transform(<arg1>, <arg2> ...)
[(row format delimited (fields terminated by <field_delimiter> (escaped by <character_escape>)) (lines separated by <line_separator>) (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>))
(lines separated by <line_separator>)
(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、またはline_separatorには1つの文字のみが使用できます。 これらのパラメーターに文字列を指定すると、文字列の最初の文字が使用されます。
MaxComputeは、Apache Hiveで指定された形式 (
inputRecordReader、outputRecordReader、SerDeなど) の構文をサポートしています。 これらの構文を使用するには、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に変換します。 変換中にランタイム例外が発生する場合があります。as(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 statement is 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' from testdata; -- The preceding statement is 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' 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;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;