Funzioni Hive: esempi di funzioni integrate e definite dall'utente (UDF).

⚡ Riepilogo intelligente

Le funzioni Hive si dividono in due gruppi: funzioni integrate fornite con il motore e che coprono operazioni su raccolta, data, matematica, condizioni, stringhe e altro, e funzioni definite dall'utente scritte in Java per la logica che Hive non fornisce.

  • 📚 Sei famiglie predefinite: Le funzioni relative a collezioni, date, operazioni matematiche, condizioni, stringhe e altre ancora possono essere richiamate direttamente all'interno di HiveQL.
  • 🧾 Le firme contano: Ogni funzione ha un elenco fisso di argomenti e un tipo di ritorno documentato, quindi il tipo di ritorno determina dove può essere utilizzata.
  • 🧩 UDF colma le lacune: Quando non esiste una funzione integrata, una Java La classe che estende org.apache.hadoop.hive.ql.exec.UDF fornisce l'operazione mancante.
  • 🔢 Tre forme di funzionalità personalizzate: UDF restituisce una riga per riga, UDAF comprime più righe in una sola e UDTF espande una riga in molte.
  • Registrazione in due fasi: ADD JAR inserisce il codice nel classpath e CREATE TEMPORARY FUNCTION associa un nome alla classe.
  • ♻️ Il riutilizzo è il punto: Una UDF testata, come ad esempio uno stemmer, può essere richiamata da ogni query anziché essere riscritta ogni volta.

Funzioni di Hive: funzioni predefinite e funzioni definite dall'utente

Le funzioni sono create per uno scopo specifico, ovvero per eseguire operazioni di tipo matematico, aritmetico, logico e relazionale sugli operandi dei nomi delle colonne della tabella.

Funzioni integrate

Queste sono funzioni già disponibili in Hive. Innanzitutto, dobbiamo verificare i requisiti dell'applicazione, quindi possiamo utilizzare queste funzioni integrate nelle nostre applicazioni. Possiamo chiamare queste funzioni direttamente nella nostra applicazione.

La sintassi e i tipi sono menzionati nella sezione seguente.

Tipi di funzioni integrate in Hive:

  • Funzioni di raccolta
  • Funzioni data
  • Funzioni matematiche
  • Funzioni condizionali
  • Funzioni di stringa
  • Varie Funzioni

Ciascuna delle sei famiglie è descritta di seguito con le relative firme di funzione e i tipi di ritorno.

Funzioni di raccolta

Queste funzioni vengono utilizzate per le collezioni. Collezioni significano il gruppoping di elementi e restituiscono un singolo elemento o un array di elementi a seconda del tipo di ritorno specificato nel nome della funzione.

Tipo di ritorno Nome della funzione Descrizione
INT dimensione (mappa ) Recupererà e fornirà il numero di componenti nel tipo di mappa
INT dimensione(Array ) Recupererà e fornirà il numero di elementi nel tipo array
Vettore map_keys(Mappa ) Recupererà e restituirà un array contenente le chiavi della mappa di input. L'array non è ordinato
Vettore map_values(Mappa ) Recupererà e restituirà un array contenente i valori della mappa di input. L'array non è ordinato
Vettore sort_array(Array ) Ordina l'array di input in ordine crescente dei suoi elementi e lo restituisce
Booleano array_contains(Array , valore) Restituisce TRUE se l'array contiene il valore passato come secondo argomento

Funzioni data

Questi strumenti vengono utilizzati per eseguire manipolazioni di date e conversioni di tipi di data da un tipo a un altro:

