2013-08-09 16 views
10

ho un lavoro MapReduce definito main.py, che importa il modulo lib da lib.py. Io uso Hadoop streaming di presentare questo lavoro al cluster Hadoop come segue:Come importare un modulo personalizzato in un lavoro MapReduce?

hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -files lib.py,main.py 
    -mapper "./main.py map" -reducer "./main.py reduce" 
    -input input -output output 

Nella mia comprensione, questo dovrebbe mettere sia main.py e lib.py nella cartella della cache distribuita su ogni macchina di calcolo e quindi rendere modulo lib disponibili a main. Ma non succede: dal log vedo che i file sono copiati nella stessa directory,, ma main non possono importare lib, lanciando ImportError.

Perché ciò accade e come posso risolverlo?

UPD. Aggiunta la directory corrente al percorso non ha funzionato:

import sys  
sys.path.append(os.path.realpath(__file__)) 
import lib 
# ImportError 

però, il caricamento del modulo ha fatto manualmente il trucco:

import imp 
lib = imp.load_source('lib', 'lib.py') 

Ma non è quello che voglio. Quindi perché l'interprete Python vede altri file .py nella stessa directory, ma non li può importare? Si noti che ho già provato ad aggiungere un file vuoto __init__.py alla stessa directory senza effetto.

+0

Avete controllato 'sys.path' in' main.py' per assicurarvi che la directory di lavoro sia inclusa? – lmjohns3

+0

@ lmjohns3: sì, la directory di lavoro si trova sul classpath. BTW, non è automaticamente incluso per lo script in esecuzione? (solo curioso) – ffriend

+0

Credo che sia vero per gli script Python che vengono avviati sulla riga di comando, ma lo streaming Hadoop potrebbe avviare un interprete Python in un altro modo (non proprio sicuro). Ad ogni modo, continuo a pensare che questo possa sembrare un problema di percorso. Vedi http://www.litfuel.net/plush/?postid=195 per una possibilità di distribuire i tuoi moduli in un modo diverso. In alternativa, prova a scrivere i tuoi comandi in uno script di shell e passando quello per gli argomenti della riga di comando '-mapper' e' -reducer'. – lmjohns3

risposta

12

Ho inviato la domanda all'elenco degli utenti di Hadoop e alla fine ho trovato la risposta. Si scopre che Hadoop non copia realmente i file nella posizione in cui viene eseguito il comando, ma crea invece i collegamenti per loro. Python, a sua volta, non può funzionare con symlink e quindi non riconosce lib.py come modulo Python.

semplice soluzione qui è quello di mettere sia main.py e lib.py nella stessa directory, in modo che link simbolico alla directory è inserito nel directory di lavoro di lavoro MR, mentre entrambi i file sono fisicamente nella stessa directory. Così ho fatto la seguente:

  1. Put main.py e lib.py in app directory.
  2. In main.py ho usato lib.py direttamente, cioè, import string è solo

    import lib

  3. Uploaded directory app con -files opzione.

Quindi, comando finale assomiglia a questo:

hadoop jar /usr/lib/hadoop-mapreduce/hadoop-streaming.jar -files app 
     -mapper "app/main.py map" -reducer "app/main.py reduce" 
     -input input -output output 
+0

L'utilizzo dell'opzione -files per caricare dozzine di file non ha funzionato nel mio ambiente hadoop. –

3

Quando Hadoop-streaming inizia gli script python, il percorso del vostro script python è dove il file di script è in realtà. Comunque, hadoop li avvia a './', e il tuo lib.py (è un link simbolico) si trova anche in './'. Quindi, cercare di aggiungere 'sys.path.append ("./")' prima di importare lib.py in questo modo: import sys sys.path.append('./') import lib

+0

Sto usando il filo, che sembra non supportare -file come la risposta selezionata utilizza. Questo ha funzionato alla grande, grazie! – bkribbs

1

I -files e -archive interruttori sono solo scorciatoie per di Hadoop distributed cache (DC), un altro meccanismo generale che consente anche di caricare e decomprimere automaticamente gli archivi nei formati zip, tar e tgz/tar.gz. Se invece di un singolo modulo la tua libreria è implementata da un pacchetto Python strutturato, quest'ultima caratteristica è ciò che desideri.

Stiamo sostenendo direttamente questo Pydoop dal rilascio 1.0.0-rc1, dove si può semplicemente costruire un archivio mypkg.tgz ed eseguire il programma come:

pydoop submit --upload-archive-to-cache mypkg.tgz [...] 

La documentazione rilevanti sono a http://crs4.github.io/pydoop/self_contained.html ed ecco un esempio operativo completo (richiede wheel): https://github.com/crs4/pydoop/tree/master/examples/self_contained.

Problemi correlati