我想加入DStream中的每个RDD,并使用非流式,不变的参考文件。这是我的代码:
val sparkConf = new SparkConf().setAppName("LogCounter")
val ssc = new StreamingContext(sparkConf, Seconds(2))
val sc = new SparkContext()
val geoData = sc.textFile("data/geoRegion.csv")
.map(_.split(','))
.map(line => (line(0), (line(1),line(2),line(3),line(4))))
val topicMap = topics.split(",").map((_,numThreads.toInt)).toMap
val lines = KafkaUtils.createStream(ssc, zkQuorum, group, topicMap).map(_._2)
val goodIPsFltrBI = lines.filter(...).map(...).filter(...) // details removed for brevity
val vdpJoinedGeo = goodIPsFltrBI.transform(rdd =>rdd.join(geoData))
我遇到很多很多错误,最常见的是:
14/11/19 19:58:23 WARN TaskSetManager: Loss was due to java.io.FileNotFoundException
java.io.FileNotFoundException: http://10.102.71.92:40764/broadcast_1
我想我应该播放geoData而不是每次任务都读取它(它是一个100MB的文件),但我不知道在哪里放置初始化geoData的代码。
另外我不确定geoData是否被正确定义(也许它应该使用ssc而不是sc?)。我见过的文档只列出了转换和连接,但未显示静态文件是如何创建的。
有关如何广播geoData然后将其加入每个流式RDD的任何想法?
答案 0 :(得分:4)
geoData textFile从所提供的位置(“data / geroRegion.csv”)加载到所有工作人员。最有可能的是,此文件仅在驱动程序中可用,因此工作人员无法加载它,抛出未找到的文件异常。
广播变量在驱动程序上定义,并通过解包广播容器来获取内容,从而在工作程序上使用。 这意味着广播变量包含的数据应该在定义作业之前由驱动程序加载。
在这种情况下,这可能会解决两个问题:假设geoData.csv文件位于驱动程序节点中,它将允许在驱动程序上正确加载此数据并在群集上有效传播。
在上面的代码中,将geoData加载替换为本地文件读取版本:
val geoData = Source.fromFile("data/geoRegion.csv").getLines
.map(_.split(','))
.map(line => (line(0), (line(1),line(2),line(3),line(4)))).toMap
val geoDataBC = sc.broadcast(geoData)
要使用它,您可以访问闭包内的广播内容。请注意,您将可以访问先前包含在广播变量中的地图:它是一个简单的对象,而不是RDD,因此在这种情况下,您无法使用join
合并两个数据集。您可以改用flatMap:
val vdpJoinedGeo = goodIPsFltrBI.flatMap{ip => geoDataBC.value.get(ip).map(data=> (ip,data)}