Nome della funzione Tipo di ritorno Descrizione
unix_timestamp() BigInt Otterremo la corrente Unix timestamp in secondi. Il valore non è fisso per l'intera query.
data_data (stringa timestamp) quando Recupererà e fornirà la parte relativa alla data di una stringa timestamp
anno(data stringa) INT Recupererà e fornirà la parte dell'anno di una data o una stringa di timestamp
trimestre(data/timestamp/stringa) INT Recupererà e fornirà il trimestre dell'anno per una data, un timestamp o una stringa compresa tra 1 e 4
mese(data stringa) INT Fornirà la parte del mese di una data o una stringa di timestamp
ora(data stringa) INT Recupererà e fornirà l'ora del timestamp
minuto(stringa data) INT Recupererà e fornirà il minuto del timestamp
data_sottodata(stringa data di inizio, int giorni) quando Recupererà e fornirà il risultato di subtracun certo numero di giorni dalla data di inizio
data_attuale quando Recupererà e fornirà la data corrente all'inizio della valutazione della query.
ultimo_giorno (stringa data) stringa Recupererà e restituirà l'ultimo giorno del mese a cui appartiene la data
trunc(data stringa, formato stringa) stringa Recupererà e fornirà la data troncata all'unità specificata dal formato. Formati supportati: MESE/LUN/MM, ANNO/AAAA/AA.

Funzioni matematiche

Queste funzioni vengono utilizzate per operazioni matematiche. Invece di creare UDF, Hive dispone di alcune funzioni matematiche integrate.

Nome della funzione Tipo di ritorno Descrizione
rotondo(DOPPIO X) RADDOPPIARE Recupererà e restituirà il valore BIGINT arrotondato di X
round(DOPPIO X, INT d) RADDOPPIARE Recupererà e restituirà X arrotondato a d cifre decimali.
largo(DOPPIO X) RADDOPPIARE Recupererà e restituirà il valore BIGINT arrotondato di X utilizzando la modalità di arrotondamento HALF_EVEN, nota anche come arrotondamento bancario.
pavimento(DOPPIO X) GRANDE Recupererà e restituirà il valore BIGINT massimo uguale o inferiore al valore X.
ceil(DOPPIO a), ceiling(DOPPIO a) GRANDE Recupererà e restituirà il valore BIGINT minimo uguale o maggiore del valore a
rand(), rand(seme INT) RADDOPPIARE Recupererà e restituirà un numero casuale distribuito uniformemente tra 0 e 1. Fornendo un seme, la sequenza diventa ripetibile.

Funzioni condizionali

Queste funzioni vengono utilizzate per i controlli condizionali dei valori.

Nome della funzione Tipo di ritorno Descrizione
if(Condizione test booleana, valore TVero, valore TFalsoONullo) T Restituirà il valore True quando testCondition è vero, e il valore FalseOrNull in caso contrario.
è nullo(X) Booleano Recupererà i dati e restituirà true se X è NULL e false altrimenti.
non è nullo(X) Booleano Recupererà i dati e restituirà true se X non è NULL, altrimenti false.
nvl(valore T, valore_predefinito T) T Restituirà default_value quando value è NULL, e value altrimenti.

Funzioni di stringa

Le seguenti funzioni gestiscono le manipolazioni e le operazioni sulle stringhe.

