【问题标题】:Convert Spark DataFrame to HashMap将 Spark DataFrame 转换为 HashMap
【发布时间】:2018-01-27 00:22:37
【问题描述】:

我有一个如下所示的数据框:

product1 product2 difference
123      456      0.5
123      789      1
456      789      0
456      123      0.5
789      123      1
789      456      0

我想要一个如下所示的输出:

{'123': {'456': 0.5, '789': 1}, 456: {'123': 0.5, '789': 1}, '789': {'123': 1, '456': 0}}

到目前为止,我已经尝试过zipWithIndexcollectAsMap,但没有成功。

到目前为止我尝试过的代码是:

val tples: RDD[(Int, (Int, Double))] = (products.rdd
  .map(r => (r(0).toString.toDouble.toInt, (r(1).toString.toDouble.toInt, r(2).toString.toDouble))))
val lst: = tpls.groupByKey().map(r => (r._1, r._2.toSeq))

这给了我产品和差异的列表,而不是哈希图

【问题讨论】:

  • 我相信你还有一个 RDD,而不是一个列表......如果你想要一个 Hashmap ,你必须收集 RDD
  • 这是错字吗? 456 -> 789 -> 1 在示例中应该是 456 -> 789 -> 0.0

标签: scala apache-spark hashmap tuples spark-dataframe


【解决方案1】:

您可以先将数据帧转换为 RDD,将其转换为键值类型,然后执行groupByKey。要获得想要的Map 形式的结果,您需要collect 分组的RDD(因此对于大型数据集可能不可行):

val df = Seq(
  (123, 456, 0.5),
  (123, 789, 1.0),
  (456, 789, 0.0),
  (456, 123, 0.5),
  (789, 123, 1.0),
  (789, 456, 0.0)
).toDF("product1", "product2", "difference")

import org.apache.spark.sql.Row

val groupedRDD = df.rdd.map{
    case Row(p1: Int, p2: Int, diff: Double) => (p1, (p2, diff))
  }.
  groupByKey.mapValues(_.toMap)

groupedRDD.collectAsMap
// res1: scala.collection.immutable.Map[Any,scala.collection.immutable.Map[Int,Double]] = Map(
//   456 -> Map(789 -> 0.0, 123 -> 0.5), 789 -> Map(123 -> 1.0, 456 -> 0.0), 123 -> Map(456 -> 0.5, 789 -> 1.0)
// )

【讨论】:

    【解决方案2】:

    如果我正确理解你的问题,你想要这样的东西:

    val myRdd = sc.makeRDD(List(
      (123, (456, 0.5)), 
      (123, (789, 1.0)), 
      (456, (789, 0.0)), 
      (456, (123, 0.5)), 
      (789, (123, 1.0)), 
      (789, (456, 0.0))
    ))
    
    
    val myHashMap = myRdd.groupByKey.mapValues(_.toMap).collect.toMap
    
    // gives:
    // scala.collection.immutable.Map[Int,scala.collection.immutable.Map[Int,Double]] = 
    //   Map(
    //     456 -> Map(789 -> 0.0, 123 -> 0.5), 
    //     789 -> Map(123 -> 1.0, 456 -> 0.0), 
    //     123 -> Map(456 -> 0.5, 789 -> 1.0)
    //   )
    

    简要说明:groupByKey 为您提供像 (123, Seq((456, 0.5), (789, 1.0))) 这样的元组。您想将第二个组件(“值”)转换为映射,因此您调用 mapValues(_.toMap)。然后(如果您真的想将集合加载到您的节点并将其转换为本地的非分布式地图),您必须调用collect。这基本上为您提供了(Int, Map[Int, Double]) 类型的元组列表。现在你可以在这个集合上调用toMap来获取地图地图。

    【讨论】:

      猜你喜欢
      • 2019-02-17
      • 2017-03-17
      • 1970-01-01
      • 2018-11-30
      • 2017-04-03
      • 2017-03-25
      • 1970-01-01
      • 2017-08-10
      • 2018-04-17
      相关资源
      最近更新 更多