I need to join to enrich my dataframe with postgres data. In Spark Streaming I can do it normally because the data is processed in batch. However, in structured streaming I'm getting an error whenever I try to use aggregate with join.
For example: If I use aggregate with the output Mode complete, the job works normally, however, if I add the join, it returns the error:
Join between two streaming DataFrames/Datasets is not supported in Complete output mode, only in Append output mode;
The same happens if I do the opposite. When I use the join with the output mode append the job runs normally, however, if I add the aggregate, the job returns the error:
Append output mode not supported when there are streaming aggregations on streaming DataFrames/DataSets without watermark;
Finally, I would like to know if there is any way to use join and aggregate together without getting an error using spark structured streaming.
If so, what would an implementation look like that didn't generate that kind of error?
def main(args: Array[String]): Unit = {
val ss: SparkSession = Spark.getSparkSession
val postgresSQL = new PostgresConnection
val dataCollector = new DataCollector(postgresSQL)
val collector = new Collector(ss,dataCollector)
import ss.implicits._
val stream: DataFrame = Kafka.setStructuredStream(ss)
val parsed: DataFrame = Stream.parseInputMessages(stream)
val getRelation: DataFrame = collector.getLastRelation(parsed)
getRelation
.writeStream.format("console")
.trigger(Trigger.ProcessingTime(5000))
.outputMode("complete")
.queryName("Join")
.start()
ss.streams.awaitAnyTermination()
}
In my getLastRelation method I call a convertData method and a compareData method.
def getLastRelation(messageToProcess: DataFrame): DataFrame = {
// Faz tratamentos no DF para preparar a busca
val dss: Dataset[Message] = this.convertData(messageToProcess)
val dsRelacaolista: Dataset[WithStructure] = this.getPersonStructure(ds)
val compareData = this.compareData(dsRelacaolista,messageToProcess)
compareData
}
In my convertData method I use an agg.
def convertData(data: DataFrame): Dataset[Message] = {
data.selectExpr("country","code","order")
.groupBy($"country",$"order")
.agg(collect_list("code")
.as("code"))
.as[Message]
}
And in my compareData method I use join:
def compareData(data: Dataset[WithStructure], message: DataFrame): DataFrame = {
val tableJoin = message.selectExpr("order","order_id","hashCompare","created_at")
data.toDF()
.withColumn("hashCompare",hash($"country",$"code"))
.join(tableJoin,"hashCompare")
}
NOTE: I use scala as a language (I don't know if this information is important for this question)