了解適用於 U-SQL 開發人員的 Apache Spark 程式碼
重要
Azure Data Lake Analytics 於 2024 年 2 月 29 日淘汰。 透過此公告深入了解。
針對數據分析,您的組織可以使用 Azure Synapse Analytics 或 Microsoft Fabric。
本節提供將 U-SQL 指令碼轉換為 Apache Spark 的高階指南。
了解 U-SQL 和 Spark 語言和處理範例
在將 Azure Data Lake Analytics 的 U-SQL 指令碼移轉至 Spark 之前,建議先理解這兩個系統的一般語言和處理原理。
U-SQL 是類似 SQL 的宣告式查詢語言,使用資料流程範例,可讓您輕鬆地內嵌和擴增以 .NET (例如 C#) 、Python 和 R 撰寫的使用者程式碼。使用者延伸模組可以實作簡單的運算式或使用者定義函數,還可以讓使用者實作所謂的使用者定義運算子,從而實作自訂運算子以執行資料列集層級轉換、擷取和寫入輸出。
Spark 是一種擴增架構,提供 Scala、JAVA、Python、.NET 等數種語言繫結,您主要會以其中一種語言撰寫程式碼、建立稱為可復原分散式資料集 (RDD) 的資料抽象概念、資料框架和資料集,然後使用類似 LINQ 的特定領域語言 (DSL) 進行轉換。 此架構也在資料框架和資料集抽象概念上提供 SparkSQL 作為宣告式子語言。 DSL 提供兩種作業類別:轉換和動作。 將轉換套用至資料抽象概念不會執行轉換,而是改為建置執行計畫,並透過動作提交計畫進行評估 (例如,將結果寫入暫存資料表或檔案,或列印結果)。
因此,將 U-SQL 指令碼轉譯為 Spark 程式時,您必須決定要使用哪一種語言,此語言至少會用於產生資料框架抽象 (這是目前最常使用的資料抽象概念),以及您是否要使用 DSL 或 SparkSQL 撰寫宣告式資料流程轉換。 在某些更複雜的情況下,您可能需要將 U-SQL 指令碼分割成一連串的 Spark,並使用 Azure Batch 或 Azure Functions 實作其他步驟。
此外,Azure Data Lake Analytics 會在無伺服器作業服務環境中提供 U-SQL,該環境的資源會配置給每個作業,而 Azure Synapse Spark、Azure Databricks 和 Azure HDInsight 會以叢集服務的形式或是所謂的 Spark 集區範本來提供 Spark。 轉換應用程式時,您必須考慮現在建立、調整大小、調整和解除委任叢集或集區的影響。
轉換 U-SQL 指令碼
U-SQL 指令碼遵循下列處理模式:
- 資料讀取來源包括非結構化檔案、使用
EXTRACT
陳述式、位置或檔案集規格,以及內建或使用者定義的擷取器和所需的架構,或從 U-SQL 資料表 (Managed 或外部資料表)。 將以資料列集表示。 - 資料列集會在多個 U-SQL 陳述式中轉換,這些陳述式會將 U-SQL 運算式套用至資料列集,並產生新的資料列集。
- 最後,產生的資料列集會使用
OUTPUT
陳述式將輸出至其中一個檔案,該陳述式會指定位置以及內建或使用者定義的輸出器,或輸出至 U-SQL 資料表。
指令碼會延遲評估,這表示每個擷取和轉換步驟都會組成運算式樹狀結構,並全域評估資料流程。
Spark 程式類似於使用 Spark 連接器來讀取資料並建立資料框架,然後使用類似 LINQ 的 DSL 或 SparkSQL 在資料框架上套用轉換,接著將結果寫入檔案、暫存 Spark 資料表、一些程式設計語言類型,或是主控台。
轉換 .NET 程式碼
U-SQL 的運算式語言是 C#,提供各種方式來擴充自訂 .NET 程式碼與使用者定義函數、使用者定義運算子和使用者定義彙總工具。
Azure Synapse 和 Azure HDInsight Spark 現在都原生支援透過適用於 Apache Spark 的 .NET 執行 .NET 程式碼。 這表示您可以透過 Spark 重複使用部分或所有 .NET 使用者定義函式。 請注意,U-SQL 會使用 .NET Framework,而適用於 Apache Spark 的 .NET 則以 .NET Core 3.1 或更新版本為基礎。
U-SQL 使用者定義運算子 (UDO) 會使用 U-SQL UDO 模型來提供運算子程式碼的擴增執行。 因此,UDO 必須重寫為使用者定義的函式,以符合 Spark 執行模型。
適用於 Apache Spark 的 .NET 目前不支援使用者定義的彙總工具。 因此,U-SQL 使用者定義彙總工具必須轉譯成以 Scala 撰寫的 Spark 使用者定義彙總工具。
如果您不想利用適用於 Apache Spark 的 .NET 功能,則必須將運算式重寫為相等的 Spark、Scala、JAVA 或 Python 運算式、函式、彙總工具或連接器。
在任何情況下,如果您的 U-SQL 指令碼中有大量的 .NET 邏輯,請透過您的 Microsoft 帳戶代表與我們連絡,以取得進一步指引。
下列詳細資料是 U-SQL 指令碼中 .NET 和 C# 使用方式的不同案例。
轉換純量內嵌 U-SQL C# 運算式
U-SQL 的運算式語言為 C#。 許多純量內嵌 U-SQL 運算式都是以原生方式實作,藉此改善效能,而更複雜的運算式則可透過呼叫 .NET Framework 來執行。
Spark 有自己的純量運算式語言 (包含在 DSL 或 SparkSQL 中),並允許呼叫至針對 JVM、.NET 或 Python 執行階段撰寫的使用者定義函式。
如果您有 U-SQL 的純量運算式,則應該先找出最適合原生理解的 Spark 純量運算式,以便獲得最大效能,然後將其他運算式對應至所選 Spark 執行階段語言的使用者定義函式。
請注意,.NET 和 C# 的語意類型不同於 JVM 和 Python 執行階段和 Spark 的 DSL。 如需類型系統差異的詳細資訊,請參閱下方說明。
轉換使用者定義的純量 .NET 函式和使用者定義的彙總工具
U-SQL 提供呼叫任意純量 .NET 函數的方法,以及呼叫以 .NET 撰寫的使用者定義彙總工具。
Spark 也支援以大部分主控語言撰寫的使用者定義函式和使用者定義彙總工具,這些語言可從 Spark 的 DSL 和 SparkSQL 呼叫。
如上所述,適用於 Apache Spark 的 .NET 支援以 .NET 撰寫的使用者定義函數,但不支援使用者定義的彙總工具。 因此,針對使用者定義的函式,可以使用適用於 Apache Spark 的 .NET,而使用者定義的彙總工具則必須以適用於 Spark 的 Scala 撰寫。
轉換使用者定義運算子 (UDO)
U-SQL 提供數種使用者定義運算子 (UDO) 類別,例如擷取器、輸出器、減速工具、處理器、套用器和結合器,這些運算子可使用 .NET 寫入 (且以 Python 和 R 寫入某些分區)。
Spark 不會為運算子提供相同的擴充性模型,但對某些運算子提供相等的功能。
相當於擷取器和輸出器的 Spark 功能是 Spark 連接器。 針對許多 U-SQL 擷取器,您可能會在 Spark 社群中找到相等連接器。 對於其他擷取器,您必須撰寫自訂連接器。 如果 U-SQL 擷取器很複雜,且使用數個 .NET 程式庫,建議在 Scala 中建置連接器,以使用 Interop 來呼叫負責資料實際處理的 .NET 程式庫。 在此情況下,您必須將 .NET Core 執行時間部署到 Spark 叢集,並確定參考的 .NET 程式庫符合 .NET Standard 2.0 規範。
其他類型的 U-SQL UDO 必須採用使用者定義的函數和彙總工具,以及語意適用的 Spark DLS 或 SparkSQL 運算式來重寫。 例如,處理器可以對應至各種 UDF 調用的 SELECT,封裝為函式,採用資料框架作為引數,並傳回資料框架。
轉換 U-SQL 的選用程式庫
U-SQL 提供一組選擇性和示範程式庫,用於提供 Python、R、JSON、XML、AVRO 支援,以及一些 Azure AI 服務功能。
Spark 分別提供自己的 Python 和 R 整合、pySpark 和 SparkR,並提供連接器來讀取和寫入 JSON、XML 和 AVRO。
如果您需要轉換參考 Azure AI 服務程式庫的指令碼,建議透過您的 Microsoft 帳戶代表與我們連絡。
轉換具型別值
由於 U-SQL 的型別系統是以 .NET 型別系統為基礎,而 Spark 有自己的型別系統,後者受到主機語言繫結的影響,因此您必須確定您所使用的型別很接近,而且針對特定型別,型別範圍、有效位數和/或小數位數可能稍有不同。 此外,U-SQL 和 Spark 處理 null
值的方式不同。
資料類型
下表針對指定的 U-SQL 類型提供 Spark、Scala 和 PySpark 中的相等類型。
U-SQL | Spark | Scala | PySpark |
---|---|---|---|
byte |
|||
sbyte |
ByteType |
Byte |
ByteType |
int |
IntegerType |
Int |
IntegerType |
uint |
|||
long |
LongType |
Long |
LongType |
ulong |
|||
float |
FloatType |
Float |
FloatType |
double |
DoubleType |
Double |
DoubleType |
decimal |
DecimalType |
java.math.BigDecimal |
DecimalType |
short |
ShortType |
Short |
ShortType |
ushort |
|||
char |
Char |
||
string |
StringType |
String |
StringType |
DateTime |
DateType , TimestampType |
java.sql.Date , java.sql.Timestamp |
DateType , TimestampType |
bool |
BooleanType |
Boolean |
BooleanType |
Guid |
|||
byte[] |
BinaryType |
Array[Byte] |
BinaryType |
SQL.MAP<K,V> |
MapType(keyType, valueType, valueContainsNull) |
scala.collection.Map |
MapType(keyType, valueType, valueContainsNull=True) |
SQL.ARRAY<T> |
ArrayType(elementType, containsNull) |
scala.collection.Seq |
ArrayType(elementType, containsNull=True) |
如需詳細資訊,請參閱
NULL 的處理方式
在 Spark 中,預設型別會允許 Null 值,而在 U-SQL 中,您需要將純量、非物件明確地標示成可為 Null。 雖然 Spark 可讓您將資料行定義為不可為 Null,但不會強制執行條件約束,而且可能會導致錯誤的結果。
在 Spark 中,NULL 表示值是未知的。 Spark Null 值不與任何值相等,包括本身。 由於每個 Spark NULL 的值都是未知,因此兩個 Null 值之間、或是一個 NULL 與其他任何值之間的比較都會傳回未知。
此行為與 U-SQL 不同,U-SQL 遵循 C# 語意,因此 null
與任何值不相同,但與本身相等。
因此,使用 WHERE column_name = NULL
的 SparkSQL SELECT
陳述式會傳回零個資料列,即使 column_name
中有 Null 值也一樣,而在 U-SQL 中,該陳述式會傳回 column_name
設定為 null
的資料列。 與此類似,使用 WHERE column_name != NULL
的 Spark SELECT
陳述式會傳回零個資料列,即使 column_name
中有非 null 值也一樣,而在 U-SQL 中,該陳述式會傳回具有非 null 的資料列。 因此,如果您需要 U-SQL 非 null 檢查語意,應該分別使用 isull 和 isotnull (或其 DSL 相等項目)。
轉換 U-SQL 目錄物件
其中一個主要差異在於 U-SQL 指令碼可以使用其目錄物件,其中許多物件沒有直接的 Spark 相等項目。
Spark 可支援 Hive 中繼存放區概念,主要包括資料庫、資料表和檢視表,因此您可以將 U-SQL 資料庫和架構對應至 Hive 資料庫,並將 U-SQL 資料表對應至 Spark 資料表 (請參閱移動儲存在 U-SQL 資料表中的資料),但不支援資料表值函式 (TVF)、預存程序、U-SQL 組件、外部資料來源等。
U-SQL 程式碼物件,例如檢視、TVF、預存程序和組件可以透過 Spark 中的程式碼函式和程式庫進行模型化,並使用主機語言的函式和程序性抽象機制進行參考 (例如,透過匯入 Python 模組或參考 Scala 函式)。
如果 U-SQL 目錄已用來共用跨專案和小組的資料和程式碼物件,則必須使用共用的相等機制 (例如,用於共用程式碼物件的 Maven)。
轉換 U-SQL 資料列集運算式和 SQL 型純量運算式
U-SQL 的核心語言是轉換資料列集,並以 SQL 為基礎。 以下是 U-SQL 所提供最常見資料列集運算式的非詳盡清單:
SELECT
/FROM
/WHERE
/GROUP BY
+Aggregates+HAVING
/ORDER BY
+FETCH
INNER
/OUTER
/CROSS
/SEMI
JOIN
表達式CROSS
/OUTER
APPLY
表達式PIVOT
/UNPIVOT
運算式VALUES
資料列集建構函式設定運算式
UNION
/OUTER UNION
/INTERSECT
/EXCEPT
此外,U-SQL 提供各種 SQL 型純量運算式,例如
OVER
時間範圍運算式- 各種內建彙總工具和次序函數 (
SUM
、FIRST
等) - 一些最常見的 SQL 純量運算式:
CASE
、LIKE
、(NOT
)IN
、AND
、OR
等等。
針對上述大部分的運算式,Spark 都可以其 DSL 和 SparkSQL 的形式提供相等的運算式。 針對 Spark 中原生不支援的部分運算式,必須搭配使用原生 Spark 運算式和語意相等的模式來重寫。 例如,OUTER UNION
必須轉譯成投影和聯合的相等組合。
由於 Null 值的處理方式不同,如果比較兩個包含 Null 值的資料行,則 U-SQL 聯結會將皆包含 NULL 值的資料列視為相符,而針對 Spark 中的聯結,除非加入明確的 Null 檢查,否則不會將這類資料行視為相符。
轉換其他 U-SQL 概念
U-SQL 也提供各種其他功能和概念,例如針對 SQL Server 資料庫、參數、純量和 Lambda 運算式變數、系統變數、OPTION
提示的同盟查詢。
針對 SQL Server 資料庫/外部資料表的同盟查詢
U-SQL 會提供資料來源和外部資料表,以及針對 Azure SQL Database 的直接查詢。 雖然 Spark 未提供相同的物件抽象概念,但會提供適用於 Azure SQL Database 的 Spark 連接器,可用來查詢 SQL 資料庫。
U-SQL 參數和變數
參數和使用者變數在 Spark 及其主控語言中具有相等的概念。
例如在 Scala 中,您可以使用 var
關鍵字來定義變數:
var x = 2 * 3;
println(x)
U-SQL 的系統變數 (開頭 @@
的變數) 可以分成兩個類別:
- 可設定系統變數,可設定為特定值以影響指令碼行為
- 資訊系統變數,用於查詢系統和作業層級資訊
大部分可設定系統變數在 Spark 中沒有直接的對等項目。 某些資訊系統變數可藉由在作業執行期間傳遞資訊作為引數來建立模型,其他變數在 Spark 主控語言中可能具有對等函式。
U-SQL 提示
U-SQL 提供數種語法可將提示提供給查詢最佳化工具和執行引擎:
- 設定 U-SQL 系統變數
- 與資料列集運算式相關聯的
OPTION
子句,提供資料或計畫提示 - 聯結運算式語法中的聯結提示 (例如:
BROADCASTLEFT
)
Spark 成本型查詢最佳化工具的內建功能可提供提示並微調查詢效能。 請參閱對應的文件。