我正在尝试结构化Spark Streaming Stream-Stream Join,而我的左外部联接的行为与内部联接完全相同。
使用spark版本2.4.2和Scala版本2.12.8,Eclipse OpenJ9 VM,1.8.0_252
这就是我想要做的,
期望: 经过30秒的时间限制后,对于不匹配的行,我应该在连接右侧看到null。
发生了什么
代码-尝试使用spark-shell
import java.sql.Timestamp
import org.apache.spark.sql.streaming.{OutputMode, Trigger}
case class RateData(timestamp: Timestamp, value: Long)
// create rate source with 1 row per second.
val rateSource = spark.readStream.format("rate").option("rowsPerSecond", 1).option("numPartitions", 1).option("rampUpTime", 1).load()
import spark.implicits._
val rateSourceData = rateSource.as[RateData]
// employee stream departid increments by 2
val employeeStreamDS = rateSourceData.withColumn("firstName", concat(lit("firstName"),rateSourceData.col("value")*2)).withColumn("departmentId", lit(floor(rateSourceData.col("value")*2))).withColumnRenamed("timestamp", "empTimestamp").withWatermark("empTimestamp", "10 seconds")
// dept stream id increments by 3
val departmentStreamDS = rateSourceData.withColumn("name", concat(lit("name"),floor(rateSourceData.col("value")*3))).withColumn("Id", lit(floor(rateSourceData.col("value")*3))).drop("value").withColumnRenamed("timestamp", "depTimestamp")
// watermark - 10s and time constraint is 30 secs on employee stream.
val joinedDS = departmentStreamDS.join(employeeStreamDS, expr(""" id = departmentId AND empTimestamp >= depTimestamp AND empTimestamp <= depTimestamp + interval 30 seconds """), "leftOuter")
val q = joinedDS.writeStream.format("parquet").trigger(Trigger.ProcessingTime("60 seconds")).option("checkpointLocation", "checkpoint").option("path", "rate-output").start
10分钟后,我查询了表的输出,但我只找到31个匹配的行。与内部联接输出相同。
val df = spark.read.parquet("rate-output")
df.count
res0: Long = 31
df.agg(min("departmentId"), max("departmentId")).show
+-----------------+-----------------+
|min(departmentId)|max(departmentId)|
+-----------------+-----------------+
| 0| 180|
+-----------------+-----------------+
输出说明。 employeeStreamDS流,部门ID字段值是费率值的2倍,因此是2的倍数。
departmentStreamDS流,Id字段是速率流值的3倍,因此为3的倍数。
因为LCM(2,3)= 6,所以每6个部门的ID将匹配一次。 直到这些流之间相差30秒(加入时间限制)。
我希望30秒后,我将为dept流值(3,9,15 ..)设置空值,等等。
我希望我对它的解释足够好。
关于火花流的左外连接行为的结果问题。
答案 0 :(得分:2)
根据我的理解并确实根据https://spark.apache.org/docs/latest/structured-streaming-programming-guide.html#stream-stream-joins,您需要在两个流的事件时间列上应用水印,例如:
val impressionsWithWatermark = impressions.withWatermark("impressionTime", "2 hours")
val clicksWithWatermark = clicks.withWatermark("clickTime", "3 hours")
...
impressionsWithWatermark.join(
clicksWithWatermark,
expr("""
clickAdId = impressionAdId AND
clickTime >= impressionTime AND
clickTime <= impressionTime + interval 1 hour
"""),
joinType = "leftOuter" // can be "inner", "leftOuter", "rightOuter"
)
您仅定义了一个watermark
。