Nome della funzione Tipo di ritorno Descrizione
inverti(stringa X) stringa Fornirà la stringa invertita di X
rpad(string str, lunghezza int, string pad) stringa Recupererà e darà str right-padded con pad fino a una lunghezza totale di lunghezza
rtrim(stringa X) stringa Recupererà e restituirà la stringa risultante dalla rimozione degli spazi dalla fine (lato destro) di X.
Per esempio, rtrim('risultati') restituisce 'risultati'
spazio(INT n) stringa Recupererà e restituirà una stringa di n spazi.
dividi(STRING str, STRING pat) schieramento Divide str attorno a pat (pat è un'espressione regolare).
str_to_map(testo[, delimitatore1, delimitatore2]) mappa Questo strumento suddividerà il testo in coppie chiave-valore utilizzando due delimitatori. Il delimitatore 1 separa le coppie e il delimitatore 2 suddivide ulteriormente ciascuna coppia.

Varie Funzioni

Diverse funzioni integrate non appartengono a nessuna delle famiglie sopra menzionate. Queste includono l'hashing, le informazioni di sessione e la chiamata arbitraria Java metodi.

Nome della funzione Tipo di ritorno Descrizione
hash(a1[, a2…]) INT Restituisce un valore hash degli argomenti
utente_attuale() stringa Restituisce il nome utente corrente dal gestore di autenticazione configurato
database_corrente() stringa Restituisce il nome del database corrente
md5 (stringa/binario) stringa Restituisce il checksum MD5 a 128 bit come stringa di 32 cifre esadecimali, oppure NULL per un argomento NULL.
sha1 (stringa/binario) stringa Restituisce l'hash SHA-1 dell'argomento come stringa esadecimale.
crc32 (stringa/binario) BigInt Restituisce il valore del controllo di ridondanza ciclica di un argomento stringa o binario
versione() stringa Restituisce la versione di Hive come numero di build seguito da un hash di build.
rifletti(classe, metodo[, argomento1…]) varia Chiama un Java metodo tramite corrispondenza della firma dell'argomento, utilizzando la reflection. java_method() è un sinonimo

UDF (funzioni definite dall'utente)

In Hive, gli utenti possono definire le proprie funzioni per soddisfare determinati requisiti del cliente. Queste sono note come UDF in Hive. Le funzioni definite dall'utente sono scritte in Java per moduli specifici.

Alcune UDF sono specificamente progettate per il riutilizzo del codice nei framework applicativi. Lo sviluppatore scrive queste funzioni in Java e integra tali UDF con Hive.

Durante l'esecuzione della query, lo sviluppatore può utilizzare direttamente il codice e le UDF restituiranno output in base alle attività definite dall'utente. Ciò garantisce elevate prestazioni in termini di programmazione ed esecuzione.

Ad esempio, per lo stemming delle stringhe non abbiamo alcuna funzione predefinita in Hive. Per questo, possiamo scrivere una UDF di stemming in JavaOvunque sia necessaria la funzionalità stem, possiamo richiamare direttamente questa UDF stem in Hive.

Qui la funzionalità stemming significa derivare le parole dalle loro parole radice. Un algoritmo di stemming riduce le parole "wishing", "wished" e "wishes" alla parola radice "wish". Per eseguire questo tipo di funzionalità, possiamo scrivere una UDF in Java e integrarlo con Alveare.

A seconda del caso d'uso, la UDF può essere scritta per accettare e produrre un numero diverso di valori di input e output.

La UDF di tipo generale accetta un singolo valore di input e produce un singolo valore di output. Se la UDF viene utilizzata in una query, verrà richiamata una volta per ogni riga del set di dati risultante.

Nella direzione opposta, una funzione può accettare un gruppo di valori in input e restituire un singolo valore in output. Questa differenza è ciò che distingue i tre tipi di funzioni personalizzate descritti di seguito.

UDF vs UDAF vs UDTF in Hive

Le funzioni personalizzate in Hive sono raggruppate in base al numero di righe in ingresso e in uscita. La scelta del tipo errato è la causa più comune per cui una funzione personalizzata non viene compilata o restituisce una singola riga dove era prevista una tabella.

Tipo Righe in entrata → righe in uscita Classe da estendere Esempi integrati
UDF Una riga → una riga org.apache.hadoop.hive.ql.exec.UDF lunghezza(), arrotonda(), inverti()
UDAF Molte righe → una riga org.apache.hadoop.hive.ql.udf.generic.AbstractGenericUDAFResolver count(), min(), max()
UDTF Una riga → molte righe org.apache.hadoop.hive.ql.udf.generic.GenericUDTF explode(), json_tuple(), parse_url_tuple()

Dalla tabella si possono ricavare due regole pratiche:

  • Una clausola UDAF è quasi sempre abbinata a una clausola GROUP BY, perché comprime ogni gruppo in un'unica riga.
  • Un UDTF non può essere selezionato insieme ad altre colonne nella stessa lista SELECT, quindi viene normalmente utilizzato con una LATERAL VIEW.

Esiste anche una seconda classe base più potente per le operazioni a livello di riga, GenericUDF, che accetta tipi complessi come array, mappe e struct e un numero variabile di argomenti.

Come scrivere e registrare una UDF in Hive

L'esempio dello stem descritto sopra può essere costruito come una vera funzione in quattro passaggi. Niente oltre a Java Sono necessari un compilatore e una sessione Hive in esecuzione.

Passo 1) Scrivi a Java Classe che estende UDF e implementa un metodo pubblico evaluate(). Hive chiama evaluate() una volta per riga, quindi il metodo deve gestire un input NULL.

package com.guru99.hive.udf;

import org.apache.hadoop.hive.ql.exec.UDF;
import org.apache.hadoop.io.Text;

public final class Stem extends UDF {

    public Text evaluate(final Text input) {
        if (input == null) {
            return null;
        }
        String word = input.toString().toLowerCase();
        if (word.endsWith("ing")) {
            word = word.substring(0, word.length() - 3);
        } else if (word.endsWith("ed") || word.endsWith("es")) {
            word = word.substring(0, word.length() - 2);
        }
        return new Text(word);
    }
}

Passo 2) Compila la classe e impacchettala in un file JAR, ad esempio hive-udf-1.0.jar, insieme a tutte le classi da cui dipende.

