Python 如何将Spark流数据转换为Spark数据帧
到目前为止,Spark还没有为流式数据创建DataFrame,但是当我进行异常检测时,使用DataFrame进行数据分析更方便、更快。我已经完成了这一部分,但是当我尝试使用流数据进行实时异常检测时,问题出现了。我尝试了几种方法,但仍然无法将数据流转换为数据帧,也无法将数据流内部的RDD转换为数据帧 以下是我最新版本代码的一部分:Python 如何将Spark流数据转换为Spark数据帧,python,pyspark,spark-streaming,Python,Pyspark,Spark Streaming,到目前为止,Spark还没有为流式数据创建DataFrame,但是当我进行异常检测时,使用DataFrame进行数据分析更方便、更快。我已经完成了这一部分,但是当我尝试使用流数据进行实时异常检测时,问题出现了。我尝试了几种方法,但仍然无法将数据流转换为数据帧,也无法将数据流内部的RDD转换为数据帧 以下是我最新版本代码的一部分: import sys import re from pyspark import SparkContext from pyspark.sql.context impo
import sys
import re
from pyspark import SparkContext
from pyspark.sql.context import SQLContext
from pyspark.sql import Row
from pyspark.streaming import StreamingContext
from pyspark.mllib.clustering import KMeans, KMeansModel, StreamingKMeans
from pyspark.sql.functions import *
from pyspark.sql.types import *
from pyspark.sql.functions import udf
import operator
sc = SparkContext(appName="test")
ssc = StreamingContext(sc, 5)
sqlContext = SQLContext(sc)
model_inputs = sys.argv[1]
def streamrdd_to_df(srdd):
sdf = sqlContext.createDataFrame(srdd)
sdf.show(n=2, truncate=False)
return sdf
def main():
indata = ssc.socketTextStream(sys.argv[2], int(sys.argv[3]))
inrdd = indata.map(lambda r: get_tuple(r))
Features = Row('rawFeatures')
features_rdd = inrdd.map(lambda r: Features(r))
features_rdd.pprint(num=3)
streaming_df = features_rdd.flatMap(streamrdd_to_df)
ssc.start()
ssc.awaitTermination()
if __name__ == "__main__":
main()
正如您在main()函数中所看到的,当我使用ssc.socketextstream()方法读取输入流数据时,它会生成数据流,然后我尝试将数据流中的每个个体转换为行,希望以后可以将数据转换为数据帧
如果我在这里使用ppprint()打印出features\u rdd,它会起作用,这让我想到,features\u rdd中的每个单独部分都是一批rdd,而整个features\u rdd是一个数据流
然后我创建了streamrdd_to_df()方法,希望将每批RDD转换为dataframe,它给出了错误,显示:
ERROR StreamingContext:启动上下文时出错,将其标记为已停止
java.lang.IllegalArgumentException:需求失败:未注册任何输出操作,因此无法执行任何操作
有没有想过如何对Spark streaming data执行数据帧操作?仔细阅读错误。它说没有注册输出操作。Spark是懒惰的,只有当它有结果时才执行作业/cod。在您的程序中没有“输出操作”,Spark也在抱怨这一点
在数据帧上定义foreach()或原始SQL查询,然后打印结果。它会很好地工作。Spark为我们提供了结构化流媒体,可以解决这些问题。它可以生成流数据帧,即连续追加的数据帧。请查看下面的链接
为什么不使用这样的东西:
def socket_streamer(sc): # retruns a streamed dataframe
streamer = session.readStream\
.format("socket") \
.option("host", "localhost") \
.option("port", 9999) \
.load()
return streamer
上面这个函数的输出本身(或者通常是readStream
)是一个数据帧。在这里,您不需要担心df,它已经由spark自动创建。
参见1年后,我开始探索Spark 2.0流媒体方法,并最终解决了异常检测问题,您还可以在Spark 2.3/Python 3/Scala 2.11(使用databricks)中找到,我可以在Scala中使用临时表和代码片段(在笔记本中使用magic): Python部分:
ddf.createOrReplaceTempView("TempItems")
然后在新单元格上:
%scala
import java.sql.DriverManager
import org.apache.spark.sql.ForeachWriter
// Create the query to be persisted...
val tempItemsDF = spark.sql("SELECT field1, field2, field3 FROM TempItems")
val itemsQuery = tempItemsDF.writeStream.foreach(new ForeachWriter[Row]
{
def open(partitionId: Long, version: Long):Boolean = {
// Initializing DB connection / etc...
}
def process(value: Row): Unit = {
val field1 = value(0)
val field2 = value(1)
val field3 = value(2)
// Processing values ...
}
def close(errorOrNull: Throwable): Unit = {
// Closing connections etc...
}
})
val streamingQuery = itemsQuery.start()
不需要将数据流转换为RDD。根据定义,DStream是RDD的集合。只需使用DStream的foreach()方法在每个RDD上循环并采取行动
val conf = new SparkConf()
.setAppName("Sample")
val spark = SparkSession.builder.config(conf).getOrCreate()
sampleStream.foreachRDD(rdd => {
val sampleDataFrame = spark.read.json(rdd)
}
spark介绍了如何使用DStream。基本上,您必须在流对象上使用foreachRDD
与之交互
下面是一个示例(请确保创建spark会话对象):
谢谢@Sumit,我确实试过输出结果。在streamrdd_to_df()函数中,我使用
sdf.show(n=2,truncate=False)
打印结果,但它无法……我执行了代码,它对我有效。我所做的唯一更改是用tuple
替换get\u tuple
,并删除pyspark.mllib…
import。虽然输出没有意义,但没有错误。这个错误还有其他原因吗?你能粘贴完整的堆栈跟踪吗?我刚刚读到,他们在Spark 2.0中添加了它,这可能是解决这个问题的方法。我使用的是Spark 1.5,它现在比发布时有了很大的改进。
def process_stream(record, spark):
if not record.isEmpty():
df = spark.createDataFrame(record)
df.show()
def main():
sc = SparkContext(appName="PysparkStreaming")
spark = SparkSession(sc)
ssc = StreamingContext(sc, 5)
dstream = ssc.textFileStream(folder_path)
transformed_dstream = # transformations
transformed_dstream.foreachRDD(lambda rdd: process_stream(rdd, spark))
# ^^^^^^^^^^
ssc.start()
ssc.awaitTermination()