簡體   English   中英

從 Azure EventHubs Capture 生成的 Azure Data Lake Gen1 使用 Databricks 讀取 avro 數據失敗

[英]Reading avro data with Databricks from Azure Data Lake Gen1 generated by Azure EventHubs Capture fails

我正在嘗試從 Azure Data Lake Gen1 讀取 avro 數據,這些數據是從 Azure EventHubs 生成的,在 Azure Databricks 中使用 pyspark 啟用了 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 捕獲的數據是否有任何最佳實踐?

實現冷攝取路徑的一種模式是使用Event Hubs Capture EventHubs 捕獲為每個分區寫入一個文件,如windowing parameters所定義。 數據以 avro 格式編寫,可以使用 Apache Spark 進行分析。

那么使用此功能的最佳實踐是什么?

1.不要過度分區

我經常看到人們使用默認配置,最終通常會產生許多小文件。 如果您想要使用通過 EventHubs Capture with Spark 引入的數據,請牢記Azure Data Lake Store 中文件大小和 Spark 分區的最佳做法。 文件大小應為 ~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-extension 的數據。 您可以通過 spark 配置輕松實現此目的:

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

6.只讀相關分區

考慮只讀取相關分區,例如過濾當前攝取日。

7.使用共享元數據

讀取捕獲的數據的工作方式類似於直接從 Azure EventHubs 讀取數據。 所以你必須有一個模式。 假設您還有作業直接使用 Spark Structured Streaming 讀取數據,一個好的模式是存儲元數據並共享它。 您可以將此元數據存儲在 Data Lake Store json 文件中:

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

並使用這個簡單的解析函數讀取它:

# 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.*")

確保輸入數據是“ .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")

要么

#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

希望這可以幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM