Mengdong的技术博客

学习,记录,分享

导航

统计

公告

分治法解决MapReduce stripe模式内存瓶颈问题

本文内容基于之前的一篇博文Data-intensive Text Processing with MapReduce读书笔记第3MapReduce算法设计(2):pair模式与stripe模式。这一节的末尾提出一个问题:

stripe模式因为需要在mapper内维护一个关联数组,因此无法处理语料的词汇表非常大的情况。

随后文章给出了一个解决思路:划分词汇表。但没有给出具体解决方法。

本文针对这个思路,谈一谈如何通过划分词汇表的方式解决stripe模式存在的内存瓶颈。本文仅从抽象算法的层面对这个思路进行细化,不涉及具体的程序设计。

因为条件所限,我目前尚无hadoop编程经验。空谈难免会有错误之处,还希望广大朋友不吝指正。

共现矩阵计算

关于共现矩阵的定义在此不再赘述,可参见本文开始给出的链接或是Wikipedia中的定义.

简单地说,计算共现矩阵的算法输入一组单词共现对输出共现矩阵

例如对于如下的共现对输入(简单起见单词均用斜体数字代替):

文档1 (1,2) (1,2) (1,3) (2,3)

文档2 (2,4) (1,4) (3,4)

输出共现矩阵(共现对计数):

(1,2):2 (1,3):1 (2,3):1 (2,4):1 (1,4):1 (3,4):1

回顾stripe模式

首先来回顾一下应用stripe模式计算单词共现矩阵的过程:

stripe模式在mapper内对于当前单词wi维护一个关联数组(可以是哈希表,treemap等k-v结构)H. 在H中,k是与wi存在共现关系的单词wjv是共现对(wi,wj)的计数,例如对于上面给出的实例,当处理文档1时,mapper有如下处理过程:

wi

wj

H

操作

 

 

{}

H初始化

1

2

{2:1}

H[2] ++

 

2

{2:2}

H[2] ++

 

3

{2:2,3:1}

H[3] ++

 

 

 

输出(1,H)

 

 

{}

H初始化

2

3

{3:1}

H[3] ++

 

 

 

输出(2,H)

随后,reducer接受(w, [H1,H2,H3...]),合并H1,H2,H3...后输出结果,共现矩阵计算完毕。

内存瓶颈从何而来?

单词表很大的情况下,每个文档可能包含的单词量非常多。此时对于每个wi,可能都有非常多的单词与之共现。假如对于每个单词wi,与之共现的不同的wj单词数平均是一个相对于词汇表规模的固定比例r(例如1%),那么对于规模为n的单词表,维护对于一个特定单词wi的H平均需要存储r×n个k-v对,如果H的空间利用率是常数的话(例如50%或100%),那么维护H的空间开销是O(n).

简而言之,词汇表变得很大,从而导致与每个wi共现的不同wj很多,最终导致H变得很大。考虑stripe的应用情境:mapper内维护H,可以得出stripe受限于单机内存容量的结论(一个mapper任务在一台机器上运行)。因此stripe虽然高效(较之pair),却不能直接应用于词汇表很大的语料数据。

分治解决内存瓶颈

那么有没有办法解决这个问题呢?原书中小节末尾给出了一个划分词汇表的解决方法。

如何划分呢?内存瓶颈问题的本质是每个wi需要维护的wj太多了,导致H过大,如下图所示:

为了简单的考虑,我们先假设这r×nwj均匀分布在整个词汇表区间里,如果能对这个词汇表做划分,那么就可以减少一次需要统计的wj的数量,从而减小H. 划分如下图所示:

将词汇表划分为b个桶后,对于每个桶单独统计,就可以减小H. 而b的值是可变的,这样即使是再大的词汇表,也可以通过增大b缩小需要一次处理的词汇表大小,使得stripe模式能够应用至任意大小的词汇表。

算法实现

分治可以通过在原有的stripe算法上增加一次预处理实现,预处理的功能即为划分词汇表:

class Mapper

  method Map(docid a, doc d)

    for all term w in doc d do

      for all term u in Neighbors(w) do

        barrel←hash(u) mod b // 划为b个子区间

        Emit(barrel, (a, (w, u)))

class Reducer

  method Reducer(barrel b, (docid a, (term w, term u)))

    Emit(a, (w, u))

经过预处理后,数据集被划分为b个子数据集,其中第i个数据集中只包含(wi,wj),其中hash(wj) mod b = i. 然后对这b个数据集分别使用stripe算法计算共现矩阵。由于数据集根据wj划分,可知每个数据集的计算结果都是最终全局共现矩阵的其中几列,而数据集之间的计算结果无交集。因此只需要将各数据集的结果简单合并即可得到全局共现矩阵,如下图所示。

posted on 2011-07-21 16:15 mdyang 阅读(...) 评论(...) 编辑 收藏