PairRDD,每个键初始化变量

时间:2017-01-11 15:30:52

标签: scala apache-spark rdd

我有一个很大的RDD[(K, V)]。为了映射这些值,我需要一个每个密钥都很常见的大型数据结构,并且构建起来很昂贵。我之后无法执行groupByKey并执行flatMap,因为每个密钥的值都不适合内存。我无法加载所有结构,因为它们也不适合内存。如何每组执行一次结构初始化(或最少次数),然后将其删除?

使用例

  • 我们有一个RDD [String,String]。键表示值的语言,即该语言的短文本。
  • 我们想要对值的一些标记进行分类。为此,我们需要为每种语言构建一个trie,其中包含一些标记的类别。
  • 构建trie是昂贵的,所以我们无法构建foreach(K,V)对。单个trie将适合内存,但保持所有语言的尝试不会(给定不同键的数量)。
  • 因此,我们需要一种方法来构建最少次数的trie,并且只在内存中保留一些它们。

2 个答案:

答案 0 :(得分:0)

根据您的用例,您可以为这个大型数据结构使用广播变量

CREATE TRIGGER update_child_validitiy AFTER UPDATE ON parents
 FOR EACH ROW
 BEGIN
   UPDATE children SET child_validity = NEW.parent_validity WHERE id = NEW.id;
 END;

http://spark.apache.org/docs/latest/programming-guide.html#broadcast-variables

或者您可以使用val broadcastVar = sc.broadcast(LargeThingy()) broadcastVar.value 并为每个分区初始化一个大的东西,然后处理分区中的数据:

rdd.foreachPartition

答案 1 :(得分:0)

例如,您可以RDD使用repartitionAndSortWithinPartitions后跟mapPartitions

val partitioner: org.apache.spark.Partitioner = ???

rdd.repartitionAndSortWithinPartition(partitioner).mapPartitions { iter => {
  var currentKey: Option[String] = None
  var currentTrie: Option[Trie] = None 
  iter.map {
    case (k, v) => 
      .. // if Option(k) != currentKey update currentKey and currentTrie
      .. // Proceed with logic
  }
}}

Dataset groupBy后跟flatMapGroups

rdd.toDS.groupByKey(_._1).flatMapGroups { case (key, iter) => {
  val currentTrie: Trie = ???
  iter.map { case (_, v) => ??? }
})

与其RDD对应Dataset不同,不必同时将所有值加载到内存中,因此各个组的大小不应成为问题。

两种解决方案都需要完全随机播放,但每个参考结构只会为每个键初始化一次。