Scala 结构化外部联接的行为类似于内部联接

Scala 结构化外部联接的行为类似于内部联接,scala,apache-spark,left-join,spark-streaming,Scala,Apache Spark,Left Join,Spark Streaming,我正在尝试结构化spark流连接,我左侧的外部连接与内部连接的行为完全相同 使用spark版本2.4.2和Scala版本2.12.8,EclipseOpenJ9VM,1.8.0ü 这就是我要做的 创建每秒生成1行的速率流 从中创建员工和部门流 员工流deptId字段将比率值乘以2,部门流id字段将乘以3 这样做的目的是使两个流具有很少的公共id字段和非公共id字段 执行leftOuter流-流连接,时间限制为30秒,dept流位于连接左侧 期望: 在30秒的时间限制之后,对于不匹配的行,我应该在

我正在尝试结构化spark流连接,我左侧的外部连接与内部连接的行为完全相同

使用spark版本2.4.2和Scala版本2.12.8,EclipseOpenJ9VM,1.8.0ü

这就是我要做的

  • 创建每秒生成1行的速率流
  • 从中创建员工和部门流
  • 员工流deptId字段将比率值乘以2,部门流id字段将乘以3
  • 这样做的目的是使两个流具有很少的公共id字段和非公共id字段
  • 执行leftOuter流-流连接,时间限制为30秒,dept流位于连接左侧
  • 期望: 在30秒的时间限制之后,对于不匹配的行,我应该在连接的右侧看到null

    发生了什么事

    • 我只看到ID之间匹配的行,而不是不匹配的行
    代码-在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
    
    输出的解释。 employeeStreamDS流,departmentId字段值是速率值的2倍,因此是2的倍数

    departmentStreamDS stream,Id字段是速率流值的3倍,因此是3的倍数

    所以每6个都会有departmentId=Id的匹配,因为LCM(2,3)=6。 这将一直发生,直到这些流之间存在30秒的差异(连接时间限制)

    我希望在30秒后,dept流值(3,9,15..)的值为空,依此类推

    我希望我解释得足够好


    因此,结果是关于spark流的左外连接行为的问题。

    根据我的理解,实际上根据,您需要在两个流的事件时间列上应用水印,例如:

    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"
     )
    
    val-impressionsWithWatermark=impressions.withWatermark(“印象时间”,“2小时”)
    val clicksWithWatermark=单击。带有水印(“单击时间”,“3小时”)
    ...
    ImpressionWithWatermark.join(
    单击Swithwatermark,
    表达式(“”)
    单击ADID=impressionAdId,然后单击
    单击时间>=印象时间和
    
    clickTime根据我的理解,实际上根据,您需要在两个流的事件时间列上应用水印,例如:

    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"
     )
    
    val-impressionsWithWatermark=impressions.withWatermark(“印象时间”,“2小时”)
    val clicksWithWatermark=单击。带有水印(“单击时间”,“3小时”)
    ...
    ImpressionWithWatermark.join(
    单击Swithwatermark,
    表达式(“”)
    单击ADID=impressionAdId,然后单击
    单击时间>=印象时间和
    
    clickTime感谢您指出这一点。我刚刚为其他流启用了水印,一切正常。我被来自同一链接的文档弄糊涂了,该链接说,水印对于连接的左侧是可选的“根据条件支持,必须在右侧指定水印+时间限制以获得正确的结果,也可以在左侧指定水印以进行所有状态清理。”“感谢您指出这一点。我刚刚为其他流启用了水印,一切正常。我被来自同一链接的文档弄糊涂了,该链接说,水印对于连接的左侧是可选的有条件支持,必须在右侧指定水印+时间约束才能获得正确的结果,也可以在左侧指定水印以进行所有状态清理