Hadoop Streaming 编程

栏目: 服务器 · 发布时间: 5年前

内容简介:Hadoop Streaming是Hadoop提供的一个编程工具,它允许用户使用任何可执行文件或者脚本文件作为Mapper和Reducer,例如:采用shell脚本语言中的一些命令作为mapper和reducer(cat作为mapper,wc作为reducer)本文安排如下,第二节介绍Hadoop Streaming的原理,第三节介绍Hadoop Streaming的使用方法,第四节介绍Hadoop Streaming的程序编写方法,在这一节中,用C++、C、shell脚本 和python实现了WordCo

1、概述

Hadoop Streaming是Hadoop提供的一个编程工具,它允许用户使用任何可执行文件或者脚本文件作为Mapper和Reducer,例如:

采用 shell 脚本语言中的一些命令作为mapper和reducer(cat作为mapper,wc作为reducer)

$HADOOP_HOME/bin/hadoop  jar \
  $HADOOP_HOME/contrib/streaming/hadoop-*-streaming.jar \
  -input myInputDirs \
  -output myOutputDir \
  -mapper cat \
  -reducer wc

本文安排如下,第二节介绍Hadoop Streaming的原理,第三节介绍Hadoop Streaming的使用方法,第四节介绍Hadoop Streaming的程序编写方法,在这一节中,用C++、C、shell脚本 和 python 实现了WordCount作业,第五节总结了常见的问题。 文章最后给出了程序下载地址 。(本文内容基于Hadoop-0.20.2版本)

(注:如果你采用的语言为C或者C++,也可以使用Hadoop Pipes,具体可参考这篇文章: Hadoop Pipes编程。 )

关于Hadoop Streaming高级编程方法,可参考这篇文章: Hadoop Streaming高级编程

2、Hadoop Streaming原理

mapper和reducer会从标准输入中读取用户数据,一行一行处理后发送给标准输出。Streaming工具会创建MapReduce作业,发送给各个tasktracker,同时监控整个作业的执行过程。

如果一个文件(可执行或者脚本)作为mapper,mapper初始化时,每一个mapper任务会把该文件作为一个单独进程启动,mapper任务运行时,它把输入切分成行并把每一行提供给可执行文件进程的标准输入。 同时,mapper收集可执行文件进程标准输出的内容,并把收到的每一行内容转化成key/value对,作为mapper的输出。 默认情况下,一行中第一个tab之前的部分作为 key ,之后的(不包括tab)作为 value。 如果没有tab,整行作为key值,value值为null。

对于reducer,类似。

以上是Map/Reduce框架和streaming mapper/reducer之间的基本通信协议。

3、Hadoop Streaming用法

Usage: $HADOOP_HOME/bin/hadoop jar \
  $HADOOP_HOME/hadoop-streaming.jar [options]

options:

(1)-input:输入文件路径

(2)-output:输出文件路径

(3)-mapper:用户自己写的mapper程序,可以是可执行文件或者脚本

(4)-reducer:用户自己写的reducer程序,可以是可执行文件或者脚本

(5)-file:打包文件到提交的作业中,可以是mapper或者reducer要用的输入文件,如配置文件,字典等。

(6)-partitioner:用户自定义的partitioner程序

(7)-combiner:用户自定义的combiner程序(必须用 java 实现)

(8)-D:作业的一些属性(以前用的是-jonconf),具体有:

  • 1)mapred.map.tasks:map task数目
  • 2)mapred.reduce.tasks:reduce task数目
  • 3)stream.map.input.field.separator/stream.map.output.field.separator: map task输入/输出数据的分隔符,默认均为\t。
  • 4)stream.num.map.output.key.fields:指定map task输出记录中key所占的域数目
  • 5)stream.reduce.input.field.separator/stream.reduce.output.field.separator:reduce task输入/输出数据的分隔符,默认均为\t。
  • 6)stream.num.reduce.output.key.fields:指定reduce task输出记录中key所占的域数目

另外,Hadoop本身还自带一些好用的Mapper和Reducer:

(1)Hadoop聚集功能

Aggregate提供一个特殊的reducer类和一个特殊的combiner类,并且有一系列的“聚合器”(例如“sum”,“max”,“min”等)用于聚合一组value的序列。用户可以使用Aggregate定义一个mapper插件类,这个类用于为mapper输入的每个key/value对产生“可聚合项”。Combiner/reducer利用适当的聚合器聚合这些可聚合项。要使用Aggregate,只需指定“-reducer aggregate”。

(2)字段的选取(类似于Unix中的‘cut’)

Hadoop的 工具 类org.apache.hadoop.mapred.lib.FieldSelectionMapReduc帮助用户高效处理文本数据,就像unix中的“cut”工具。工具类中的map函数把输入的key/value对看作字段的列表。 用户可以指定字段的分隔符(默认是tab),可以选择字段列表中任意一段(由列表中一个或多个字段组成)作为map输出的key或者value。 同样,工具类中的reduce函数也把输入的key/value对看作字段的列表,用户可以选取任意一段作为reduce输出的key或value。

4、Mapper和Reducer实现

本节试图用尽可能多的语言编写Mapper和Reducer,包括Java,C,C++,Shell脚本,python等。

由于Hadoop会自动解析数据文件到Mapper或者Reducer的标准输入中,以供它们读取使用,所有应先了解各个语言获取标准输入的方法。

(1)Java语言:

见Hadoop自带例子

(2) C++语言:

string key;
while(cin>>key){
  cin>>value;
   ….
}

