在Hadoop UDF输出中保持列数据类型(流处理)

1 投票
1 回答
1061 浏览
提问于 2025-04-18 09:30

我正在为Hadoop上的Hive查询编写一个Python的用户自定义函数(UDF)。我的表里有几个bigint类型的字段,还有几个string类型的字段。

我的这个UDF会修改bigint字段,把修改后的值放到一个新列里(这个新列也应该是数字类型),而string字段则保持不变。

但是,当我在查询中运行这个UDF时,结果却都是string类型的列。

我该如何在我的UDF输出中保留或指定数据类型呢?


更多细节:

我的Python UDF代码:

import sys
for line in sys.stdin:
    # pre-process row
    line = line.strip()
    inputs = line.split('\t')

    # modify numeric fields, calculate new field
    inputs[0], inputs[1], new_field = process(int(inputs[0]), int(inputs[1]))

    # leave rest of inputs as is; they are string fields.

    # output row
    outputs = [new_field]
    outputs.extend(inputs)
    print '\t'.join([str(i) for i in outputs]) # doesn't preserve types!

我把这个UDF保存为myudf.py,并添加到了Hive中。

我的Hive查询代码:

CREATE TABLE calculated_tbl AS
SELECT TRANSFORM(bigintfield1, bigintfield2, stringfield1, stringfield2)
USING 'python myudf.py'
AS (calculated_int, modified_bif1, modified_bif2, stringfield1, stringfield2)
FROM original_tbl;

1 个回答

1

流式处理会把所有内容通过标准输出(stdout)发送出去。其实这只是对 Hadoop 流式处理的一个封装。所有的数据类型都会被转换成字符串,这个你在你的 Python 用户定义函数(udf)中已经处理过了,最后再以字符串的形式返回到 Hive 中。在 Hive 中,Python 的转换函数永远只会返回字符串。你可以尝试在一个子查询中进行转换,然后把结果转换成其他类型:

 SELECT cast(calculated_int as bigint)
        ,cast( modified_bif1 as bigint)
        ,cast( modified_bif2 as bigint) 
        ,stringfield1 
        ,stringfield2
 FROM ( 
 SELECT TRANSFORM(bigintfield1, bigintfield2, stringfield1, stringfield2)
 USING 'python myudf.py'
 AS (calculated_int, modified_bif1, modified_bif2, stringfield1, stringfield2)
 FROM original_tbl) A ;

如果 Hive 允许这样做,那就没问题;如果不允许,你需要把结果保存到一个表中,然后在另一个查询中再转换成其他类型。

最后一个选择是直接使用 Java 用户定义函数(UDF)。只做映射的 UDF 也不算太复杂,而且可以让你指定返回的类型。

更新(来自提问者):

上面的答案效果很好。几周后我在阅读 O'Reilly 的《Programming Hive》一书时发现了一个更优雅的解决方案:

CREATE TABLE calculated_tbl AS
SELECT TRANSFORM(bigintfield1, bigintfield2, stringfield1, stringfield2)
USING 'python myudf.py'
AS (calculated_int BIGINT, modified_bif1 BIGINT, modified_bif2 BIGINT, stringfield1 STRING, stringfield2 STRING)
FROM original_tbl;

与其转换类型,不如直接在 AS(...) 这一行中指定类型。

撰写回答