了解適用於 U-SQL 開發人員的 Apache Spark 程式碼

重要

Azure Data Lake Analytics 於 2024 年 2 月 29 日淘汰。 使用此公告深入瞭解。

針對數據分析,您的組織可以使用 Azure Synapse AnalyticsMicrosoft 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 指令碼遵循下列處理模式:

  1. 資料讀取來源包括非結構化檔案、使用 EXTRACT 陳述式、位置或檔案集規格,以及內建或使用者定義的擷取器和所需的架構,或從 U-SQL 資料表 (Managed 或外部資料表)。 它以數據列集表示。
  2. 資料列集會在多個 U-SQL 陳述式中轉換,這些陳述式會將 U-SQL 運算式套用至資料列集,並產生新的資料列集。
  3. 最後,產生的資料列集會使用 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 使用者定義彙總工具。

如果您不想利用 .NET for Apache Spark 功能,則必須將表達式重寫為對等的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 呼叫。

如上所述,.NET for Apache Spark 支援以 .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 提供一組選擇性和示範連結庫,提供 PythonRJSON、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 檢查語意,應該分別使用 isullisotnull (或其 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/SEMIJOIN 運算式

  • CROSS/OUTERAPPLY 運算式

  • PIVOT/UNPIVOT 運算式

  • VALUES 資料列集建構函式

  • 設定運算式 UNION/OUTER UNION/INTERSECT/EXCEPT

此外,U-SQL 提供各種 SQL 型純量表達式,例如

  • OVER 時間範圍運算式
  • 各種內建匯總工具與排名函式 (SUMFIRST )
  • 一些最常見的 SQL 純量運算式:CASELIKE、(NOT) INANDOR 等等。

針對上述大部分的運算式,Spark 都可以其 DSL 和 SparkSQL 的形式提供相等的運算式。 針對 Spark 中原生不支援的部分運算式,必須搭配使用原生 Spark 運算式和語意相等的模式來重寫。 例如,OUTER UNION 必須轉譯成投影和聯合的相等組合。

由於 NULL 值的不同處理,如果比較的兩個數據行都包含 NULL 值,則 U-SQL 聯結一律會比對一個數據列,而 Spark 中的聯結則不會符合這類數據行,除非加入明確的 Null 檢查。

轉換其他 U-SQL 概念

U-SQL 也提供各種其他功能和概念,例如針對 SQL Server 資料庫、參數、純量和 Lambda 運算式變數、系統變數OPTION、提示的同盟查詢。

針對 SQL Server 資料庫/外部資料表的同盟查詢

U-SQL 會提供資料來源和外部資料表,以及針對 Azure SQL Database 的直接查詢。 雖然 Spark 未提供相同的物件抽象概念,但它會針對可用來查詢 SQL 資料庫的 Azure SQL Database 提供 Spark 連接器

U-SQL 參數和變數

參數和使用者變數在 Spark 及其主控語言中具有相等的概念。

例如在 Scala 中,您可以使用 var 關鍵字來定義變數:

var x = 2 * 3;
println(x)

U-SQL 的系統變數 (開頭 @@ 的變數) 可以分成兩個類別:

  • 可設定系統變數,可設定為特定值以影響指令碼行為
  • 資訊系統變數,用於查詢系統和作業層級資訊

大部分可設定系統變數在 Spark 中沒有直接的對等項目。 某些資訊系統變數可藉由在作業執行期間傳遞資訊作為引數來建立模型,其他變數在 Spark 主控語言中可能具有對等函式。

U-SQL 提示

U-SQL 提供數種語法可將提示提供給查詢最佳化工具和執行引擎:

  • 設定 U-SQL 系統變數
  • 與資料列集運算式相關聯的 OPTION 子句,提供資料或計畫提示
  • 聯結運算式語法中的聯結提示 (例如:BROADCASTLEFT)

Spark 成本型查詢最佳化工具的內建功能可提供提示並微調查詢效能。 請參閱對應的檔。

下一步