将RDD [List [AnyRef]]转换为RDD [List [String,Date,String,String]]

时间:2018-01-27 00:19:55

标签: scala apache-spark rdd

我想设置RDD的返回类型。但它是RDD [List [AnyRef]]。 所以我无法直接指定任何内容。 像,

val rdd2 = rdd1.filter(! _.isEmpty).filter(x => x(0) != null)

返回RDD [List [String,Date,String,String]]类型的RDD,但它是RDD [List [AnyRef]]。

修改

rdd1:
List(Sun Jul 31 10:21:53 PDT 2016, pm1, 11, ri1)
List(Mon Aug 01 12:57:09 PDT 2016, pm3, 5, ri1)
List(Mon Aug 01 01:11:16 PDT 2016, pm1, 1, ri2)

此rdd1是RDD [List [AnyRef]]类型。

现在我想要这种类型的rdd2:

RDD[List[Date, String, Long, String]]

原因是我在使用模式将RDD转换为数据框时面临日期问题。首先要解决这个问题,我必须修复RDD类型。 那个问题的解决方案是: Spark rdd correct date format in scala?

2 个答案:

答案 0 :(得分:2)

这是一个导致相同问题的小例子(我省略了Date,将其替换为String,这不是重点:

val myRdd = sc.makeRDD(List(
  List[AnyRef]("date 1", "blah2", (11: java.lang.Integer), "baz1"),
  List[AnyRef]("date 2", "blah3", (5: java.lang.Integer),  "baz2"),
  List[AnyRef]("date 3", "blah4", (1: java.lang.Integer),  "baz3") 
))

// myRdd: org.apache.spark.rdd.RDD[List[AnyRef]] = ParallelCollectionRDD[0]

以下是恢复类型的方法:

val unmessTypes = myRdd.map{
  case List(a: String, b: String, c: java.lang.Integer, d: String) => (a, b, (c: Int), d)
}

// unmessTypes: org.apache.spark.rdd.RDD[(String, String, Int, String)] = MapPartitionsRDD[1]

您只需应用一个将长度为4的列表与指定类型的元素匹配的部分函数,​​并从中构造出预期类型的​​元组。如果您的RDD确实只包含长度为4且具有预期类型的​​列表,则部分函数将永远不会失败。

答案 1 :(得分:2)

通过查看您的Spark rdd correct date format in scala?,您似乎在将rdd转换为数据帧时遇到问题。 Tzach已经正确回答了将java.util.Date转换为java.sql.Date的问题,这可以解决您的问题。

首先,List不能为列表中的每个元素提供单独的 dataType ,就像我们对Tuples所做的那样。 List只有一个 dataType ,如果使用混合 dataTypes ,则列表的 dataType 表示为AnyAnyRef

我猜您必须创建如下数据

val list = List(
  List[AnyRef](new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH).parse("Sun Jul 31 10:21:53 PDT 2016"), "pm1", 11L: java.lang.Long,"ri1"),
  List[AnyRef](new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH).parse("Mon Aug 01 12:57:09 PDT 2016"), "pm3", 5L: java.lang.Long, "ri1"),
  List[AnyRef](new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy", Locale.ENGLISH).parse("Mon Aug 01 01:11:16 PDT 2016"), "pm1", 1L: java.lang.Long, "ri2")
)

val rdd1 = spark.sparkContext.parallelize(list)

会给出

rdd1: org.apache.spark.rdd.RDD[List[AnyRef]]

但事实上它真正的数据类型[java.util.Date, String, java.lang.Long, String]

在查看您的其他问题时,您必须在将rdd转换为具有dataframe后的schema时遇到问题

val schema =
  StructType(
    StructField("lotStartDate", DateType, false) ::
      StructField("pm", StringType, false) ::
      StructField("wc", LongType, false) ::
      StructField("ri", StringType, false) :: Nil)

您可以做的是在其他问题中使用java.sql.Date api,然后创建dataframe

val rdd1 = sc.parallelize(list).map(lis => Row.fromSeq(new java.sql.Date((lis.head.asInstanceOf[java.util.Date]).getTime)::lis.tail))
val df = sqlContext.createDataFrame(rdd1,schema)

应该给你

+------------+---+---+---+
|lotStartDate|pm |wc |ri |
+------------+---+---+---+
|2016-07-31  |pm1|11 |ri1|
|2016-08-02  |pm3|5  |ri1|
|2016-08-01  |pm1|1  |ri2|
+------------+---+---+---+

我希望答案很有帮助