从 Spark BinaryType 中提取字节
Extract byte from Spark BinaryType
我有一个 table,其二进制列的类型为 BinaryType:
>>> df.show(3)
+--------+--------------------+
| t| bytes|
+--------+--------------------+
|0.145533|[10 50 04 89 00 3...|
|0.345572|[60 94 05 89 80 9...|
|0.545574|[99 50 68 89 00 7...|
+--------+--------------------+
only showing top 3 rows
>>> df.schema
StructType(List(StructField(t,DoubleType,true),StructField(bytes,BinaryType,true)))
如果我提取二进制文件的第一个字节,我从 Spark 得到一个异常:
>>> df.select(n["t"], df["bytes"].getItem(0)).show(3)
AnalysisException: u"Can't extract value from bytes#477;"
转换为 ArrayType(ByteType)
也无效:
>>> df.select(n["t"], df["bytes"].cast(ArrayType(ByteType())).getItem(0)).show(3)
AnalysisException: u"cannot resolve '`bytes`' due to data type mismatch: cannot cast BinaryType to ArrayType(ByteType,true) ..."
如何提取字节?
您可以为此制作一个简单的 udf:
from pyspark.sql import functions as f
a = bytearray([10, 50, 04])
df = sqlContext.createDataFrame([(1, a), (2, a)], ("t", "bytes"))
df.show()
+---+----------+
| t| bytes|
+---+----------+
| 1|[0A 32 04]|
| 2|[0A 32 04]|
+---+----------+
u = f.udf(lambda a: a[0])
df.select(u(df['bytes']).alias("first")).show()
+-----+
|first|
+-----+
| 10|
| 10|
+-----+
编辑
如果你想让提取的位置成为一个参数,你可以做一些柯里化:
func = lambda i: lambda a: a[i]
my_udf = lambda i: f.udf(func(i))
df.select(my_udf(2)(df['bytes']).alias("last")).show()
+----+
|last|
+----+
| 4|
| 4|
+----+
另一种方法是使用本机 API 函数 substring
(docs),它可以使用位置和长度参数“切片”二进制类型。
这是一个遵循已接受答案示例的演示:
df.select("*",
f.substring("bytes", 2, 1),
f.substring("bytes", 2, 1).cast("string")).show()
+---+----------+----------------------+--------------------------------------+
| t| bytes|substring(bytes, 2, 1)|CAST(substring(bytes, 2, 1) AS STRING)|
+---+----------+----------------------+--------------------------------------+
| 1|[0A 32 04]| [32]| 2|
| 2|[0A 32 04]| [32]| 2|
+---+----------+----------------------+--------------------------------------+
我有一个 table,其二进制列的类型为 BinaryType:
>>> df.show(3)
+--------+--------------------+
| t| bytes|
+--------+--------------------+
|0.145533|[10 50 04 89 00 3...|
|0.345572|[60 94 05 89 80 9...|
|0.545574|[99 50 68 89 00 7...|
+--------+--------------------+
only showing top 3 rows
>>> df.schema
StructType(List(StructField(t,DoubleType,true),StructField(bytes,BinaryType,true)))
如果我提取二进制文件的第一个字节,我从 Spark 得到一个异常:
>>> df.select(n["t"], df["bytes"].getItem(0)).show(3)
AnalysisException: u"Can't extract value from bytes#477;"
转换为 ArrayType(ByteType)
也无效:
>>> df.select(n["t"], df["bytes"].cast(ArrayType(ByteType())).getItem(0)).show(3)
AnalysisException: u"cannot resolve '`bytes`' due to data type mismatch: cannot cast BinaryType to ArrayType(ByteType,true) ..."
如何提取字节?
您可以为此制作一个简单的 udf:
from pyspark.sql import functions as f
a = bytearray([10, 50, 04])
df = sqlContext.createDataFrame([(1, a), (2, a)], ("t", "bytes"))
df.show()
+---+----------+
| t| bytes|
+---+----------+
| 1|[0A 32 04]|
| 2|[0A 32 04]|
+---+----------+
u = f.udf(lambda a: a[0])
df.select(u(df['bytes']).alias("first")).show()
+-----+
|first|
+-----+
| 10|
| 10|
+-----+
编辑
如果你想让提取的位置成为一个参数,你可以做一些柯里化:
func = lambda i: lambda a: a[i]
my_udf = lambda i: f.udf(func(i))
df.select(my_udf(2)(df['bytes']).alias("last")).show()
+----+
|last|
+----+
| 4|
| 4|
+----+
另一种方法是使用本机 API 函数 substring
(docs),它可以使用位置和长度参数“切片”二进制类型。
这是一个遵循已接受答案示例的演示:
df.select("*",
f.substring("bytes", 2, 1),
f.substring("bytes", 2, 1).cast("string")).show()
+---+----------+----------------------+--------------------------------------+
| t| bytes|substring(bytes, 2, 1)|CAST(substring(bytes, 2, 1) AS STRING)|
+---+----------+----------------------+--------------------------------------+
| 1|[0A 32 04]| [32]| 2|
| 2|[0A 32 04]| [32]| 2|
+---+----------+----------------------+--------------------------------------+