我正在尝试从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捕获的数据的最佳实践?
答案 0 :(得分:2)
实现冷摄入路径的一种模式是使用Event Hubs Capture。 EventHubs捕获按照windowing parameters的定义为每个分区写入一个文件。数据以avro格式写入,可以使用Apache Spark进行分析。
那么使用此功能的最佳实践是什么?
1。不要过度分区
我经常看到人们使用默认配置,该配置最终通常会导致许多小文件。如果您想使用Spark使用通过EventHubs Capture摄取的数据,请记住使用Spark的file sizes in Azure Data Lake Store和partitions的最佳做法。文件大小应为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}
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
希望这会有所帮助。