Passo 3) Inserisci il file JAR nel classpath di Hive e associa un nome di funzione alla classe. Una funzione temporanea esiste solo per la durata della sessione corrente.

ADD JAR /home/hduser/hive-udf-1.0.jar;

CREATE TEMPORARY FUNCTION stem AS 'com.guru99.hive.udf.Stem';

Passo 4) Richiama la nuova funzione esattamente come una funzione integrata. Applicata alle parole "wishing", "wished" e "wishes", questa classe restituisce "wish" per tutte e tre.

SELECT word, stem(word) FROM words;

Per mantenere la funzionalità disponibile a ogni sessione e a ogni utente, è preferibile registrarla in modo permanente in un database. Il file JAR deve trovarsi in un percorso accessibile a tutto il cluster, che in genere corrisponde a HDFS.

CREATE FUNCTION default.stem AS 'com.guru99.hive.udf.Stem'
USING JAR '/user/hive/udfs/hive-udf-1.0.jar';

Una singola classe può dichiarare più di un metodo evaluate(). Hive confronta la chiamata con le firme degli argomenti, ed è così che una funzione può accettare sia una stringa che un numero intero.

DOMANDE FREQUENTI

SHOW FUNCTIONS elenca tutti i nomi registrati, inclusi quelli personalizzati. DESCRIBE FUNCTION nome stampa una firma su una riga, e DESCRIBE FUNCTION EXTENDED nome aggiunge esempi di utilizzo laddove forniti dalla classe implementatrice.

Quasi sempre si tratta di un problema di nome o di ambito: la stringa dopo AS deve essere il nome completo della classe e ADD JAR si applica solo alla sessione che lo ha eseguito. Riconnettersi elimina sia il file JAR che qualsiasi funzione temporanea.

Utilizza GenericUDF quando la funzione accetta tipi complessi come array, mappe o struct, un numero variabile di argomenti o deve convalidare autonomamente i tipi degli argomenti. La semplice classe UDF risolve i tipi tramite reflection e gestisce solo i tipi primitivi Writable.

Una vera UDF deve essere eseguita sulla JVM. Per altri linguaggi, Alveare offre la clausola TRANSFORM, che trasmette ogni riga attraverso uno script esterno come Python tramite input e output standard. È più lento ma evita Java interamente.

Possono farlo. evaluate() viene eseguito una volta per riga, quindi la logica complessa viene moltiplicata per il numero di righe e l'allocazione di oggetti all'interno del metodo aumenta il carico sulla garbage collection. È preferibile utilizzare una funzione integrata quando disponibile e mantenere evaluate() libero da operazioni di I/O.

No. I nomi delle funzioni non fanno distinzione tra maiuscole e minuscole, quindi ROUND(), Round() e round() sono la stessa funzione. Java Il nome della classe nella clausola AS è una questione diversa e deve corrispondere esattamente alla classe compilata, incluso il suo pacchetto.

Gli assistenti di apprendimento automatico associano una descrizione in linguaggio naturale alle firme candidate e avvisano quando un tipo di ritorno non è compatibile con la colonna di destinazione. Verifica il suggerimento confrontandolo con la firma documentata, poiché i nomi generati a volte appartengono a un altro dialetto SQL.

Genera uno scheletro utilizzabile — la dichiarazione della classe, le importazioni e un metodo evaluate() — a partire da un commento che descrive l'operazione. La gestione dei valori null, i tipi scrivibili e la fase di impacchettamento necessitano ancora di revisione, e la funzione deve essere testata su righe reali.

Riassumi questo post con: