我遇到了一个问题,试图将一个火花数据帧的列从十六进制字符串转换为double。我有以下代码:
import spark.implicits._
case class MsgRow(block_number: Long, to: String, from: String, value: Double )
def hex2int (hex: String): Double = (new BigInteger(hex.substring(2),16)).doubleValue
txs = txs.map(row=>
MsgRow(row.getLong(0), row.getString(1), row.getString(2), hex2int(row.getString(3)))
)
我无法分享我的txs数据框的内容,但这里是元数据:
>txs
org.apache.spark.sql.DataFrame = [blockNumber: bigint, to: string ... 4 more fields]
但是当我运行时,我收到错误:
错误:类型不匹配; 发现:MsgRow 必需:org.apache.spark.sql.Row MsgRow(row.getLong(0),row.getString(1),row.getString(2),hex2int(row.getString(3))) ^
我不明白 - 为什么spark / scala期望一个行对象?我所看到的所有示例都没有涉及显式转换为行,实际上大多数都涉及返回case类对象的匿名函数,如上所述。由于某种原因,谷歌搜索“必需:org.apache.spark.sql.Row”只返回五个结果,其中没有一个与我的情况有关。这就是为什么我把这个标题变得如此不具体,因为几乎没有误报的可能性。提前谢谢!
答案 0 :(得分:1)
您的错误是因为您将输出存储到同一个变量,而txs
在您返回Row
时期待MsgRow
。如此改变
txs = txs.map(row=>
MsgRow(row.getLong(0), row.getString(1), row.getString(2), hex2int(row.getString(3)))
)
到
val newTxs = txs.map(row=>
MsgRow(row.getLong(0), row.getString(1), row.getString(2), (new BigInteger(row.getString(3).substring(2),16)).doubleValue)
)
应解决您的问题。
我排除了hex2int
函数,因为它给出了序列化错误。
答案 1 :(得分:0)
感谢@Ramesh指出我的代码中的错误。他的解决方案有效,但它也没有提到与我的OP更直接相关的问题,即从map返回的结果不是数据帧而是数据集。我需要做的就是改变
,而不是创建一个新的变量txs = txs.map(row=>
MsgRow(row.getLong(0), row.getString(1), row.getString(2), hex2int(row.getString(3)))
)
到
txs = txs.map(row=>
MsgRow(row.getLong(0), row.getString(1), row.getString(2), hex2int(row.getString(3)))
).toDF
这可能是包含我的标题的大多数错误的简单答案。虽然@ Ramesh的答案消除了这个错误,但当我尝试将此结果连接到另一个数据帧时,我遇到了另一个错误,后来发生了同样的基本问题。