任何一个解决方案都不可能做到天衣无缝,在不断出现的应用面前,一定会不断暴露出问题,暴露出问题就要解决。
问题1.与同一个KEY相关联的数据不能太多。
需求如下:
假如有如下的数据(我尽量简化字段):
域名 QQ号码 性别。
www.qq.com 21201421 男
....
我需要做类似如下功能的统计 select count(distinct QQ号码) from 数据源 group by 性别。
根据上次的文章,我们可能的做法如下:
map(K1 key, Text value, OutputCollector<K2, V2> output, Reporter reporter)
{
//如何抽取字段我就不多说了,大家应该都清楚了。
//关键就是这个KEY的取值。
key = 性别+"_UV";
value = QQ号码
//将找到的key->value对反馈给框架
Output.emit(Key ,value);
}
2.Reduce方法需要做什么
void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output, Reporter reporter)
{
if( postFix( key ) == "_UV" ) //判断是否是用户数这个指标相关的数据
{
//values中的数据就是从各台机器上归总过来的QQ号码
String uv = distinctCount( values );
//push出最终结果
Output.emit(key,uv );
}
}
这样的方式乍看上去没什么问题,但是如果真正提交任务,很有可能将多个机器磁盘撑爆都无法完成任务的执行,问题在哪里呢?
关键就是KEY值的生成,因为这个需求是按照性别进行统计分析,很显然最终会有两个KEY:"男性_UV","女性_UV",也就是说这个job只有两个reduce任务,所有男性的QQ号码会集中到一台机器,所有女性的QQ号码也会集中到一台机器,这就导致承担reduce任务的机器负载过大,如果涉及的数据量过大,很可能任务就会执行失败。
问题就在这里,想必大家都已经清楚了,那么如何解决这个问题呢?
解决办法:将KEY打散。
还是这个需求。
map(K1 key, Text value, OutputCollector<K2, V2> output, Reporter reporter)
{
//关键就是这个KEY的取值,我们按照QQ号码后5五位进行数据打散。
key = 性别+"_UV_"+$func_取QQ号码后五位(QQ号码);
value = QQ号码
//将找到的key->value对反馈给框架
Output.emit(Key ,value);
}
2.Reduce方法需要做什么(reduce代码不做任何变化)
void reduce(Text key, Iterator<Text> values,
OutputCollector<Text, Text> output, Reporter reporter)
{
if( postFix( key ) == "_UV" ) //判断是否是用户数这个指标相关的数据
{
//values中的数据就是从各台机器上归总过来的QQ号码
String uv = distinctCount( values );
//push出最终结果
Output.emit(key,uv );
}
}
这样就会有很多个类似于如下格式的KEY "男性_UV_00000" "男性_UV_00001" "男性_UV_00002" ..... "男性_UV_99999" (女性时一样)
也就是说
原来的统计结果为:
男性_UV: XXXXXX
女性_UV:XXXXXX
而现在的统计结果为:
以00000结尾的男性的QQ号码_UV: XXXXX
以00001结尾的男性的QQ号码_UV: XXXXX
以00002结尾的男性的QQ号码_UV: XXXXX
.....
以99999结尾的男性的QQ号码_UV: XXXXX
以00000结尾的女性的QQ号码_UV: XXXXX
以00001结尾的女性的QQ号码_UV: XXXXX
以00002结尾的女性的QQ号码_UV: XXXXX
.....
以99999结尾的女性的QQ号码_UV: XXXXX
拿到结果再做一次统计操作就可以得到整体指标数据了。
转自:
http://blog.csdn.net/sxf_824/article/details/4842126