[英]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"
应该转化为:
并且我的 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:闪电般快速的大数据分析》一书中找到类似的样本,但很遗憾没有找到类似的案例。 我将非常感谢您的帮助和提示。
这是一种方法:
zip
将每一行转换为 (id, date, Array[(country, numericPrice)])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.