在Azure Databricks结构化流(scala笔记本,已连接到Azure IoT中心)中,我正在与Azure IoT中心的事件中心兼容的终结点上打开流。然后,我基于结构化架构解析传入的流,并在同一流上创建3个查询(groupBy)。
在大多数情况下(似乎并不总是这样),我在分区上的某个时期值附近的一个显示查询中遇到了异常。 (见下文)
我正在使用一个专用的消费群体,而其他应用程序都无法在该消费群体上进行阅读。那么,我想应该可以支持打开1个流并对其进行多个流查询吗?
有什么建议,解释或想法可以解决吗? (我希望避免创建3个消费者组并再次定义流3次)
异常示例:
org.apache.spark.SparkException:由于阶段失败,作业被中止: 1064.0阶段中的任务3失败4次,最近一次失败:丢失的任务 在阶段1064.0中的3.3(TID 24790、10.139.64.10,执行程序7):java.util.concurrent.CompletionException: com.microsoft.azure.eventhubs.ReceiverDisconnectedException:新增 创建具有较高时期“ 0”的接收器,因此当前接收器 时代'0'断开连接。如果您正在重新创建 接收器,请确保使用更高的纪元。 TrackingId:xxxx, SystemTracker:iothub-name | databricks-db, 时间戳记:2019-02-18T15:25:19,errorContext [NS:yyy,PATH: savanh-traffic-camera2 / ConsumerGroups / databricks-db / Partitions / 3, REFERENCE_ID:a0e445_7319_G2_1550503505013,PREFETCH_COUNT:500, LINK_CREDIT:500,PREFETCH_Q_LEN:0]
这是我的代码:(清理)
// Define schema and create incoming camera eventstream
val cameraEventSchema = new StructType()
.add("TrajectId", StringType)
.add("EventTime", StringType)
.add("Country", StringType)
.add("Make", StringType)
val iotHubParameters =
EventHubsConf(cameraHubConnectionString)
.setConsumerGroup("databricks-db")
.setStartingPosition(EventPosition.fromEndOfStream)
val incomingStream = spark.readStream.format("eventhubs").options(iotHubParameters.toMap).load()
// Define parsing query selecting the required properties from the incoming telemetry data
val cameraMessages =
incomingStream
.withColumn("Offset", $"offset".cast(LongType))
.withColumn("Time (readable)", $"enqueuedTime".cast(TimestampType))
.withColumn("Timestamp", $"enqueuedTime".cast(LongType))
.withColumn("Body", $"body".cast(StringType))
// Select the event hub fields so we can work with them
.select("Offset", "Time (readable)", "Timestamp", "Body")
// Parse the "Body" column as a JSON Schema which we defined above
.select(from_json($"Body", cameraEventSchema) as "cameraevents")
// Now select the values from our JSON Structure and cast them manually to avoid problems
.select(
$"cameraevents.TrajectId".cast("string").alias("TrajectId"),
$"cameraevents.EventTime".cast("timestamp").alias("EventTime"),
$"cameraevents.Country".cast("string").alias("Country"),
$"cameraevents.Make".cast("string").alias("Make")
)
.withWatermark("EventTime", "10 seconds")
val groupedDataFrame =
cameraMessages
.groupBy(window($"EventTime", "5 seconds") as 'window)
.agg(count("*") as 'count)
.select($"window".getField("start") as 'window, $"count")
display(groupedDataFrame)
val makeDataFrame =
cameraMessages
.groupBy("Make")
.agg(count("*") as 'count)
.sort($"count".desc)
display(makeDataFrame)
val countryDataFrame =
cameraMessages
.groupBy("Country")
.agg(count("*") as 'count)
.sort($"count".desc)
display(countryDataFrame)
答案 0 :(得分:1)
您可以将流数据存储到表或文件位置,然后可以在该表或文件上运行多个查询,所有查询均实时运行。 对于文件,需要在将数据提取到数据帧中时指定架构,因此将流数据写入表中是一种很好的做法。
cameraMessages.writeStream
.format("delta")
.outputMode("append")
.option("checkpointLocation","/data/events/_checkpoints/data_file")
.table("events")
现在,您可以在“事件”表上执行查询。 对于数据框-
cameraMessages = spark.readStream.table("events")
在使用EventHub时我遇到了同样的问题,上面的技巧对我来说是有效的。
使用文件而不是表
//Write/Append streaming data to file
cameraMessages.writeStream
.format("parquet")
.outputMode("append")
.option("checkpointLocation", "/FileStore/StreamCheckPoint.parquet")
.option("path","/FileStore/StreamData")
.start()
//Read data from the file, we need to specify the schema for it
val Schema = (
new StructType()
.add(StructField("TrajectId", StringType))
.add(StructField("EventTime", TimestampType))
.add(StructField("Country", StringType))
.add(StructField("Make", StringType))
)
val cameraMessages = (
sqlContext.readStream
.option("maxEventsPerTrigger", 1)
.schema(Schema)
.parquet("/FileStore/StreamData")
)