附註:
- 此教學課程需要存取 Oracle Cloud。若要註冊免費帳戶,請參閱 Oracle Cloud Infrastructure Free Tier 入門。
- 它使用 Oracle Cloud Infrastructure 證明資料、租用戶及區間的範例值。完成實驗室時,請將這些值取代為您雲端環境特定的值。
將 Apache Impala 命令檔移轉至 Oracle Big Data Service 上的 Trino
簡介
Oracle Big Data Service (BDS) 是由 Oracle 提供的雲端服務,可讓使用者建立與管理 Hadoop 叢集、Spark 叢集、Trino 及其他大數據服務。在大數據分析的世界中,Trino 扮演高效能分散式 SQL 查詢引擎,專為在大型資料集上執行互動式分析查詢所設計。Trino 可在統一 SQL 介面內跨多個來源查詢資料,包括 Hadoop 分散式檔案系統 (HDFS)、OCI 儲存桶及傳統關聯式資料庫。它能夠以低延遲處理大規模資料,使其成為資料工程師和分析師的強大工具。
隨著移轉至現代化資料平台,許多組織都在 Oracle Big Data Service 上從 Apache Impala 移轉至 Trino。本教學課程提供自動化和手動調整 Apache Impala 命令檔的逐步方法,讓您順暢地移轉至 Trino。
目標
-
自動將 Apache Impala 命令檔轉換成 Trino 相容的 SQL。
-
反白特定案例所需的手動變更。
-
提供常見移轉挑戰的疑難排解秘訣。
必要條件
-
安裝 Trino 後即可存取 Oracle Big Data Service。
-
Apache Impala 和 Trino SQL 的基本知識。
-
具備執行命令檔和修改組態的足夠權限。
作業 1:自動化命令檔轉換
自動化指令碼旨在簡化將 Apache Impala 指令碼轉換成與 Oracle Big Data Service 上的 Trino 相容的程序。此指令碼可自動化數個關鍵轉換,減少所需的手動工作量,並將移轉過程中人為錯誤的可能性降到最低。以下是其功能的細目。
-
檔案處理與初始化。
-
命令檔會從讀取輸入
.hql
檔案 (通常用於 Apache Impala 查詢) 開始。 -
它會建立一個新的輸出檔案,其中會儲存轉換的 Trino 相容查詢。
-
命令檔會從新增一行來設定目錄和資料庫相關資訊環境開始,使用
USE catalog_name.schema_name
來確保查詢在 Trino 的正確相關資訊環境中執行。
-
-
自動化查詢轉換。
-
覆寫表格處理:命令檔會尋找 Apache Impala 命令檔中的任何
OVERWRITE TABLE
敘述句,並在它們上方插入對應的DELETE FROM
敘述句。這可確保在插入新資料前清除表格,與 Trino 處理資料覆寫的方式一致。 -
取代 Impala 特定函數:命令檔會套用數個轉換,將 Apache Impala 特定語法和函數取代為 Trino 相容的語法和函數。舉例而言:
-
由於 Trino 中不需要
invalidate metadata
和REFRESH
指令,因此會對其加註。 -
資料類型變更 (例如將
string
變更為varchar
) 以符合 Trino 的資料類型。 -
Impala 的
TRUNCATE TABLE
敘述句被DELETE FROM
取代,因為 Trino 處理的截斷方式不同。 -
COMPUTE STATS
會由ANALYZE
取代,以反映 Trino 如何收集統計資料。 -
其他特定轉換包括處理
nvl
、ifnull
和from_utc_timestamp
等函數,將它們調整為 Trino 的語法和函數。 -
將
nvl2
函數轉換為等效的COALESCE
表示式。 -
修改正規表示式比對 (
REGEXP
) 至 Trino 的REGEXP_LIKE
。 -
調整日期與時間戳記函數以符合 Trino 的語法。
-
Script:
#!/bin/bash # Function to apply transformations to an HQL file process_file() { local input_file="$1" local output_file="${input_file%.hql}_modified.hql" local diff_file="${input_file%.hql}_diff.sql" # Create the output file with the initial modification { echo "use catalog_name.schema_name;" cat "$input_file" } > "$output_file" # Insert DELETE FROM statements above OVERWRITE TABLE statements awk ' BEGIN { IGNORECASE = 1 } { if (match($0, /OVERWRITE[[:space:]]+TABLE[[:space:]]+([^[:space:]]+)/, arr)) { print "DELETE FROM " arr[1] ";" } else if (match($0, /OVERWRITE[[:space:]]+([^[:space:]]+)/, arr)) { print "DELETE FROM " arr[1] ";" } print }' "$output_file" > temp_file && mv temp_file "$output_file" # Define replacements as array of tuples (search, replace) declare -a replacements=( "old_line1 new_line1" "old_line2 new_line2" # Add more replacements as needed ) # Apply replacements for replacement in "${replacements[@]}"; do search_text=$(echo "$replacement" | awk '{print $1}') replace_text=$(echo "$replacement" | awk '{print $2}') sed -i "s/${search_text}/${replace_text}/Ig" "$output_file" done # Handle specific replacements sed -i 's/invalidate metadata/--invalidate metadata/Ig' "$output_file" sed -i 's/REFRESH/--REFRESH/Ig' "$output_file" sed -i 's/ string/ varchar/Ig' "$output_file" sed -i 's/TRUNCATE[[:space:]]\+TABLE[[:space:]]*/DELETE FROM /Ig' "$output_file" sed -i 's/TRUNCATE /DELETE FROM /Ig' "$output_file" sed -i 's/OVERWRITE[[:space:]]\+TABLE[[:space:]]*/INTO /Ig' "$output_file" sed -i 's/COMPUTE[[:space:]]\+stats/ANALYZE/Ig' "$output_file" sed -i 's/INSERT[[:space:]]\+INTO[[:space:]]\+TABLE/INSERT INTO/Ig' "$output_file" sed -i 's/from_utc_timestamp(now(),/current_timestamp AT TIME ZONE /Ig' "$output_file" sed -i "s/'America\/New_York')/'America\/New_York'/Ig" "$output_file" sed -i 's|/\* +NOSHUFFLE \*/| |Ig' "$output_file" sed -i 's/into[[:space:]]\+table/into/Ig' "$output_file" sed -i 's/STRAIGHT_JOIN/ /Ig' "$output_file" sed -i 's/OVERWRITE[[:space:]]\+/INTO /Ig' "$output_file" sed -i 's/TABLE[[:space:]]\+INTO/INTO/Ig' "$output_file" sed -i 's/SET[[:space:]]\+DECIMAL_V2/--SET DECIMAL_V2/Ig' "$output_file" sed -i 's/nvl(/COALESCE(/Ig' "$output_file" sed -i 's/ifnull(/COALESCE(/Ig' "$output_file" sed -i 's/CREATE[[:space:]]\+EXTERNAL/CREATE/Ig' "$output_file" sed -i -E 's/TRUNC[[:space:]]*\(/TRUNCATE(/Ig' "$output_file" sed -i -E 's/CAST[[:space:]]*\(/TRY_CAST(/Ig' "$output_file" sed -i -E 's/instr[[:space:]]*\(/strpos(/Ig' "$output_file" sed -i 's/""[[:space:]]\+as/null as/Ig' "$output_file" sed -i -E 's/\$\{var\:([^}]*)\}/\$\{\1\}/Ig' "$output_file" sed -i -E 's/([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]+REGEXP[[:space:]]+('\''[^'\'']*'\'')/REGEXP_LIKE(\1, \2)/Ig' "$output_file" sed -i -E 's/lower\(([a-zA-Z_][a-zA-Z0-9_]*\))[[:space:]]+REGEXP[[:space:]]+('\''[^'\'']*'\'')/REGEXP_LIKE(lower(\1, \2)/Ig' "$output_file" sed -i "s/)\s*STORED\s*AS\s*PARQUET\s*LOCATION\s*'\([^']*\)';/) WITH (\nexternal_location = '\1',\nformat = 'PARQUET'\n);/Ig" "$output_file" sed -i -E "s/try_cast\(extract\(([a-zA-Z0-9_.]+), 'MONTH'\) AS varchar\)/try_cast(extract(MONTH from try_cast(\1 AS timestamp)) as VARCHAR)/Ig" "$output_file" sed -i -E "s/TRY_CAST\(extract\(add_months\(([^,]+),([^,]+)\),[[:space:]]*'MONTH'\)[[:space:]]*AS[[:space:]]*varchar\)/TRY_CAST\(extract\(MONTH from date_add\('month',\2,try_cast\(\1 as timestamp\)\)\) AS varchar\)/Ig" "$output_file" sed -Ei "s/try_cast\(ADD_MONTHS\(([^,]+),\s*-?\s*([0-9]+)\) AS varchar\)/try_cast\(date_add\('month', -\2, try_cast(\1 as timestamp)\) AS varchar\)/Ig" "$output_file" sed -i -E 's/DATEDIFF\(/date_diff\('\''day'\'', /Ig' "$output_file" sed -i -E 's/TO_DATE\(/DATE\(/Ig' "$output_file" sed -i -E 's/now\(\)/current_timestamp/Ig' "$output_file" # Generate the diff file diff -u "$input_file" "$output_file" > "$diff_file" echo "Processed $input_file -> $output_file. Diff file created: $diff_file" } # Check arguments if [ "$#" -ne 1 ]; then echo "Usage: $0 <file_or_directory>" exit 1 fi TARGET="$1" # Check if the target is a directory if [ -d "$TARGET" ]; then for file in "$TARGET"/*.hql; do [ -e "$file" ] || continue # Skip if no HQL files found process_file "$file" done elif [ -f "$TARGET" ]; then process_file "$TARGET" else echo "Invalid input: $TARGET is neither a file nor a directory." exit 1 fi
注意:此命令檔提供將 Apache Impala 命令檔轉換成 Trino 的基礎方法,但並不涵蓋所有可能的 Impala 敘述句和案例。如果您遇到此程序檔未處理的其他 Impala 特定語法或函數,則可以新增轉換規則以涵蓋這些案例來延伸程序檔。使用這些修改定期更新指令碼,以提升其日後轉換的效益
-
工作 2:執行轉換命令檔
-
將命令檔儲存至 Oracle Big Data Service 邊緣節點。
-
以包含 Apache Impala 命令檔的目標檔案或目錄執行命令檔。
-
複查產生的輸出與差異檔案以進行變更。
任務 3:進行手動調整
-
使用
LEFT ANTI JOIN
敘述句。某些 Apache Impala SQL 建構 (例如
LEFT ANTI JOIN
) 需要手動介入。識別 Impala 命令檔中的LEFT ANTI JOIN
敘述句,並使用LEFT JOIN
以WHERE
子句取代為同等的 Trino SQL。命令檔範例:
-
Impala 命令檔:
SELECT t1.* FROM table1 t1 LEFT ANTI JOIN table2 t2 ON t1.key = t2.key;
-
Trino 指令碼:
SELECT t1.* FROM table1 t1 LEFT JOIN table2 t2 ON t1.key = t2.key WHERE t2.key IS NULL;
-
-
調整
GROUP BY
子句。Trino 允許在
GROUP BY
子句中以位置為基礎的群組,這可以簡化長群組。必要時,將資料欄名稱轉換成GROUP BY
子句中的等同位置。確定所有資料欄都已正確對應。命令檔範例:
-
Impala 命令檔:
GROUP BY sales_data.region, sales_data.product_name, sales_data.transaction_id, transaction_date, last_updated, inventory.stock_quantity, sales_amount, discount_status, inventory_cost, total_revenue, revenue_status, reporting_period, report_generated_date;
-
Trino 指令碼:
GROUP BY sales_data.region, sales_data.product_name, sales_data.transaction_id, transaction_date, last_updated, inventory.stock_quantity, 7, -- sales_amount 8, -- discount_status 9, -- inventory_cost 10, -- total_revenue 11, -- revenue_status 12, -- reporting_period 13; -- report_generated_date
-
疑難排解與秘訣
-
錯誤處理:如果您在轉換後發生語法錯誤,請仔細複查命令檔,特別是
JOIN
子句和日期函數。 -
測試:驗證 Trino 中查詢的輸出,以確保它們符合 Apache Impala 的預期結果。
-
如有需要,請參考 Trino 文件。
接下來的步驟
完成將 Apache Impala 命令檔移轉至 Oracle Big Data Service 上的 Trino 之後,請務必徹底驗證轉換後的命令檔。從在測試環境中執行轉換的 Trino 命令檔開始,以確保產生預期的結果。請密切注意效能差異,特別是在涉及結合或聚總的複雜查詢中,因為 Trino 的執行引擎可能與 Impala 不同。
此外,請考慮透過分析查詢計畫和進行必要的調整來最佳化新的 Trino 查詢。最後,記錄移轉過程中所學到的任何特定挑戰或課程,因為這對於未來的移轉至關重要。
相關連結
致謝
- 作者 - Pavan Upadhyay (Principal Cloud Engineer)、Saket Bihari (Principal Cloud Engineer)
其他學習資源
探索 docs.oracle.com/learn 上的其他實驗室,或存取 Oracle Learning YouTube 頻道上的更多免費學習內容。此外,請造訪 education.oracle.com/learning-explorer 以成為 Oracle Learning Explorer。
如需產品文件,請造訪 Oracle Help Center 。
Migrate Apache Impala Scripts to Trino on Oracle Big Data Service
G13976-01
September 2024