2012-06-19 4 views
14

Quando lo sviluppo di script di maiale che utilizzano lo STORE comando devo cancellare la directory di output per ogni corsa o lo script si ferma e offre:Come forzare STORE (sovrascrittura) su HDFS in Pig?

2012-06-19 19:22:49,680 [main] ERROR org.apache.pig.tools.grunt.Grunt - ERROR 6000: Output Location Validation Failed for: 'hdfs://[server]/user/[user]/foo/bar More info to follow: 
Output directory hdfs://[server]/user/[user]/foo/bar already exists 

Quindi sono alla ricerca di una soluzione in-Pig a rimuovere automaticamente la directory, anche quella che non soffoca se la directory non esiste al momento della chiamata.

Nel Pig Latin Reference ho trovato il comando di shell invoker fs. Sfortunatamente lo script Pig si rompe ogni volta che qualcosa produce un errore. Quindi non posso usare

fs -rmr foo/bar 

(i. E. Eliminare ricorsivamente) in quanto si rompe se la directory non esiste. Per un momento ho pensato che potrei usare

fs -test -e foo/bar 

che è un test e non dovrebbe rompere o così ho pensato. Tuttavia, Pig interpreta nuovamente il codice di ritorno di test in una directory non esistente come codice di errore e interruzioni.

C'è una JIRA ticket per il progetto Pig affrontare il mio problema e suggerendo un optional parametro OVERWRITE o FORCE_WRITE per il comando diSTORE. Ad ogni modo, sto usando Pig 0.8.1 per necessità e non esiste un parametro del genere.

risposta

40

Finalmente ho trovato una soluzione su grokbase. Dal momento che trovare la soluzione ha richiesto troppo tempo, lo riprodurrò qui e aggiungerò ad esso.

si supponga di voler archiviare l'output utilizzando l'istruzione

STORE Relation INTO 'foo/bar'; 

Poi, al fine di eliminare la directory, è possibile chiamare alla partenza dello script

rmf foo/bar 

No ";" o citazioni richieste poiché si tratta di un comando di shell.

Non riesco a riprodurlo ora ma a un certo punto nel tempo ho ricevuto un messaggio di errore (qualcosa sui file mancanti) dove posso solo supporre che rmf interferito con mappa/ridurre. Quindi consiglio di mettere la chiamata prima di ogni dichiarazione di parentela. Dopo SET, REGISTRI e valori di default dovrebbero andare bene.

Esempio:

SET mapred.fairscheduler.pool 'inhouse'; 
REGISTER /usr/lib/pig/contrib/piggybank/java/piggybank.jar; 
%default name 'foobar' 
rmf foo/bar 
Rel = LOAD 'something.tsv'; 
STORE Rel INTO 'foo/bar'; 
+0

Anche se questo è davvero bello, non è atomica.Preferirei farlo in tre passaggi: 1) memorizza in 'foobar-tmp' 2) rmf foo/bar 3) mv 'foobar-tmp' a foo/bar –

+2

@MiguelPing: Mi sembra che il tuo approccio dovrebbe incappare in il mio problema iniziale, ma per 'foobar-tmp' invece di' foo/bar'. La memorizzazione per prima cosa può anche produrre quell'errore elusivo che ho attribuito provvisoriamente alla mappa/riduzione. Se la soluzione funziona da parte tua, potresti trasformarla in una risposta con uno script di esempio e fornire il numero di versione del tuo maiale? – valid

+0

@valid la mia soluzione è simile alla tua, ho appena aggiunto un ulteriore passaggio per garantire che se qualcosa accade tra 'rmf' e' STORE' (ad esempio, eccezione) non perdi dati. Gli script Pig possono fallire in qualsiasi momento, quindi la mia soluzione non è atomica, ma almeno non corri il rischio di perdere dati. –

2

Una volta che si utilizza il comando fs, c'è un sacco di modi per farlo. Per un singolo file, ho finito di aggiungere questo per l'inizio dei miei script:

-- Delete file (won't work for output, which will be a directory 
-- but will work for a file that gets copied or moved during the 
-- the script.) 
fs -touchz top_100 
rm top_100 

Per una directory

-- Delete dir 
fs -rm -r out