2009-12-03 29 views
1

J'ai plusieurs fichiers HTML volumineux et je souhaite exécuter un travail Hadoop MapReduce pour trouver les mots les plus fréquemment utilisés. J'ai écrit mon mapper et réducteur en Python et j'ai utilisé le streaming Hadoop pour les exécuter.Travail Hadoop MapReduce dans un fichier contenant des balises HTML

Voici mon Mapper:

#!/usr/bin/env python 

import sys 
import re 
import string 

def remove_html_tags(in_text): 
''' 
Remove any HTML tags that are found. 

''' 
    global flag 
    in_text=in_text.lstrip() 
    in_text=in_text.rstrip() 
    in_text=in_text+"\n" 

    if flag==True: 
     in_text="<"+in_text 
     flag=False 
    if re.search('^<',in_text)!=None and re.search('(>\n+)$', in_text)==None: 
     in_text=in_text+">" 
     flag=True 
    p = re.compile(r'<[^<]*?>') 
    in_text=p.sub('', in_text) 
    return in_text 

# input comes from STDIN (standard input) 
global flag 
flag=False 
for line in sys.stdin: 
    # remove leading and trailing whitespace, set to lowercase and remove HTMl tags 
    line = line.strip().lower() 
    line = remove_html_tags(line) 
    # split the line into words 
    words = line.split() 
    # increase counters 
    for word in words: 
     # write the results to STDOUT (standard output); 
     # what we output here will be the input for the 
     # Reduce step, i.e. the input for reducer.py 
     # 
     # tab-delimited; the trivial word count is 1 
     if word =='': continue 
     for c in string.punctuation: 
      word= word.replace(c,'') 

     print '%s\t%s' % (word, 1) 

Voici mon réducteur:

#!/usr/bin/env python 

from operator import itemgetter 
import sys 

# maps words to their counts 
word2count = {} 

# input comes from STDIN 
for line in sys.stdin: 
    # remove leading and trailing whitespace 
    line = line.strip() 

    # parse the input we got from mapper.py 
    word, count = line.split('\t', 1) 
    # convert count (currently a string) to int 
    try: 
     count = int(count) 
     word2count[word] = word2count.get(word, 0) + count 
    except ValueError: 
     pass 

sorted_word2count = sorted(word2count.iteritems(), 
key=lambda(k,v):(v,k),reverse=True) 

# write the results to STDOUT (standard output) 
for word, count in sorted_word2count: 
    print '%s\t%s'% (word, count) 

Chaque fois que je viens d'un petit tuyau petit échantillon chaîne comme «bonjour bonjour bonjour monde monde ... Je reçois la sortie appropriée d'une liste classée. Cependant, lorsque je tente d'utiliser un petit fichier HTML, et essayez d'utiliser le chat pour tuyau le code HTML dans mon cartographe, je reçois l'erreur suivante (input2 contient un code HTML):

[email protected]:~$ cat input2 | /home/rohanbk/mapper.py | sort | /home/rohanbk/reducer.py 
Traceback (most recent call last): 
    File "/home/rohanbk/reducer.py", line 15, in <module> 
    word, count = line.split('\t', 1) 
ValueError: need more than 1 value to unpack 

Quelqu'un peut-il expliquer pourquoi je Je reçois ça? En outre, quel est un bon moyen de déboguer un programme de travail MapReduce?

Répondre

1

Vous pouvez reproduire le bug même avec juste:

echo "hello - world" | ./mapper.py | sort | ./reducer.py 

La question est ici:

if word =='': continue 
for c in string.punctuation: 
      word= word.replace(c,'') 

Si word est un signe de ponctuation, comme ce serait le cas pour l'entrée ci-dessus (après sa division), il est converti en une chaîne vide. Donc, il suffit de déplacer la vérification d'une chaîne vide à après le remplacement.

+0

Est-il raisonnable de supposer que si vous utilisez cat et que vous obtenez la sortie désirée, l'étape MapReduce fonctionnera? – GobiasKoffi

+0

Pour une expérience d'intégration python/Hadoop plus agréable, vous pouvez envisager d'utiliser Dumbo. – drxzcl