Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1088175
  • 博文数量: 143
  • 博客积分: 969
  • 博客等级: 准尉
  • 技术积分: 1765
  • 用 户 组: 普通用户
  • 注册时间: 2011-07-30 12:09
文章分类

全部博文(143)

文章存档

2023年(4)

2021年(2)

2020年(4)

2019年(4)

2018年(33)

2017年(6)

2016年(13)

2014年(7)

2013年(23)

2012年(33)

2011年(14)

我的朋友

分类: 云计算

2018-07-06 10:24:49

相关性计数模式主要用来分析数据相关性的设计模式。比如根据大量用户超市购物车的商品列表就可以分析关联性,大多数用户购买了A商品的同时购买了C商品,我们可以通过分析挖掘,将商品AC摆在一起,或者将AC捆绑销售,提高用户的购买性

假设有如下数据:

2,3,1,4,5,2,3

1,2,5,2

4,5

1,3,4,1

3,1

4,2,1,5,5,3

每一行代表一个用户购物车所有商品的ID

     [1,2]  5(2+2+0+0+0+1=5)来表示,5个用户同时购买商品2和商品1, 要实现这种统计,通常有2种模式: pairs  stripes 

   paris模式


paris模式思想相对简单,就是在Map阶段逐个列表读取2个商品ID为一对做为key,并且计数为1做为value,将Keyvalue 发送到Reduce中,相同的Key会发送到同一reduce中,因此,在reduce中对value值进行累加就完成计数。

伪代码如下:

点击(此处)折叠或打开

  1. class Mapper
  2.     method Map(null, items [i1, i2,...] )
  3.         for all item i in [i1, i2,...]
  4.             for all item j in [i1, i2,...]
  5.                 Emit(pair [i j], count 1) //出现一次发送一次计数
  6.  class Reducer
  7.     method Reduce(pair [i j], counts [c1, c2,...])
  8.         s = sum([c1, c2,...]) //统计出现的次数
  9.         Emit(pair[i j], count s)

 Stripes模式

      stripes模式相对比较复杂,在map阶段逐个读取商品ID,并对这个商品ID进行累加计数。将商品IDkey,计数个数作为value,保存在MapWritable中。将商品IDkeyMapWriteablevalue 发送到reduce中。在reudce中,对MapWritable中的商品ID,购买个数在次进行累加,将商品对及累计数发送出去,完成计数。

Map阶段输入数据:

2,3,1,4,5,2,3

1,2,5,2

4,5

1,3,4,1

3,1

4,2,1,5,5,3

Map 阶段输出格式: 商品ID[商品ID,累计数]

     2,[1,1]

     2,[3,2]

     2,[4,1]

     2,[5,1]

           3,[1,1]

3,[2,1]

3,[4,1]

3,[5,1]

1,[2,1]

1,[3,1]

1,[4,1]

1,[5,1]

4,[2,1]

4,[3,1]

4,[5,1]

5,[2,1]

5,[3,1]

2,[3,1]    

1,[2,2]

1,[5,1]

2,[5,1]

5,[2,1]

4,[5,1]

1,[3,1]

1,[4,1]

3,[1,1]

3,[4,1]

4,[1,1]

3,[1,1]

4,[1,1]

4,[2,1]

4,[3,1]

4,[5,2]

2,[1,1]

2,[3,1]

2,[5,2]

1,[3,1]

1,[5,2]

5,[3,1]

5,[3,1]

    

Reduce阶段输出:

[1,2]                           3

[1,3]                           3

[1,4]                           2

[1,5]                           4

[2,1]                           2

[2,3]                           4

[2,4]                           1

[2,5]                           4

[3,1]                           3

[3,2]                           1

[3,4]                           2

[3,5]                           1

[4,1]                           2

[4,2]                           2

[4,3]                           2

[4,5]                           4

[5,2]                           2

[5,3]                           3

伪代码如下:
   

点击(此处)折叠或打开

  1. class Mapper
  2.      method Map(null, items [i1, i2,...] )
  3.         for all item i in [i1, i2,...]
  4.              H = new AssociativeArray : item -> counter
  5.              for all item j in [i1, i2,...]
  6.                 H{j} = H{j} + 1 //统计和item i同时出现的单词的计数
  7.              Emit(item i, stripe H)
  8.  class Reducer
  9.     method Reduce(item i, stripes [H1, H2,...])
  10.         H = new AssociativeArray : item -> counter
  11.         H = merge-sum( [H1, H2,...] ) //按元素进行统计Element-wise sum
  12.         for all item j in H.keys()
  13.             Emit(pair [i j], H{j})

      pairsmap阶段输出的键由于是pair,因此类型多样,不利于conbiners排序,而stripes方法中map输出键为元素个数,减少了排序,且在combiners有更多的机会执行局部聚集,且高效利用内存。总的来说,在维度和数据很大的情况下,stripes性能更优。

但是从可拓展性上来说,Pairs Stripes 有更高的拓展性,因为Paris 产生的Key/Value 的大小总是很小的,所以Paris几乎不存在拓展性问题。但是对于Stripes就不同了。Stripes 产生的Key/Value 的大小依据整个文集的大小。当文集很大时,一个Key/Value Value就会非常的大,有可能一个Mapper无法处理。这样拓展性能问题就显而易见了。

此外,特别注意stripes算法中,map输出为MapWritable类型,不能使用MapHash类型中作为输出输入类型的键值对类型(否则会出现空指针异常错误),可选类型见api库的org.apache.hadoop.io,里面还罗列了许多继承了writeble的数据类型。

还有个问题需要注意,如上Reduce阶段输出:

        [1,2]                           3

        [2,1]                           2

这两个输出,其实是可以合并的,[1,2]     5,因为都是同时购买的商品,只是先后顺序不同,要解决这类问题有2种方法,

1、  在map阶段,对输入数据进行排序。

2、  在map输出阶段,比较输出元素大小,按由小到大的顺序输出

阅读(1240) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~