Hadoop MapReduce教程–最大化MapReduce

对于本文,我们假设我们正在运营一家在线广告公司。 我们为客户(如百事可乐,索尼)开展广告活动,并在新闻网站(CNN,Fox)和社交媒体网站(Facebook)等热门网站上展示广告。 为了跟踪广告活动的效果,我们跟踪我们投放的广告和用户点击的广告。

这是事件的顺序:

  1. 我们向用户投放广告

  2. 如果广告出现在用户浏览器上,则又是用户看到了广告。 我们将此事件跟踪为VIEWED_EVENT

  3. 如果用户点击广告,则我们将此事件跟踪为CLICKED_ EVENT

这些事件作为纯文本日志文件记录在我们的Web服务器上。 这些日志可能会变得非常大,每天达到数亿(100,000,000)。 我们正在谈论的是数百GB甚至TB的数据。 通过分析大量数据可以收集到很多有趣的信息和趋势,而Hadoop是分析数据的理想选择。 在本文中,我们将通过衡量点击次数与观看次数的比率来计算广告系列的效果。

Java : 代码示例使用Java,您将需要Java才能运行Hadoop。 拥有诸如Eclipse之类的IDE是可选的。

Hadoop:您需要安装并运行Hadoop。 这可以是包含多个计算机的实际Hadoop群集。 您也可以在笔记本电脑上运行Hadoop! 仅仅使用Hadoop就足够了。 Hadoop可以从Apache网站Cloudera网站下载。 设置Hadoop不在本文讨论范围之内。 请参阅各个站点文档

Ruby (可选) :提供了示例日志文件。 如果需要更多的日志文件,可以使用随附的Ruby脚本 ad -log-generator.rb。 Ruby是一种非常紧凑的语言,非常适合脚本等。

本文的源代码:本文提到的所有代码和材料都可以从Github获得 。 您可以从参考文献中的URL下载代码,也可以使用git来获取它:https://github.com/sujee/java-tech-journal-mapreduce。

日志文件: 日志文件采用以下格式: 时间戳,用户ID,查看/点击,域,campaign_id。 例如:1262332801728、899523、1,npr.org,19

这些文件为CSV(逗号分隔值)格式,每行一条记录。 每条记录将具有以下字段:

  • 时间戳:Unix时间戳(以毫秒为单位)
  • user_id:每个用户都有一个唯一的ID
  • action_id:1 =查看,2 =点击
  • 域:投放广告的域
  • campaign_id:标识广告所属的广告系列

有一个 sample.log 文件 ,其中包含一些条目:

  • 1293868800864,319248,1,flickr.com,12
  • 1293868801728,625828,1,npr.org,19
  • 1293868802592,522177,2,wikipedia.org,16
  • 1293868803456,535052,2,cnn.com,20

logs 目录包含一些可用于测试的日志文件。

我们想看看我们的广告系列效果如何。 对于每个广告系列,我们都希望评估“观看次数”和“点击次数”。 我们将使用MapReduce进行计算! 让我们勾勒出MapReduce算法。 有时,从我们想要的结果中倒退比较容易:

输入: 日志行
输出:
campaign1,total_views,total_clicks
campaign2,total_views,total_clicks

我们的减速器必须产生最终的输出,运动统计数据。 因此减速器必须接受“运动”作为关键。 让我们将每个广告系列的所有action_id都设为值。 因此,我们的地图正在通过日志行,并提取campaign_id和action_id。 图1说明了工作流程。

让我们看一些代码!

MapReduce程序(通常)具有三个组件:

• 映射器
• 减速机
• 和一个“驱动程序”程序,将所有东西连接在一起

如果代码很小,我们可以将整个文件放在一个文件中。 可以在GitHub清单1中看到代码

首先要注意的是我们的映射器类是如何定义的:

static class MyMapper extends Mapper<Object, Text, IntWritable, IntWritable>

我们指定:

  • 输入键,值是:对象,文本:输入键是行号,由于我们不关心它,因此将其强制转换为对象。 输入值是实际的行,是Java字符串,等效的MapReduce类称为Text
  • 输出键值是:IntWritable,IntWritable:映射器将campaign_id和action_id输出为整数。
Java类型 MapReduce类型
整数 可写的
可写
文本

MapReduce具有围绕大多数Java原语的包装器类。 这样,就可以对值进行序列化/反序列化(表1)。 现在地图功能:

 

static class MyMapper extends Mapper<Object, Text, IntWritable, IntWritable>

请注意,输入参数与Mapper类定义匹配。 映射器功能非常简单。 我们将行分成令牌。 提取“广告系列”和“操作”字段。 将这两个包装为IntWritables并将其写出。

代码:减速器

让我们从Reducer类定义开始:

public static class MyReducer extends Reducer<IntWritable, IntWritable, IntWritable, Text>
  • 输入键/值:Int- Writable / IntWritable :这些类类型与Mapper的输出匹配
  • 并且输出是IntWritable / Text

让我们看一下reduce函数:

public void reduce(IntWritable key, Iterable<IntWritable> results, Context context)

键/值:IntWritables为每个广告系列 IntWritable /列表 ,我们得到该广告活动的所有行动作为一个迭代列表。 我们正在遍历action_ids 。 并计算“观看次数”和“点击次数”。 一旦完成计算,就写出结果。 这是可能的,因为针对一个活动的所有动作都被分组并发送到一个化简器(记住MapReduce的“魔力”)。

这是所有映射器和精简器的连接点,作业开始了。 该代码大部分是样板代码,非常简单。 我将省略对这部分的解释 。 在继续之前,请确保具备以下条件:

• Hadoop已安装并正在运行
• HADOOP_HOME环境变量集

将日志文件复制到HDFS中:

hadoop dfs –mkdir adlogs/in 
        hadoop dfs –put *.log adlogs/in

这将在HDFS中的/ user / user_name / adlogs / in下创建目录。 在我们的例子中,用户名是/ user / sujee / adlogs / in 。 在顶层目录中运行compile.sh来编译Java源代码并生成一个jar(a.jar): sh ./compile.sh 。 我们通过以下方式运行此地图减少作业:

$HADOOP_HOME/bin/hadoop jar a.jar mapreduce.CampaignMR1 adlogs/in adlogs/out
  • 使用“ $ HADOOP_ HOME / bin”目录中的“ hadoop”命令
  • 指向提供我们的MR类的a.jar :mapreduce.CampaignMR1
  • 两条路径:adlogs / in是日志文件的位置,
  • adlogs / out是将输出写入的位置

这将产生如下输出:

12/01/18 08:22:25 INFO input.FileInputFormat: Total input paths to process : 5
12/01/18 08:22:25 INFO mapred.JobClient: Running job: job_201201180820_0004
12/01/18 08:22:26 INFO mapred.JobClient: map 0% reduce 0%
12/01/18 08:22:32 INFO mapred.JobClient: map 40% reduce 0%
12/01/18 08:22:33 INFO mapred.JobClient: map 60% reduce 0%
12/01/18 08:22:36 INFO mapred.JobClient: map 100% reduce 0%
12/01/18 08:22:41 INFO mapred.JobClient: map 100% reduce 26%
12/01/18 08:22:43 INFO mapred.JobClient: map 100% reduce 100%
12/01/18 08:22:43 INFO mapred.JobClient: Job complete: job_201201180820_0004

让我们看看生成的输出。 这将在/ user / user_name / adlogs / out中 。 您可以使用NameNode Web UI在这里浏览。 应该有一个part-r-00000文件。 继续并单击它。 或者您也可以像这样检查:

•hadoop dfs –ls adlogs / out
•hadoop dfs –cat adlots / out / part-r-00000

它将如下所示

1  views=134, clicks=122

2  views=139, clicks=135

3  views=115, clicks=152

4  views=129, clicks=123

5  views=99, clicks=120

6  views=110, clicks=124

7  views=126, clicks=113

8  views=110, clicks=119

9  views=127, clicks=131

10  views=113, clicks=143

11 views = 120, clicks=116

12 views = 99, clicks=143

13 views=113, clicks =133

14 views=117, clicks 135

15 views=127, clicks 121

16 views=117, clicks 121

17 views=127, clicks 98

18 views=127, clicks 157

19 views=127, clicks 117

20 views=132, clicks 169

我们到了,我们有我们的广告系列摘要! 结果文件在HDFS中。 要将其复制到本地计算机:

