如何将RDD解析为数据框

时间:2019-07-17 11:58:38

标签: apache-spark hbase

我正在尝试将RDD [Seq [String]]解析为Dataframe。 尽管它是字符串的序列,但它们可以具有更特定的类型,例如Int,Boolean,Double,String等。 例如,一行可能是:

"hello", "1", "bye", "1.1"
"hello1", "11", "bye1", "2.1"
...

另一个执行可能具有不同数量的列。

第一列将始终为String,第二列为int,依此类推,并且将始终采用这种方式。另一方面,一个执行可能包含五个元素,而其他执行可能包含2000个元素,因此取决于执行情况。在每次执行中,都会定义列类型的名称。

要做到这一点,我可以有这样的东西:

//I could have a parameter to generate the StructType dinamically.
def getSchema(): StructType = {
  var schemaArray = scala.collection.mutable.ArrayBuffer[StructField]()
  schemaArray += StructField("col1" , IntegerType, true)
  schemaArray += StructField("col2" , StringType, true)
  schemaArray += StructField("col3" , DoubleType, true)
  StructType(schemaArray)
}

//Array of Any?? it doesn't seem the best option!!
val l1: Seq[Any] = Seq(1,"2", 1.1 )
val rdd1 = sc.parallelize(l1).map(Row.fromSeq(_))

val schema = getSchema()
val df = sqlContext.createDataFrame(rdd1, schema)
df.show()
df.schema

我根本不希望拥有Seq of Any,但这确实是我拥有的。另一个机会?

另一方面,我认为我有一个类似于CSV的东西,我可以创建一个。使用spark时,有一个库可以读取CSV并返回一个推断类型的数据框。如果我已经有RDD [String],可以调用它吗?

1 个答案:

答案 0 :(得分:2)

由于每次执行的列数都会发生变化,所以我建议使用CSV选项,将分隔符设置为空格或其他。这样,spark将为您找出列类型。

更新

由于您提到从HBase读取数据,因此一种方法是将HBase行转换为JSON或CSV,然后将RDD转换为数据框:

val jsons = hbaseContext.hbaseRDD(tableName, scan).map{case (_, r) =>
  val currentJson = new JSONObject
  val cScanner = r.cellScanner
  while (cScanner.advance) {
    currentJson.put(Bytes.toString(cScanner.current.getQualifierArray, cScanner.current.getQualifierOffset, cScanner.current.getQualifierLength),
      Bytes.toString(cScanner.current.getValueArray, cScanner.current.getValueOffset, cScanner.current.getValueLength))
  }
  currentJson.toString
}
val df = spark.read.json(spark.createDataset(jsons))

可以对CSV做类似的事情。