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 ]
参数
-
expression
指定一个或多个值、运算符和 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|
+-------+---------------------+