必需:org.apache.spark.sql.Row

时间:2017-11-09 03:52:09

标签: scala apache-spark

我遇到了一个问题,试图将一个火花数据帧的列从十六进制字符串转换为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”只返回五个结果,其中没有一个与我的情况有关。这就是为什么我把这个标题变得如此不具体,因为几乎没有误报的可能性。提前谢谢!

2 个答案:

答案 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的答案消除了这个错误,但当我尝试将此结果连接到另一个数据帧时,我遇到了另一个错误,后来发生了同样的基本问题。