Apache Spark Streaming中的定期广播

时间:2015-02-18 00:27:22

标签: apache-spark spark-streaming

我正在实现一个用于文本分类的流学习器。我的实现中有一些单值参数需要在新流项到达时进行更新。例如,我想在新的预测发生时改变学习率。但是,我怀疑在初始广播之后有一种方法可以广播变量。那么如果我每次更新它时都需要广播变量会发生什么。如果有一种方法可以做到这一点或者解决我想要在Spark Streaming中完成的工作,我会很高兴听到它。

提前致谢。

5 个答案:

答案 0 :(得分:2)

我的理解是,一旦广播变量最初被发送出去,它就是“只读”。我相信你可以更新本地节点上的广播变量,但不能更新远程节点上的广播变量。

可能你需要考虑在“Spark之外”这样做。如何使用noSQL商店(Cassandra ..etc)甚至Memcache?然后,您可以从一个任务更新变量,并定期从其他任务中检查此存储?

答案 1 :(得分:2)

我通过在广播变量上创建一个包装类来实现这一点。包装类的updateAndGet方法返回刷新的广播变量。我在dStream.transform中调用了这个函数 - >根据Spark文档

http://spark.apache.org/docs/latest/streaming-programming-guide.html#transform-operation

转换操作状态: "在每个批处理间隔中调用提供的函数。这允许您进行时变RDD操作,即RDD操作,分区数量,广播变量等。可以在批次之间更改。"

BroadcastWrapper类看起来像:

public class BroadcastWrapper {
private Broadcast<ReferenceData> broadcastVar;
private Date lastUpdatedAt = Calendar.getInstance().getTime();

private static BroadcastWrapper obj = new BroadcastWrapper();

private BroadcastWrapper(){}

public static BroadcastWrapper getInstance() {
       return obj;
}

public JavaSparkContext getSparkContext(SparkContext sc) {
      JavaSparkContext jsc = JavaSparkContext.fromSparkContext(sc);
      return jsc;
}

public Broadcast<ReferenceData> updateAndGet(SparkContext sparkContext){
       Date currentDate = Calendar.getInstance().getTime();
       long diff = currentDate.getTime()-lastUpdatedAt.getTime();
       if (var == null || diff > 60000) { //Lets say we want to refresh every 1 min = 60000 ms
           if (var != null)
              var.unpersist();
           lastUpdatedAt = new Date(System.currentTimeMillis());

           //Your logic to refresh
           ReferenceData data = getRefData();

           var = getSparkContext(sparkContext).broadcast(data);
      }
      return var;
}
}

您可以在允许RDD-RDD转换的stream.transform方法中使用此广播变量updateAndGet函数

objectStream.transform(stream -> {

  Broadcast<Object> var = BroadcastWrapper.getInstance().updateAndGet(stream.context());

/**Your code to manipulate stream **/
});

请参阅我的完整答案:https://stackoverflow.com/a/41259333/3166245

希望有所帮助

答案 2 :(得分:1)

我玩得很丑,但是有效! 我们可以找到如何从广播对象获取广播值。 https://github.com/apache/spark/blob/master/core/src/main/scala/org/apache/spark/broadcast/TorrentBroadcast.scala#L114 只是通过广播ID。

所以我定期通过相同的广播ID重播。

val broadcastFactory = new TorrentBroadcastFactory()
broadcastFactory.unbroadcast(BroadcastId, true, true)
// append some ids to initIds
val broadcastcontent = broadcastFactory.newBroadcast[.Set[String]](initIds, false, BroadcastId)

我可以从第一个广播值获得BroadcastId。

val ids = ssc.sparkContext.broadcast(initIds)
// broadcast id
val BroadcastId = broadcastIds.id

然后工人正常使用ID作为广播类型。

def func(record: Array[Byte], bc: Broadcast[Set[String]]) = ???

答案 3 :(得分:1)

bkc.unpersist(true)
bkc.destroy() 
bkc = sc.broadcast(tableResultMap) 
bkv = bkc.value

你可以试试这个,我不保证是否有效

答案 4 :(得分:0)

最好将数据收集到驱动程序,然后将它们广播到所有节点。

使用Dstream # foreachRDD在驱动程序中收集计算出的RDD,一旦知道何时需要更改学习速率,就可以使用SparkContext#broadcast(value)将新值发送到所有节点。

我希望代码看起来像下面这样:

dStreamContainingBroadcastValue.foreachRDD{ rdd => 
      val valueToBroadcast = rdd.collect()
      sc.broadcast(valueToBroadcast)
}

您还可以从spark用户邮件列表中找到有用的this thread。如果有效,请告诉我。