All'interno di un database definiamo tabelle rappresentate da un file collocato nello spazio di storage gestito da
Hive. La tabella potrà agganciarsi ad un file già esistente o ad uno che essa stessa creerà con le operazioni di inserimento.
Il comando che crea una tabella è CREATE TABLE e richiede obbligatoriamente il nome della tabella da creare. Nel seguente
esempio vediamo del codice che svolge le seguenti operazioni:
- cancellazione del database archivio (se esistente), al solo scopo di far partire l'esempio da zero
- nuova creazione del database archivio
- impostazione di archivio come database corrente
- creazione di una tabella
DROP DATABASE IF EXISTS archivio CASCADE;
CREATE DATABASE archivio;
USE archivio;
CREATE TABLE dipendenti(
matricola STRING,
nome STRING,
cognome STRING,
data_nascita DATE
)
STORED AS PARQUET;
Abbiamo specificato, oltre al nome dipendenti, due elementi basilari:
- i nomi dei campi, indicati tra parentesi tonde, ognuno dei quali definito con un nome ed un
tipo di dato. Nel nostro caso
per ogni dipendente saranno indicati una matricola, un nome ed un cognome (tutte e tre di tipo stringa) nonché una data di nascita
di tipoDATE
; - un formato di salvataggio dei dati introdotto da STORED AS. In questo caso, chiediamo di creare un file
PARQUET
,
un tipo di file a gestione colonnare.
L'indicazione di STORED AS
non è obbligatoria. Quando non è fornita, indica che il tipo di file sarà quello di default, ovvero TEXTFILE
. Abbiamo
già sottolineato in questa guida come il tipo di memorizzazione adottato impatterà sulle prestazioni e dipende pertanto dal genere
di attività di interrogazione che vogliamo svolgere. Comunque sia, i comandi HiveQL che si utilizzeranno funzioneranno senza nessuna necessità
di adattamento in base al tipo di file. Ad esempio, se volessimo svolgere un inserimento di tre righe (argomento approfondito nelle prossime lezioni), potremmo
invocare la seguente direttiva:
INSERT INTO dipendenti VALUES ('003411L','Valerio', 'Rossi', '1978-12-03'),
('398122K', 'Diana', 'Bianchi', '1990-07-21'), ('451932Z', 'Simona', 'Verdi', '1980-08-20');
funzionante con qualsiasi tipo di tabella.
Per accertarsi dell'avvenuta creazione della tabella possiamo utilizzare il comando SHOW TABLES
, che
fornirà il seguente output:
hive> SHOW TABLES;
OK
dipendenti
Time taken: 0.167 seconds, Fetched: 1 row(s)
Possiamo inoltre richiedere informazioni dettagliate sulla tabella con DESCRIBE FORMATTED dipendenti;
il quale
fornirà statistiche e dettagli della struttura tra cui:
- nome e tipo di dato dei campi:
# col_name data_type comment matricola string nome string cognome string data_nascita date informazioni sulla tabella: [code lang=plain] Database: archivio OwnerType: USER Owner: hduser CreateTime: Sat Aug 17 12:46:22 UTC 2019 LastAccessTime: UNKNOWN Retention: 0 Location: hdfs://localhost:9000/warehouse/archivio.db/dipendenti Table Type: MANAGED_TABLE Table Parameters: COLUMN_STATS_ACCURATE {\"BASIC_STATS\":\"true\"} bucketing_version 2 numFiles 1 numRows 3 rawDataSize 12 totalSize 759 transient_lastDdlTime 1566046552
Tabelle come file CSV
Potremmo creare anche una tabella per gestire un file CSV.
Questa è la revisione del comando CREATE TABLE
dell'esempio precedente per raggiungere tale scopo:
CREATE TABLE dipendenti(
matricola STRING,
nome STRING,
cognome STRING,
data_nascita DATE
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ';';
Come si vede, abbiamo dovuto specificare che avremo righe delimitate con campi separati da un punto e virgola. Non abbiamo
indicato STORED AS
, pertanto il file sarà di tipo TEXTFILE
.
Considerando che abbiamo installato Hive con Hadoop, se abbiamo un po' di dimestichezza con i comandi per interagire con il client
hdfs possiamo interrogare il file system distribuito per farci stampare il contenuto della tabella (in cui abbiamo fatto gli
inserimenti multipli come visto prima). Così facendo potremo vedere come i dati siano effettivamente stati salvati su disco. Digitiamo quindi dalla riga di comando del sistema operativo:
hdfs dfs -cat /warehouse/archivio.db/dipendenti/000000_0
e otteniamo in output:
003411L;Valerio;Rossi;1978-12-03
398122K;Diana;Bianchi;1990-07-21
451932Z;Simona;Verdi;1980-08-20
Questa è la forma fisica della nostra tabella e, come possiamo notare, si tratta di un normale file CSV con il punto e virgola
come separatore. Per chiarire il comando impartito, si noti che al client hdfs abbiamo passato il flag -cat
per la stampa di un
file come direttiva per il modulo dfs. Il percorso dipende dalla nostra installazione di Hive: come abbiamo già ricordato facciamo
salvare il tutto nella cartella HDFS /warehouse, la cartella archivio.db prende il nome dal database, la cartella dipendenti dalla
tabella mentre il file vero e proprio segue un numero progressivo assegnato dal sistema. Tale prova non è obbligatoria per usare Hive
ma in questo caso ci è utile per sapere qualcosa in più sulla modalità di immagazzinamento dei dati.
Creazione di tabelle per copia
Una tabella può nascere come copia di un'altra, ed esistono due modi per farlo:
- si può copiare solo la struttura usando il costrutto
CREATE TABLE ... LIKE
dove, dopo il
LIKE
, specifichiamo il nome della tabella di cui importeremo lo schema (ma non i dati). Dalla prova seguente copiamo la tabella
dipendenti per dare una struttura a dipendenti_nuova e subito dopo eseguiamo qualche verifica:hive> CREATE TABLE dipendenti_nuova LIKE dipendenti; OK Time taken: 1.382 seconds hive> SHOW TABLES; OK dipendenti dipendenti_nuova Time taken: 0.061 seconds, Fetched: 2 row(s) hive> DESCRIBE FORMATTED dipendenti_nuova; OK # col_name data_type comment matricola string nome string cognome string data_nascita date ... ... Table Parameters: ... ... numRows 0 ... ...
Come si nota, la struttura contiene gli stessi campi di dipendenti ma ha numero di righe nullo;
- possiamo copiare i dati utilizzando il costrutto
CREATE TABLE...AS SELECT
dove il contenuto della nuova tabella sarà il risultato della query (argomento approfondito nelle lezioni successive):CREATE TABLE dipendenti_nuova AS SELECT * FROM dipendenti;
e dalla verifica otteniamo:
hive> SHOW TABLES; OK dipendenti dipendenti_copia Time taken: 0.034 seconds, Fetched: 2 row(s) hive> DESCRIBE FORMATTED dipendenti_copia; OK # col_name data_type comment matricola string nome string cognome string data_nascita date ... ... Table Parameters: ... ... numRows 3 ... ...
Tabelle esterne
Una tabella esterna memorizza i dati in una cartella diversa da quella che Hive usa come collocazione di default per lo storage. Ciò è utile per incorporare
dati esterni nel nostro lavoro senza procedere a copie o spostamenti ma soprattutto quando dei dati sono condivisi con altre applicazioni
che puntano allo stesso spazio su HDFS. Per farlo dobbiamo usare la parola chiave EXTERNAL e indicare con LOCATION
quale collocazione di HDFS ne costituirà il contenuto: attenzione che l'indirizzo deve puntare ad una cartella, mai ad un file.
CREATE EXTERNAL TABLE transazioni(
data DATE,
importo DECIMAL,
codice STRING,
descrizione STRING,
id_conto INT
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY ';'
LOCATION 'hdfs://localhost:9000/banca';
In questo caso, tutto ciò che Hive farà con la tabella lo farà all'interno della cartella banca.
Cancellare una tabella
Una tabella può essere cancellata con DROP TABLE
. Il seguente comando, ad esempio, cancella
la tabella dipendenti così:
DROP TABLE dipendenti;
Se provassimo a cancellare una tabella che non esiste e la variabile di configurazione di Hive hive.exec.drop.ignorenonexistent fosse
impostata a false, verremmo respinti da un messaggio di errore. Per evitare ciò possiamo utilizzare il modificatore IF EXISTS
con DROP TABLE
(o impostare la variabile hive.exec.drop.ignorenonexistent a true). Ricordiamo che per leggere e modificare i valori delle variabili di sistema
si deve utilizzare in entrambi i casi il comando SET
. Conduciamo il seguente esperimento per chiarire il concetto: impostiamo a
false il valore della variabile di configurazione citata, sempre con SET
ne verifichiamo l'effettiva modifica e proviamo a cancellare una tabella
non esistente con e senza IF EXISTS
:
hive> SET hive.exec.drop.ignorenonexistent;
hive.exec.drop.ignorenonexistent=true
hive> DROP TABLE tabella_che_non_esiste;
OK
Time taken: 0.022 seconds
hive> SET hive.exec.drop.ignorenonexistent=false;
hive> SET hive.exec.drop.ignorenonexistent;
hive.exec.drop.ignorenonexistent=false
hive> DROP TABLE tabella_che_non_esiste;
FAILED: SemanticException [Error 10001]: Table not found tabella_che_non_esiste
hive> DROP TABLE IF EXISTS tabella_che_non_esiste;
OK
Time taken: 0.025 seconds
Il valore iniziale di hive.exec.drop.ignorenonexistent era impostato a true infatti il primo DROP TABLE
, sprovvisto di IF EXISTS
non ha sollevato errori.
Subito dopo l'abbiamo cambiato in false
e da lì abbiamo iniziato a ricevere i messaggi di errore.
In molti casi, può essere utile non cancellare la tabella come struttura ma eliminare solo i suoi contenuti. Allo scopo, esiste un comando apposito:
TRUNCATE TABLE
. Supponendo di avere una tabella dipendenti non vuota, il seguente esempio dimostra come TRUNCATE TABLE
sia in grado di cancellare i suoi
contenuti senza rimuoverla dal database:
hive> TRUNCATE TABLE dipendenti;
OK
Time taken: 0.284 seconds
hive> SHOW TABLES;
OK
dipendenti
Time taken: 0.028 seconds, Fetched: 1 row(s)
hive> SELECT * FROM dipendenti;
OK
Time taken: 0.276 seconds