在不同的类中访问Spark广播变量

时间:2016-04-15 09:12:27

标签: scala apache-spark apache-spark-sql spark-streaming

我在Spark Streaming应用程序中广播一个值。但我不知道如何在与播放它的类不同的类中访问该变量。

我的代码如下:

object AppMain{
  def main(args: Array[String]){
    //...
    val broadcastA = sc.broadcast(a)
    //..
    lines.foreachRDD(rdd => {
    val obj = AppObject1
    rdd.filter(p => obj.apply(p))
    rdd.count
  }
}

object AppObject1: Boolean{
  def apply(str: String){
    AnotherObject.process(str)
  }
}
object AnotherObject{
  // I want to use broadcast variable in this object
  val B = broadcastA.Value // compilation error here
  def process(): Boolean{
   //need to use B inside this method
  }
}

在这种情况下,有人可以建议如何访问广播变量吗?

3 个答案:

答案 0 :(得分:6)

这里没有特别的Spark特定于忽略可能的序列化问题。如果你想使用某个对象,它必须在当前范围内可用,你可以像往常一样实现这个目的:

  • 您可以在已定义广播的范围内定义助手:

    {
        ...
        val x = sc.broadcast(1)
        object Foo {
          def foo = x.value
        }
        ...
    }
    
  • 您可以将它用作构造函数参数:

    case class Foo(x: org.apache.spark.broadcast.Broadcast[Int]) {
      def foo = x.value
    }
    
    ...
    
    Foo(sc.broadcast(1)).foo
    
  • 方法参数

    case class Foo() {
      def foo(x: org.apache.spark.broadcast.Broadcast[Int]) = x.value
    }
    
    ...
    
    Foo().foo(sc.broadcast(1))
    
  • 甚至是这样的帮助者:

    trait Foo {
      val x: org.apache.spark.broadcast.Broadcast[Int]
      def foo = x.value
    }
    
    object Main extends Foo {
      val sc = new SparkContext("local",  "test", new SparkConf())
      val x = sc.broadcast(1)
    
      def main(args: Array[String]) {
        sc.parallelize(Seq(None)).map(_ => foo).first
        sc.stop
      }
    }
    

答案 1 :(得分:1)

对前面介绍的性能注意事项进行简短介绍。

zero233提出的选项确实是在Scala中执行此类操作的非常优雅的方式。同时,重要的是要了解在分布式系统中使用某些模式的含义。

使用混合方法/使用封闭类状态的任何逻辑不是最好的主意。每当您在lambdas中使用封闭类的状态时,Spark都必须序列化外部对象。并非总是如此,但是最好写安全的代码,而不是有一天不小心炸毁整个集群。

意识到这一点,我个人会去将显式参数传递给方法,因为这不会导致外部类序列化(method argument方法)。

答案 2 :(得分:0)

您可以使用类并将广播变量传递给类

你的psudo代码应如下所示:

object AppMain{
   def main(args: Array[String]){
     //...
     val broadcastA = sc.broadcast(a)
     //..
     lines.foreach(rdd => {
       val obj = new AppObject1(broadcastA)
       rdd.filter(p => obj.apply(p))
       rdd.count
     })
   }
}

class AppObject1(bc : Broadcast[String]){
   val anotherObject = new AnotherObject(bc)
   def apply(str: String): Boolean ={
      anotherObject.process(str)
   }
}

class AnotherObject(bc : Broadcast[String]){
  // I want to use broadcast variable in this object
  def process(str : String): Boolean = {
    val a = bc.value
    true
    //need to use B inside this method
  }
}