这是一个多方面的问题:
结构化流式API具有IMHO限制。
一个人可以通过管道传输多个查询,并在技术上运行它,但不会产生任何输出,因此这样做毫无价值——即使您可以指定它,它也无法执行此类其他功能。
手动状态:必须在与时间戳相同的列上调用WithWatermark
聚合中使用的列。
例如,df.withWatermark(“时间”,“1”
Min”).GroupBy(“Time2”).Count()在追加输出模式下无效,因为
水印是在与聚合不同的列上定义的
列。
简单地说,附加需要水印。
我觉得你有问题。
使用路径时是否与以下相关?
.enableHiveSupport().config("hive.exec.dynamic.partition", "true")
.config("hive.exec.dynamic.partition.mode", "nonstrict")
另外,您的最终用例还不知道。这里的问题是,这是否是一个好的方法,但是对于我来说,没有太多的洞察力来评估,我们只是假设它是这样的。
我们假设同一部电影的收视率将成为未来微博的一部分。
在提要中缺少事件时间,但您自己创建它。有些不切实际,但是我们可以接受,尽管时间戳有点问题。
所以,一般来说:
在完成的选项中,追加和更新我认为您选择了正确的追加。可以使用更新,但我把它放在范围之外。
但并没有把事件时间放在窗口里。你应该这样做。我在这里最后举了一个例子,在Spark Shell中运行,我无法让case类工作——这就是为什么它花费了这么长时间,但是在编译的程序中,它不是一个问题,也不是数据块。
在功能上,您不能编写多个查询来执行所尝试的聚合。在我的例子中,它只会产生一些错误。
我建议您使用我使用的时间戳方法,这比较容易,因为我无法测试所有的东西。
然后:
或者,将该模块的输出写入卡夫卡主题,并将该主题读取到另一个模块中,然后进行第二次聚合和写出,同时考虑到您可以在不同的微博中获得多个电影分级。
或者,在包含计数字段的情况下写出数据,然后为查询提供一个视图层,考虑到存在多个写入的事实。
下面是一个使用插座输入和火花外壳的示例-您可以将其外推到自己的数据和微型批次的输出(请注意,看到数据时会有延迟):
import java.sql.Timestamp
import org.apache.spark.sql.SparkSession
import org.apache.spark.sql.functions._
import org.apache.spark.sql.streaming.OutputMode
val sparkSession = SparkSession.builder
.master("local")
.appName("example")
.getOrCreate()
//create stream from socket
import sparkSession.implicits._
sparkSession.sparkContext.setLogLevel("ERROR")
val socketStreamDs = sparkSession.readStream
.format("socket")
.option("host", "localhost")
.option("port", 9999)
.load()
.as[String]
val stockDs = socketStreamDs.map(value => (value.trim.split(","))).map(entries=>(new java.sql.Timestamp(entries(0).toLong),entries(1),entries(2).toDouble)).toDF("time","symbol","value")//.toDS()
val windowedCount = stockDs
.withWatermark("time", "20000 milliseconds")
.groupBy(
window($"time", "10 seconds"),
$"symbol"
)
.agg(sum("value"), count($"symbol"))
val query =
windowedCount.writeStream
.format("console")
.option("truncate", "false")
.outputMode(OutputMode.Append())
query.start().awaitTermination()
结果:
Batch: 14
----------------------------------------------+------+----------+-------------+
|window |symbol|sum(value)|count(symbol)|
+---------------------------------------------+------+----------+-------------+
|[2016-04-27 04:34:20.0,2016-04-27 04:34:30.0]|"aap1"|4200.0 |6 |
|[2016-04-27 04:34:30.0,2016-04-27 04:34:40.0]|"app1"|800.0 |2 |
|[2016-04-27 04:34:20.0,2016-04-27 04:34:30.0]|"aap2"|2500.0 |1 |
|[2016-04-27 04:34:40.0,2016-04-27 04:34:50.0]|"app1"|2800.0 |4 |
+---------------------------------------------+------+----------+-------------+
这是一个相当大的主题,你需要从整体上看。
您可以看到,对于某些情况下具有计数的输出可能很方便,尽管AVG输出可用于计算总体AVG.成功。