繁体   English   中英

Spark/Scala:RDD[列表<String> ] 到 RDD[自定义对象]

[英]Spark/Scala: RDD[List<String>] to RDD[Custom Object]

我在输入文本文件中有数据。 它包含以下格式的输入数据:“PriceId、DateTime、PriceForUSA、PriceForUK、PriceForAUS”。

它看起来像这样:

0000002,11-05-08-2016,0.92,1.68,0.81

0000003,07-05-08-2016,0.80,1.05,1.49

0000008,07-05-08-2016,1.43,1.29,1.22

国家/地区列表是固定的(USA、UK、AUS),行中的价格顺序也是固定的(PriceForUSA、PriceForUK、PriceForAUS)。

我使用 Spark Context 从文件中读取这些数据并将其转换为 RDD[List[String[]。 我的 RDD 中的每个 List 都代表输入文本文件中的一行。

例如,

第一个列表包含字符串

"0000002", "11-05-08-2016", "0.92", "1.68", "0.81"

第二个列表包含字符串

"0000003", "07-05-08-2016" , "0.80", "1.05" , "1.49"

等等。

我也有自定义类 PriceInfo

case class PriceInfo(priceId: String, priceDate: String, country: String, price: Double) {

  override def toString: String = s"$priceId,$priceDate,$country,$price"
}

将每个 List[String] 转换为此类对象并不困难(我已经可以做到),但在这种情况下,我的任务是从每个 List[String] 中获取多个自定义对象

例如,包含

"0000002", "11-05-08-2016", "0.92", "1.68", "0.81"

应该转化为:

  • 价格信息(“0000002”,“11-05-08-2016”,“美国”,“0.92”)
  • PriceInfo("0000002", "11-05-08-2016", "UK", "1.68")
  • 价格信息(“0000002”,“11-05-08-2016”,“澳大利亚”,“0.81”)。

并且我的 RDD[List[String]] 中的每个 List[String] 都必须以相同的方式“拆分”为多个 PriceInfo 对象。

结果应该是一个 RDD[PriceInfo]。

即来到我的脑海里唯一的解决办法就是循环RDD [列表[字符串]用foreach()函数,创建3个PriceInfo在每次迭代的对象,然后添加列表[PriceObjects]所有创建的对象,并使用该结果名录中SparkContext .parallelize(List...)

像这样的东西:

rawPricesList.foreach(list => {

      //...create PriceInfo1 from list
      //...create PriceInfo2 from list
      //...create PriceInfo3 from list

      //...add them all to result List<PriceInfo>

    })

    //...sc.parallelize(List<PriceInfo>...)

但是这样的解决方案有很多缺点。

主要的是,如果我们没有指向 SparkContext 的链接,它将无法工作。 例如,如果我们有一个方法 getPrices(),它只有 1 个参数 - RDD[List[String]]。

def getPrices(rawPricesList: RDD[List[String]]): RDD[PriceInfo] = {



    rawPricesList.foreach(list => {

      //...create PriceInfo1 from list
      //...create PriceInfo2 from list
      //...create PriceInfo3 from list

      //...add them all to result List<PriceInfo>

    })

    //...but we can't sc.parallelize(List...) here, because there is no SparkContext sc in method parameters
  }

此外,在我看来,Scala 包含一个更优雅的解决方案。

我试图在《不耐烦的Scala》和《学习Spark:闪电般快速的大数据分析》一书中找到类似的样本,但很遗憾没有找到类似的案例。 我将非常感谢您的帮助和提示。

这是一种方法:

  1. 加载文本文件并将每一行拆分为一个数组[String] of (id, date, price1, price2, price3)
  2. 使用zip将每一行转换为 (id, date, Array[(country, numericPrice)])
  3. 使用flatMap每行中的 (country, numericPrice) 元组展平为PriceInfo对象的行

示例代码如下:

case class PriceInfo(priceId: String, priceDate: String, country: String, price: Double) {
  override def toString: String = s"$priceId,$priceDate,$country,$price"
}

val countryList = List("USA", "UK", "AUS")

val rdd = sc.textFile("/path/to/textfile").
  map( _.split(",") ).
  map{ case Array(id, date, p1, p2, p3) =>
    (id, date, countryList.zip(List(p1.toDouble, p2.toDouble, p3.toDouble)))
  }.
  flatMap{ case (id, date, countryPrices) =>
    countryPrices.map( cp => PriceInfo(id, date, cp._1, cp._2) ) 
  }
// rdd: org.apache.spark.rdd.RDD[PriceInfo] = ...

rdd.collect
// res1: Array[PriceInfo] = Array(
//    0000002,11-05-08-2016,USA,0.92,
//    0000002,11-05-08-2016,UK,1.68,
//    0000002,11-05-08-2016,AUS,0.81,
//    0000003,07-05-08-2016,USA,0.8,
//    0000003,07-05-08-2016,UK,1.05,
//    0000003,07-05-08-2016,AUS,1.49,
//    0000008,07-05-08-2016,USA,1.43,
//    0000008,07-05-08-2016,UK,1.29,
//    0000008,07-05-08-2016,AUS,1.22
// )

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM