Hinweis:

Apache Impala-Skripte auf Oracle Big Data Service nach Trino migrieren

Einführung

Oracle Big Data Service (BDS) ist ein cloud-basierter Service von Oracle, mit dem Benutzer Hadoop-Cluster, Spark-Cluster, Trino und andere Big Data-Services erstellen und verwalten können. In der Welt der Big Data-Analysen zeichnet sich Trino als leistungsstarke, verteilte SQL-Abfrage-Engine aus, die für die Ausführung interaktiver analytischer Abfragen auf großen Datensätzen entwickelt wurde. Trino ermöglicht die Abfrage von Daten über mehrere Quellen hinweg, einschließlich Hadoop Distributed File System (HDFS), OCI-Bucket und traditionellen relationalen Datenbanken, alles innerhalb einer einheitlichen SQL-Schnittstelle. Die Fähigkeit, große Datenmengen mit geringer Latenz zu verarbeiten, macht sie zu einem leistungsstarken Tool für Data Engineers und Analysten gleichermaßen.

Durch den Wechsel zu modernen Datenplattformen migrieren viele Unternehmen auf Oracle Big Data Service von Apache Impala nach Trino. Dieses Tutorial bietet einen schrittweisen Ansatz zur Automatisierung und manuellen Anpassung von Apache Impala-Skripten für eine nahtlose Migration nach Trino.

Ziele

Voraussetzungen

Aufgabe 1: Skriptkonvertierung automatisieren

Das automatisierte Skript wurde entwickelt, um den Prozess der Konvertierung von Apache Impala-Skripten zu optimieren, sodass sie mit Trino in Oracle Big Data Service kompatibel sind. Dieses Skript automatisiert mehrere Schlüsseltransformationen, reduziert den manuellen Aufwand und minimiert das Potenzial für menschliche Fehler während des Migrationsprozesses. Hier ist eine Aufschlüsselung seiner Funktionalität.

  1. Dateiverarbeitung und Initialisierung.

    • Das Skript beginnt mit dem Lesen einer Eingabedatei .hql (die normalerweise für Apache Impala-Abfragen verwendet wird).

    • Es wird eine neue Ausgabedatei erstellt, in der die konvertierte Trino-kompatible Abfrage gespeichert wird.

    • Das Skript fügt zunächst eine Zeile hinzu, um den Katalog- und Datenbankkontext festzulegen. Dabei wird USE catalog_name.schema_name verwendet, um sicherzustellen, dass die Abfragen im richtigen Kontext im Trino ausgeführt werden.

  2. Automatisierte Abfragetransformationen.

    • Tabellenhandhabung überschreiben: Das Skript sucht nach beliebigen OVERWRITE TABLE-Anweisungen im Apache Impala-Skript und fügt entsprechende DELETE FROM-Anweisungen direkt darüber ein. Dadurch wird sichergestellt, dass die Tabelle gelöscht wird, bevor neue Daten eingefügt werden. Dies richtet sich nach dem Umgang von Trino mit Datenüberschreibungen.

    • Ersatz von Impala-spezifischen Funktionen: Das Skript wendet mehrere Transformationen an, um Apache Impala-spezifische Syntax und Funktionen durch trino-kompatible zu ersetzen. Beispiel:

      • Die Befehle invalidate metadata und REFRESH werden auskommentiert, da sie im Trino nicht benötigt werden.

      • Datentypänderungen wie string in varchar werden so vorgenommen, dass sie den Datentypen des Trino entsprechen.

      • Die TRUNCATE TABLE-Anweisungen von Impala werden durch DELETE FROM ersetzt, da Trino die Abschneidung unterschiedlich behandelt.

      • COMPUTE STATS wird durch ANALYZE ersetzt, was widerspiegelt, wie Trino Statistiken sammelt.

      • Andere spezifische Transformationen umfassen die Verarbeitung von Funktionen wie nvl, ifnull und from_utc_timestamp und die Anpassung an die Syntax und Funktionen des Trino.

      • nvl2-Funktionen werden in äquivalente COALESCE-Ausdrücke konvertiert.

      • Abgleich regulärer Ausdrücke (REGEXP) mit Trinos REGEXP_LIKE wird geändert.

      • Datums- und Zeitstempelfunktionen werden an die Syntax des Trino angepasst.

    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
    

    Hinweis Dieses Skript bietet einen grundlegenden Ansatz für die Konvertierung von Apache Impala-Skripten in Trino, deckt jedoch nicht alle möglichen Impala-Anweisungen und -Szenarios ab. Wenn zusätzliche Impala-spezifische Syntax oder Funktionen auftreten, die nicht von diesem Skript verarbeitet werden, können Sie das Skript erweitern, indem Sie neue Transformationsregeln hinzufügen, um diese Fälle abzudecken. Die regelmäßige Aktualisierung des Skripts mit diesen Änderungen wird seine Effektivität für zukünftige Konvertierungen verbessern.

