Una funzione definita dall'utente (UDF) è un modo per un utente di estendere le capacità native di Apache Spark™ SQL. SQL su Databricks supporta funzioni definite dall'utente esterne scritte nei linguaggi di programmazione Scala, Java, Python e R fin dalla versione 1.3.0. Sebbene le UDF esterne siano molto potenti, presentano anche alcuni avvertimenti:
Per far fronte alle limitazioni di cui sopra, siamo entusiasti di introdurre una nuova forma di UDF: le UDF SQL. Disponibile in DBR 9.1 LTS, la UDF SQL è completamente definita con la potenza espressiva di SQL ed è anche completamente trasparente al compilatore SQL.
Dai un'occhiata all'ebook Why the Data Lakehouse is Your Next Data Warehouse per scoprire il funzionamento interno della Databricks Lakehouse Platform.
Le UDF SQL sono estensioni semplici ma potenti di SQL su Databricks. Come funzioni, forniscono un livello di astrazione per semplificare la costruzione delle query, rendendo le query SQL più leggibili e modularizzate. A differenza delle UDF scritte in un linguaggio non SQL, le UDF SQL sono più leggere da creare per gli utenti SQL. I corpi delle funzioni SQL sono trasparenti all'ottimizzatore di query, rendendole quindi più performanti delle UDF esterne. Le UDF SQL possono essere create come funzioni temporanee o permanenti, riutilizzate in più query, sessioni e utenti, e controllate tramite Access Control Language (ACL). In questo blog, ti guideremo attraverso alcuni casi d'uso chiave delle UDF SQL con esempi.
Iniziamo con la funzione più semplice immaginabile: una costante. Sappiamo tutti che non dovremmo usare letterali nel nostro codice perché danneggia la leggibilità e, chi lo sa, forse la costante non rimane tale. Quindi vogliamo poterla cambiare in un solo posto:
Se hai familiarità con le UDF esterne, puoi vedere che ci sono alcune differenze che spiccano:
Oltre a queste differenze, ci sono molte altre cose che sono uguali alle UDF esterne:
Usiamo la funzione:
Senza sorpresa, questo funziona. Ma cosa sta succedendo sotto il cofano?
Questo è fantastico! Il compilatore SQL ha sostituito l'invocazione della funzione con la costante stessa.
Ciò significa che almeno questa UDF SQL non ha alcun costo in termini di prestazioni.
Ora, diamo un'occhiata a un altro modello di utilizzo comune.
Immagina di non gradire la denominazione di alcune funzioni predefinite. Forse stai migrando molte query da un altro prodotto, che ha nomi e comportamenti di funzione diversi. O forse semplicemente non sopporti di copiare e incollare espressioni lunghe più e più volte nelle tue query SQL. Quindi, vuoi risolvere questo problema.
Con le UDF SQL, possiamo semplicemente creare una nuova funzione con il nome che preferiamo:
Diamo un'occhiata a quale nuova sintassi è stata utilizzata qui:
Non solo funziona…
...ma funziona bene:
Possiamo vedere che il piano fisico mostra un'applicazione diretta delle funzioni lpad, hex, least e greatest. Questo è lo stesso piano che ottieni invocando direttamente la serie di funzioni.
Puoi anche comporre funzioni SQL da funzioni SQL:
Un altro uso comune delle UDF SQL è quello di codificare i lookup. Un semplice lookup può essere quello di decodificare i codici colore RGB in nomi di colore in inglese:
OK, ma ci sono molti più di due colori in questo mondo. E vogliamo questa traduzione in entrambi i sensi, quindi questi dovrebbero essere in una tabella di lookup:
Ci sono diversi nuovi concetti applicati qui:
Come appare il piano fisico ora? È facile vedere che l'utilizzo di una UDF esterna, che a sua volta esegue una query che risulterebbe in un join a ciclo annidato, è un modo terribile per bruciare preziose risorse.
In questo caso, Catalyst ha scelto un broadcast hash join invece di un nested loop join. Può farlo perché comprende il contenuto della SQL UDF.
Finora, tutti gli esempi discussi hanno utilizzato funzioni a valore scalare – quelle che restituiscono un singolo valore. Quel risultato può essere di qualsiasi tipo, anche combinazioni complesse di struct, array e mappe. Esiste anche un altro tipo di UDF da discutere: la UDF a valore di tabella.
Immagina se le viste accettassero argomenti! Potresti incapsulare predicati complessi anche se si basano su valori forniti dall'utente. Una SQL Table UDF è proprio questo: una vista con un altro nome, tranne che con i parametri.
Supponiamo che la mappatura dei colori sopra non sia univoca. Almeno, possiamo affermare che i nomi dei colori differiscono tra le lingue.
Pertanto, la funzione `from_rgb` deve essere modificata per restituire un array di nomi o una relazione.
Come puoi vedere, l'unica differenza rispetto a una funzione scalare è una clausola RETURNS più complessa. A differenza delle viste, le SQL UDF richiedono una dichiarazione della firma della relazione restituita:
Le funzioni definite dall'utente a tabella sono una novità di DBR. Diamo un'occhiata a come invocarle.
Nella sua forma più semplice, una funzione a tabella viene invocata nello stesso modo e negli stessi luoghi in cui viene referenziata una vista. L'unica differenza sono le parentesi graffe obbligatorie, che includono gli argomenti della funzione. Questa funzione viene invocata con argomenti letterali, ma gli argomenti possono essere qualsiasi espressione, anche sottoquery scalari.
Tuttavia, l'uso più potente è l'utilizzo di SQL table UDF in un join, tipicamente un correlated cross join:
Qui gli argomenti fanno riferimento (correlano) a una relazione precedente (laterale) nella clausola FROM. La nuova keyword LATERAL dà a Catalyst il permesso di risolvere queste colonne. Nota anche che puoi fare riferimento al risultato della funzione a tabella nominando le colonne come definite nella firma del risultato e opzionalmente qualificate dal nome della funzione.
Naturalmente, le SQL UDF sono completamente supportate dalle istruzioni esistenti GRANT, REVOKE, SHOW, DESCRIBE e DROP.
L'istruzione che merita un approfondimento è DESCRIBE.
La describe di base restituisce ciò che ti aspetteresti, ma la DESCRIBE estesa aggiunge dettagli significativamente maggiori:
Ciò che abbiamo descritto rappresenta la funzionalità iniziale per le SQL UDF. Le future estensioni che stiamo valutando includono il supporto per:
Le SQL UDF rappresentano un grande passo avanti nell'usabilità di SQL e possono essere utilizzate in molti modi diversi come delineato in questo blog. Ti incoraggiamo a pensare a modi ancora più creativi per sfruttare le SQL UDF, sia in Databricks SQL che utilizzando Photon per i lavori di Data Engineering. Prova il notebook qui e consulta la documentazione per maggiori informazioni.
(Questo post sul blog è stato tradotto utilizzando strumenti basati sull'intelligenza artificiale) Post originale
