我开发了一个火花流媒体应用程序,其中包含json字符串的数据流。
sc = SparkContext("local[*]", "appname")
sc.setLogLevel("WARN")
sqlContext = sql.SQLContext(sc)
#batch width in time
stream = StreamingContext(sc, 5)
stream.checkpoint("checkpoint")
# mqtt setup
brokerUrl = "tcp://localhost:1883"
topic = "test"
# mqtt stream
DS = MQTTUtils.createStream(stream, brokerUrl, topic)
# transform DStream to be able to read json as a dict
jsonDS = kvs.map(lambda v: json.loads(v))
#create SQL-like rows from the json
sqlDS = jsonDS.map(lambda x: Row(a=x["a"], b=x["b"], c=x["c"], d=x["d"]))
#in each batch do something
sqlDS.foreachRDD(doSomething)
# run
stream.start()
stream.awaitTermination()
def doSomething(time,rdd):
data = rdd.toDF().toPandas()
上面的代码按预期工作:我以字符串方式接收一些jsons,我可以将每个批处理转换为数据帧,同时将其转换为Pandas DataFrame。
到目前为止一切顺利。
如果我想向DataFrame添加不同的架构,则会出现问题。
方法toDF()
在以下函数中假定为schema=None
:sqlContext.createDataFrame(rdd, schema)
。
如果我尝试从sqlContext
内部访问doSomething()
,则很明显它未定义。如果我尝试使用全局变量使其可用,我会得到无法序列化的典型错误。
我还读过sqlContext只能在Spark Driver中使用而不能在worker中使用。
所以问题是:toDF()
首先是如何工作的,因为它需要sqlContext?如何为其添加架构(希望不改变源代码)?
在驱动程序中创建DataFrame似乎不是一个选项,因为我无法将其序列化为worker。
也许我没有正确看到这一点。
提前多多感谢!
答案 0 :(得分:0)
回答我自己的问题......
定义以下内容:
def getSparkSessionInstance(sparkConf):
if ("sparkSessionSingletonInstance" not in globals()):
globals()["sparkSessionSingletonInstance"] = SparkSession \
.builder \
.config(conf=sparkConf) \
.getOrCreate()
return globals()["sparkSessionSingletonInstance"]
然后从工人那里打来电话:
spark = getSparkSessionInstance(rdd.context.getConf())