Aufgabe 2: Konvertierungsskript ausführen

  1. Speichern Sie das Skript im Oracle Big Data Service-Edge-Knoten.

  2. Führen Sie das Skript mit der Zieldatei oder dem Verzeichnis aus, das Apache Impala-Skripte enthält.

  3. Prüfen Sie die generierten Ausgabe- und Differenzdateien auf Änderungen.

Aufgabe 3: Manuelle Korrekturen vornehmen

  1. Verwenden Sie die LEFT ANTI JOIN-Anweisung.

    Bestimmte Apache Impala SQL-Konstrukte wie LEFT ANTI JOIN erfordern ein manuelles Eingreifen. Identifizieren Sie LEFT ANTI JOIN-Anweisungen im Impala-Skript, und ersetzen Sie sie durch äquivalente Trino SQL mit LEFT JOIN durch eine WHERE-Klausel.

    Beispiele für Skripte:

    • Impala-Skript:

      SELECT t1.*
       FROM table1 t1
       LEFT ANTI JOIN table2 t2 ON t1.key = t2.key;
      
    • Trino-Skript:

      SELECT t1.*
       FROM table1 t1
       LEFT JOIN table2 t2 ON t1.key = t2.key
       WHERE t2.key IS NULL;
      
  2. Passen Sie GROUP BY-Klauseln an.

    Trino ermöglicht die positionsbasierte Gruppierung in der GROUP BY-Klausel, die lange Gruppierungen vereinfachen kann. Konvertieren Sie Spaltennamen gegebenenfalls in ihre Positionsäquivalente in der GROUP BY-Klausel. Stellen Sie sicher, dass alle Spalten korrekt zugeordnet sind.

    Beispiele für Skripte:

    • Impala-Skript:

      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-Skript:

      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
      

Troubleshooting und Tipps

Nächste Schritte

Nach Abschluss der Migration von Apache Impala-Skripten nach Trino auf Oracle Big Data Service ist es wichtig, die konvertierten Skripte gründlich zu validieren. Führen Sie zunächst die konvertierten Trino-Skripte in einer Testumgebung aus, um sicherzustellen, dass sie die erwarteten Ergebnisse liefern. Achten Sie besonders bei komplexen Abfragen mit Joins oder Aggregationen auf Performanceunterschiede, da sich die Ausführungs-Engine von Trino im Vergleich zu Impala möglicherweise anders verhält.

Erwägen Sie außerdem, die neuen Abfragen im Trino zu optimieren, indem Sie die Abfragepläne analysieren und die erforderlichen Anpassungen vornehmen. Dokumentieren Sie schließlich alle spezifischen Herausforderungen oder Erfahrungen, die während des Migrationsprozesses gelernt wurden, da dies für zukünftige Migrationen von Nutzen sein wird.

Danksagungen

Weitere Lernressourcen

Sehen Sie sich andere Übungen zu docs.oracle.com/learn an, oder greifen Sie im Oracle Learning YouTube-Channel auf weitere kostenlose Lerninhalte zu. Besuchen Sie außerdem education.oracle.com/learning-explorer, um Oracle Learning Explorer zu werden.

Die Produktdokumentation finden Sie im Oracle Help Center.