经过多次加入后,我得到了一个包含以下记录的RDD:
(Int, ((Int, Option[Iterable[Int]]), Option[Iterable[Int]]))
是:
(id_of_client, ((id_of_order, products_in_order), all_products_client_ever_bought)
我需要将其转换为(Int,Int,Boolean):
(id_of_order, all_products_client_ever_bought._1, was_this_product_in_this_order)
(id_of_order, all_products_client_ever_bought._2, was_this_product_in_this_order)
(id_of_order, all_products_client_ever_bought._3, was_this_product_in_this_order)
...
结果RDD中应该有尽可能多的记录,因为在输入RDD的所有记录的all_products_client_ever_bought中都有项目。所以我正在映射我的输入RDD,rdd.map(transform_df(_))
def transform_df(row: (Int, ((Int, Option[Iterable[Int]]), Option[Iterable[Int]]))) = {
//(order_id, user_product_id, if_order_contains_product)
val order_products = row._2._1._2.get.toList
val user_products = row._2._2.get
for (product_id <- user_products) {
(row._2._1._1, product_id, order_products.contains(product_id))
}
}
因此我获得与输入相同长度的RDD,但是具有空元组。如何转换RDD?
答案 0 :(得分:1)
你是对的,你需要&#34;爆炸&#34;您的数据集,即将每条记录映射到多条记录。使用RDD API以及大多数函数式编程语言,您需要使用flapMap函数(explode用于数据帧)。
有关如何使用flatmap的更多详细信息,请参阅map-map-and-flatmap-in-scala。基本上,对于类型A的每个记录,您映射Seq [B]类型的序列,并得到RDD [B]类型的RDD,其中所有内容都被展平。
Spark中另一个非常方便的方法是flatMapValue,它可以在pairRDD(键值RDD)上工作,只会使值变平。
在您的示例中,您可以首先将RDD映射到仅包含您需要的内容以及更方便操作的内容。
rdd.map{ case (id_of_client, ((id_of_order, products_in_order), all_products)
=> id_of_order -> (products_in_order.get.toSet, all_products.get) }
请注意,使用模式匹配而不是._1._2._2表示法是一种很好的做法,可以使您的代码更具可读性。我还将订单的产品转换为Set,因为我们之后需要向它发出请求。
然后你只需要使用flatMapValues来获得你想要的东西。
.flatMapValues{ case (products_in_order, all_products) =>
all_products.map(p => p -> product_in_order.contains(p)) }
.map { case (a,(b,c)) => (a,b,c) }
最后一行只会将结果转换为您想要的结果。