(3)C语言:

char buffer[BUF_SIZE];
while(fgets(buffer, BUF_SIZE - 1, stdin)) {
  int len = strlen(buffer);
  …
}

(4)Shell脚本

用管道

(5) Python脚本

import sys
for line in sys.stdin:
.......

为了说明各种语言编写Hadoop Streaming程序的方法,下面以WordCount为例,WordCount作业的主要功能是对用户输入的数据中所有字符串进行计数。

(1)C语言实现

//mapper
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUF_SIZE        2048
#define DELIM   "\n"

int main(int argc, char *argv[]){
  char buffer[BUF_SIZE];
  while(fgets(buffer, BUF_SIZE - 1, stdin)){
  int len = strlen(buffer);
    if(buffer[len-1] == '\n')
      buffer[len-1] = 0;

      char *querys  = index(buffer, ' ');
      char *query = NULL;
      if(querys == NULL) continue;
      querys += 1; /*  not to include '\t' */

      query = strtok(buffer, " ");
      while(query){
          printf("%s\t1\n", query);
          query = strtok(NULL, " ");
      }
 }
  return 0;
}
//--------------------------------------------------------------------------
//reducer
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#define BUFFER_SIZE     1024
#define DELIM   "\t"

int main(int argc, char *argv[]){
 char strLastKey[BUFFER_SIZE];
 char strLine[BUFFER_SIZE];
 int count = 0;

 *strLastKey = '\0';
 *strLine = '\0';

 while( fgets(strLine, BUFFER_SIZE - 1, stdin) ){
 char *strCurrKey = NULL;
 char *strCurrNum = NULL;

 strCurrKey  = strtok(strLine, DELIM);
 strCurrNum = strtok(NULL, DELIM); /* necessary to check error but.... */

 if( strLastKey[0] == '\0'){
   strcpy(strLastKey, strCurrKey);
 }

 if(strcmp(strCurrKey, strLastKey)) {
   printf("%s\t%d\n", strLastKey, count);
   count = atoi(strCurrNum);
 } else {
   count += atoi(strCurrNum);
 }
 strcpy(strLastKey, strCurrKey);
 }
 printf("%s\t%d\n", strLastKey, count); /* flush the count */
 return 0;
}

(2)C++语言实现

//mapper
#include <stdio.h>
#include <string>
#include <iostream>
using namespace std;

int main() {
  string key;
  string value = "1";
  while(cin>>key) {
    cout<<key<<"\t"<<value<<endl;
  }
  return 0;
}
//------------------------------------------------------------------------------------------------------------
//reducer
#include <string>
#include <map>
#include <iostream>
#include <iterator>
using namespace std;
int main() {
  string key;
  string value;
  map<string, int> word2count;
  map<string, int>::iterator it;
  while(cin>>key) {
    cin>>value;
    it = word2count.find(key);
    if(it != word2count.end()) {
      (it->second)++;
    } else {
      word2count.insert(make_pair(key, 1));
    }
  }

  for(it = word2count.begin(); it != word2count.end(); ++it) {
    cout<<it->first<<"\t"<<it->second<<endl;
  }
  return 0;
}

(3)shell脚本语言实现

$HADOOP_HOME/bin/hadoop  jar $HADOOP_HOME/hadoop-streaming.jar \
    -input myInputDirs \
    -output myOutputDir \
    -mapper cat \
   -reducer  wc

(4)Python脚本语言实现

#!/usr/bin/env python

import sys

# maps words to their counts
word2count = {}

# input comes from STDIN (standard input)
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()
    # split the line into words while removing any empty strings
    words = filter(lambda word: word, 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
        print '%s\t%s' % (word, 1)
#---------------------------------------------------------------------------------------------------------
#!/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()
    # convert count (currently a string) to int
    try:
        count = int(count)
        word2count[word] = word2count.get(word, 0) + count
    except ValueError:
        # count was not a number, so silently
        # ignore/discard this line
        pass

# sort the words lexigraphically;
#
# this step is NOT required, we just do it so that our
# final output will look more like the official Hadoop
# word count examples
sorted_word2count = sorted(word2count.items(), key=itemgetter(0))

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

5、常见问题

(1)作业总是运行失败:

需要把mapper文件和reducer文件放到各个tasktracker上,保证各个节点均有一份。也可在提交作业时,采用-file选项指定这些文件。

(2)用脚本编写时,第一行需注明脚本解释器,默认是shell

6、参考资料

【1】 C++&Python实现Hadoop Streaming的paritioner和模块化

【2】 如何在Hadoop中使用Streaming编写MapReduce

【3】 Hadoop如何与C++结合

【4】 Hadoop Streaming和pipes理解

7、程序打包下载

文章中用到的程序源代码可在 此处下载


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

企业应用架构模式

企业应用架构模式

Martin Fowler、王怀民、周斌 / 王怀民、周斌 / 机械工业出版社 / 2004-7 / 49.00元

本书作者是当今面向对象软件开发的权威,他在一组专家级合作者的帮助下,将40多种经常出现的解决方案转化成模式,最终写成这本能够应用于任何一种企业应用平台的、关于解决方案的、不可或缺的手册。本书获得了2003年度美国软件开发杂志图书类的生产效率奖和读者选择奖。本书分为两大部分。第一部分是关于如何开发企业应用的简单介绍。第二部分是本书的主体,是关于模式的详细参考手册,每个模式都给出使用方法和实现信息,并一起来看看 《企业应用架构模式》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

MD5 加密
MD5 加密

MD5 加密工具