使用Azure EventHubs Capture生成的Azure Data Lake Gen1从Databricks读取Avro数据失败

时间:2019-12-01 15:39:14

标签: azure pyspark azure-eventhub azure-databricks azure-eventhub-capture

我正在尝试从Azure Data Lake Gen1读取avro数据,该数据是从Azure EventHubs生成的,并在pyspark中启用了Azure Databricks中的Azure Event Hubs Capture:

inputdata = "evenhubscapturepath/*/*"
rawData = spark.read.format("avro").load(inputdata)

以下语句失败

rawData.count()

使用

org.apache.spark.SparkException: Job aborted due to stage failure: Task 162 in stage 48.0 failed 4 times, most recent failure: Lost task 162.3 in stage 48.0 (TID 2807, 10.3.2.4, executor 1): java.io.IOException: Not an Avro data file

EventHub-Capture是否正在写入非Avro数据?有没有使用Spark读取EventHub捕获的数据的最佳实践?

2 个答案:

答案 0 :(得分:2)

实现冷摄入路径的一种模式是使用Event Hubs Capture。 EventHubs捕获按照windowing parameters的定义为每个分区写入一个文件。数据以avro格式写入,可以使用Apache Spark进行分析。

那么使用此功能的最佳实践是什么?

1。不要过度分区

我经常看到人们使用默认配置,该配置最终通常会导致许多小文件。如果您想使用Spark使用通过EventHubs Capture摄取的数据,请记住使用Spark的file sizes in Azure Data Lake Storepartitions的最佳做法。文件大小应为256 MB,分区应在10到50 GB之间。因此,最终的配置取决于您使用的消息的数量和大小。在大多数情况下,只按每个摄取日期对数据进行分区就可以了。

2。选中“不发出空文件选项”

您应选中“不发出空文件”选项。如果要使用Spark消耗数据,这可以节省不必要的文件操作。

3。在文件路径中使用数据来源

使用流传输架构,您的EventHub就是面向批处理架构方法中的着陆区。因此,您将在原始数据层中摄取数据。优良作法是在目录路径中使用数据源而不是EventHub的名称。因此,例如,如果您要从工厂中的机器人中获取遥测数据,则该目录路径可能为 / raw / robots /

存储命名要求使用所有属性,例如{Namesapce},{PartitionId}。因此,最终,一个良好的捕获文件格式定义应具有明确定义的路径,每日分区以及使用Azure Data Lake Gen 2中文件名的其余属性,如下所示:

 /raw/robots/ingest_date={Year}-{Month}-{Day}/{Hour}{Minute}{Second}-{Namespace}-{EventHub}-{PartitionId}

enter image description here

4。想想压实工作

在您的用例中,捕获的数据不会被压缩,并且最终可能会变成小的文件(因为最小写入频率为15分钟)。因此,如有必要,可以编写每天运行一次的压缩作业。像

df.repartition(5).write.format("avro").save(targetpath)

将完成这项工作。

那么,读取捕获的数据的最佳实践是什么?

5。忽略读取数据的非avro文件

Azure EventHubs Capture将临时数据写入Azure Data Lake Gen1。最佳做法是仅读取具有Avro扩展名的数据。您可以通过spark配置轻松实现这一点:

spark.conf.set("avro.mapred.ignore.inputs.without.extension", "true")

6。只读相关分区

请考虑仅读取相关的分区,例如e。 G。过滤当前的摄取日期。

7。使用共享的元数据

读取捕获的数据的工作原理类似于直接从Azure EventHubs读取数据。 因此,您必须有一个架构。假设您还有工作可以使用Spark结构化流直接读取数据,那么一个好的模式就是存储元数据并共享它。您可以只将此元数据存储在Data Lake Store json文件中:

[{"MeasurementTS":"timestamp","Location":"string", "Temperature":"double"}]

并与此simple parsing function一起阅读:

# parse the metadata to get the schema
from collections import OrderedDict 
from pyspark.sql.types import *
import json

ds = dbutils.fs.head (metadata)                                                 # read metadata file

items = (json
  .JSONDecoder(object_pairs_hook=OrderedDict)
  .decode(ds)[0].items())

#Schema mapping 
mapping = {"string": StringType, "integer": IntegerType, "double" : DoubleType, "timestamp" : TimestampType, "boolean" : BooleanType}

schema = StructType([
    StructField(k, mapping.get(v.lower())(), True) for (k, v) in items])

因此您可以重复使用架构:

from pyspark.sql.functions import *

parsedData = spark.read.format("avro").load(rawpath). \
  selectExpr("EnqueuedTimeUtc", "cast(Body as string) as json") \
 .select("EnqueuedTimeUtc", from_json("json", schema=Schema).alias("data")) \
 .select("EnqueuedTimeUtc", "data.*")

答案 1 :(得分:1)

确保输入数据是“ .avro ”文件。

由于spark-avro模块是外部模块,因此DataFrameReader或DataFrameWriter中没有.avro API。

要以Avro格式加载/保存数据,您需要将数据源选项格式指定为avro(或org.apache.spark.sql.avro)。

示例:

Python
df = spark.read.format("avro").load("examples/src/main/resources/users.avro")

OR

#storage->avro
avroDf = spark.read.format("com.databricks.spark.avro").load(in_path)

有关更多详细信息,请参见以下链接:

https://spark.apache.org/docs/latest/sql-data-sources-avro.html

http://blog.itaysk.com/2017/01/14/processing-event-hub-capture-files-using-spark

https://medium.com/@caiomsouza/processing-event-hubs-capture-files-avro-format-using-spark-azure-databricks-save-to-parquet-95259001d85f

希望这会有所帮助。