hadoop dfs –copyToLocal adlogs/out/part-r-00000 campaign-report

然后可以将该报告通过电子邮件发送,导入到excel等。

关于输出格式的注意事项

上面的格式是:

Campaign_id <TAB> views=x, clicks=y <NEWLINE>

为了易于导入到Excel,我们可以使用TAB作为字段分隔符。 在reduce函数中,修改以下行:

String stats = "views=" + views + ", clicks=" + clicks;

至:

String stats = views + "t" + clicks;
改善MapReduce代码

当前,我们的map和reduce函数假定数据正确并且一切都井井有条。 但是,在现实生活中,它并不理想。 我们需要加强代码以处理入侵数据。 在MapReduce中尤其如此,因为我们处理大量数据。 当事情无法正常进行时,调试可能会非常困难。 增强的代码在GitHub上的清单2中可见。

地图减少良好做法

使用计数器:在结束图减少作业运行时,您将看到如下输出:

FileSystemCounters

12/01/18 08:22:43 INFO mapred.JobClient: FILE_BYTES_READ=1733
12/01/18 08:22:43 INFO mapred.JobClient: HDFS_BYTES_READ=186904
12/01/18 08:22:43 INFO mapred.JobClient: FILE_BYTES_WRITTEN=290468
12/01/18 08:22:43 INFO mapred.JobClient: HDFS_BYTES_WRITTEN=508

这些是MapReduce框架产生的计数器。 这些显示一些IO统计信息。 我们也可以有自己的柜台。 我刚刚展示了一个名为INCORRECT_RECORDS的自定义计数器。 每次遇到无效数据时,我们都会增加此计数器。 在MapReduce运行结束时,该计数器值将被打印出来。 另外,我们可以在工作跟踪器页面上检查此计数器。 最好是使用自定义计数器来跟踪事物。 计数器可用于跟踪许多无效记录,以跟踪例如在特定操作中花费的时间。

错误检查: 程序必须处理错误。 在Map-Reduce程序中,检查错误甚至更为重要,因为MR程序处理大量数据,并且MR作业在多台计算机上运行。 因此,调试由于坏数据而导致的程序崩溃并不容易。 在处理非结构化数据(日志等)时,总是有机会遇到格式错误的数据。 因此,MR程序必须在方法的每个步骤中检查错误:

  • 首先检查该行是否具有正确的字段数(本例中为6)。 如果不是,我们增加INCORRECT_ RECORDS计数器并从map函数返回。 无需进一步处理。
  • 始终以正确的记录打印。 这些日志进入映射器日志。 可以通过JobTracker UI访问它们(单击Job | map | Tasks |输出)。
  • 然后,当将动作/广告系列转换为整数时,我们将处理异常。
  • 通常,映射器必须进行大量错误检查,因为它们会通过原始输入。 因此,映射器是清理数据,删除无效数据等的好地方。

在映射器清理数据时,Reducer的输入来自映射器。

开发和部署 : 您可以在笔记本电脑或较小的群集上开发map reduce作业。 获得处理少量测试数据的代码/算法。 然后将作业部署到生产集群。 处理较小数据量(兆字节)的代码可能不适用于较大数据集(兆字节)。

使用不同大小的数据进行测试 : 当我们开始编写MapReduce函数时,我们将从一小部分示例数据开始。 一旦我们合理地确定算法是可靠的,那么我们将使用更大的数据进行测试。 这就是为什么拥有“数据生成器”脚本很方便(我们的ruby脚本)的原因。 使用这些脚本,我们可以生成任意数量的数据(十行或一千万行)。

开发工具 : 没有太多可用于Hadoop MapReduce编程的工具和IDE。 Plain Eclipse可用于用Java开发MapReduce程序。 Karphasphere IDE等工具填补了这个空白。

既然您已经完成了一个简单的map-reduce程序,该是时候进行更多探索了。 我们计算了广告系列的总观看次数和总点击次数。 我们如何计算每天的观看次数/点击次数? (提示:使用复合键:campaign_id + date)

本文最初发表于2012年2月的Java Tech Journal:Hadoop中。要阅读Hadoop / MapReduce的更多文章,请在此处下载


翻译自: https://jaxenter.com/hadoop-mapreduce-tutorial-maximize-mapreduce-104471.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值