TRANSFORM
描述
TRANSFORM
子句用于指定 Hive 风格的转换查询规范,通过运行用户指定的命令或脚本来转换输入。
Spark 的脚本转换支持两种模式
- 禁用 Hive 支持:Spark 脚本转换可以在
spark.sql.catalogImplementation=in-memory
下运行,或者在没有SparkSession.builder.enableHiveSupport()
的情况下运行。在这种情况下,Spark 现在只使用带有ROW FORMAT DELIMITED
的脚本转换,并将传递给脚本的所有值视为字符串。 - 启用 Hive 支持:当 Spark 在
spark.sql.catalogImplementation=hive
下运行,或者 Spark SQL 使用SparkSession.builder.enableHiveSupport()
启动时,Spark 可以将脚本转换与 Hive SerDe 和ROW FORMAT DELIMITED
一起使用。
语法
SELECT TRANSFORM ( expression [ , ... ] )
[ ROW FORMAT row_format ]
[ RECORDWRITER record_writer_class ]
USING command_or_script [ AS ( [ col_name [ col_type ] ] [ , ... ] ) ]
[ ROW FORMAT row_format ]
[ RECORDREADER record_reader_class ]
参数
-
表达式
指定一个或多个值、运算符和 SQL 函数的组合,这些值、运算符和 SQL 函数的结果为一个值。
-
row_format
指定输入和输出的行格式。有关更多语法详细信息,请参阅HIVE FORMAT。
-
RECORDWRITER
指定自定义 RecordWriter 的完全限定类名。默认值为
org.apache.hadoop.hive.ql.exec.TextRecordWriter
。 -
RECORDREADER
指定自定义 RecordReader 的完全限定类名。默认值为
org.apache.hadoop.hive.ql.exec.TextRecordReader
。 -
command_or_script
指定用于处理数据的命令或脚本路径。
ROW FORMAT DELIMITED 行为
当 Spark 使用 ROW FORMAT DELIMITED
格式时
- Spark 使用字符
\u0001
作为默认字段分隔符,可以使用FIELDS TERMINATED BY
覆盖此分隔符。 - Spark 使用字符
\n
作为默认行分隔符,可以使用LINES TERMINATED BY
覆盖此分隔符。 - Spark 使用字符串
\N
作为默认的NULL
值,以便将NULL
值与字面字符串NULL
区分开来。可以使用NULL DEFINED AS
覆盖此分隔符。 - Spark 将所有列转换为
STRING
,并在将其提供给用户脚本之前,使用制表符组合列。对于ARRAY
/MAP
/STRUCT
等复杂类型,Spark 使用to_json
将其转换为输入JSON
字符串,并使用from_json
将结果输出JSON
字符串转换为ARRAY
/MAP
/STRUCT
数据。 COLLECTION ITEMS TERMINATED BY
和MAP KEYS TERMINATED BY
是用于拆分ARRAY
/MAP
/STRUCT
等复杂数据的分隔符,Spark 使用to_json
和from_json
以JSON
格式处理复杂数据类型。因此,COLLECTION ITEMS TERMINATED BY
和MAP KEYS TERMINATED BY
在默认行格式下不起作用。- 用户脚本的标准输出被视为以制表符分隔的
STRING
列。任何仅包含字符串\N
的单元格都将重新解释为字面NULL
值,然后将生成的STRING
列转换为col_type
中指定的数据类型。 - 如果实际输出列数小于指定的输出列数,则将使用
NULL
填充其他输出列。例如output tabs: 1, 2 output columns: A: INT, B INT, C: INT result: +---+---+------+ | a| b| c| +---+---+------+ | 1| 2| NULL| +---+---+------+
- 如果实际输出列数大于指定的输出列数,则输出列仅选择相应的列,其余部分将被丢弃。例如,如果输出有三个制表符,但只有两个输出列
output tabs: 1, 2, 3 output columns: A: INT, B INT result: +---+---+ | a| b| +---+---+ | 1| 2| +---+---+
- 如果
USING my_script
后面没有AS
子句,则输出架构为key: STRING, value: STRING
。key
列包含第一个制表符之前的所有字符,value
列包含第一个制表符之后的剩余字符。如果没有制表符,Spark 将返回NULL
值。例如output tabs: 1, 2, 3 output columns: result: +-----+-------+ | key| value| +-----+-------+ | 1| 2| +-----+-------+ output tabs: 1, 2 output columns: result: +-----+-------+ | key| value| +-----+-------+ | 1| NULL| +-----+-------+
Hive SerDe 行为
当启用 Hive 支持并使用 Hive SerDe 模式时
- Spark 默认使用 Hive SerDe
org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe
,因此在将列提供给用户脚本之前,会将列转换为STRING
并使用制表符组合列。 - 所有字面
NULL
值都将转换为字符串\N
,以便将字面NULL
值与字面字符串NULL
区分开来。 - 用户脚本的标准输出被视为以制表符分隔的
STRING
列,任何仅包含字符串\N
的单元格都将重新解释为NULL
值,然后将生成的 STRING 列转换为col_type
中指定的数据类型。 - 如果实际输出列数小于指定的输出列数,则将使用
NULL
填充其他输出列。 - 如果实际输出列数大于指定的输出列数,则输出列仅选择相应的列,其余部分将被丢弃。
- 如果
USING my_script
后面没有AS
子句,则输出架构为key: STRING, value: STRING
。key
列包含第一个制表符之前的所有字符,value
列包含第一个制表符之后的剩余字符。如果没有制表符,Spark 将返回NULL
值。 - 可以使用
ROW FORMAT SERDE
或ROW FORMAT DELIMITED
覆盖这些默认值。
示例
CREATE TABLE person (zip_code INT, name STRING, age INT);
INSERT INTO person VALUES
(94588, 'Zen Hui', 50),
(94588, 'Dan Li', 18),
(94588, 'Anil K', 27),
(94588, 'John V', NULL),
(94511, 'David K', 42),
(94511, 'Aryan B.', 18),
(94511, 'Lalit B.', NULL);
-- With specified output without data type
SELECT TRANSFORM(zip_code, name, age)
USING 'cat' AS (a, b, c)
FROM person
WHERE zip_code > 94511;
+-------+---------+-----+
| a | b| c|
+-------+---------+-----+
| 94588| Anil K| 27|
| 94588| John V| NULL|
| 94588| Zen Hui| 50|
| 94588| Dan Li| 18|
+-------+---------+-----+
-- With specified output with data type
SELECT TRANSFORM(zip_code, name, age)
USING 'cat' AS (a STRING, b STRING, c STRING)
FROM person
WHERE zip_code > 94511;
+-------+---------+-----+
| a | b| c|
+-------+---------+-----+
| 94588| Anil K| 27|
| 94588| John V| NULL|
| 94588| Zen Hui| 50|
| 94588| Dan Li| 18|
+-------+---------+-----+
-- Using ROW FORMAT DELIMITED
SELECT TRANSFORM(name, age)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ','
LINES TERMINATED BY '\n'
NULL DEFINED AS 'NULL'
USING 'cat' AS (name_age string)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '@'
LINES TERMINATED BY '\n'
NULL DEFINED AS 'NULL'
FROM person;
+---------------+
| name_age|
+---------------+
| Anil K,27|
| John V,null|
| ryan B.,18|
| David K,42|
| Zen Hui,50|
| Dan Li,18|
| Lalit B.,null|
+---------------+
-- Using Hive Serde
SELECT TRANSFORM(zip_code, name, age)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim' = '\t'
)
USING 'cat' AS (a STRING, b STRING, c STRING)
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe'
WITH SERDEPROPERTIES (
'field.delim' = '\t'
)
FROM person
WHERE zip_code > 94511;
+-------+---------+-----+
| a | b| c|
+-------+---------+-----+
| 94588| Anil K| 27|
| 94588| John V| NULL|
| 94588| Zen Hui| 50|
| 94588| Dan Li| 18|
+-------+---------+-----+
-- Schema-less mode
SELECT TRANSFORM(zip_code, name, age)
USING 'cat'
FROM person
WHERE zip_code > 94500;
+-------+---------------------+
| key| value|
+-------+---------------------+
| 94588| Anil K 27|
| 94588| John V \N|
| 94511| Aryan B. 18|
| 94511| David K 42|
| 94588| Zen Hui 50|
| 94588| Dan Li 18|
| 94511| Lalit B. \N|
+-------+---------------------+