Hadoop map-reduce中中值的计算

Hadoop map-reduce中中值的计算,hadoop,statistics,mapreduce,apache-pig,median,Hadoop,Statistics,Mapreduce,Apache Pig,Median,有人能举例说明map reduce中中值/分位数的计算吗 我对Datafu中值的理解是“n”映射器对 并将数据发送至负责分拣的“1”减速器 从n个制图器中获取所有数据并找到中值(中间值) 我的理解正确吗 如果是,这种方法是否适用于 大量的数据,因为我可以清楚地看到一个单一的减速机 努力完成最后的任务。 感谢要在一系列中找到中间值(中间值),需要将1个减速机传递给整个数字范围,以确定哪个是“中间”值 根据输入集中值的范围和唯一性,可以引入组合器来输出每个值的频率,从而减少发送到单个减速机的映射输出

有人能举例说明map reduce中中值/分位数的计算吗

我对Datafu中值的理解是“n”映射器对 并将数据发送至负责分拣的“1”减速器 从n个制图器中获取所有数据并找到中值(中间值) 我的理解正确吗

如果是,这种方法是否适用于 大量的数据,因为我可以清楚地看到一个单一的减速机 努力完成最后的任务。 感谢

要在一系列中找到中间值(中间值),需要将1个减速机传递给整个数字范围,以确定哪个是“中间”值

根据输入集中值的范围和唯一性,可以引入组合器来输出每个值的频率,从而减少发送到单个减速机的映射输出的数量。然后,减速机可以使用排序值/频率对来识别中值

另一种扩展方法(如果您知道值的范围和粗略分布,请再次使用)是使用自定义分区器,该分区器按范围存储桶(0-99转到reducer 0,100-199转到reducer 2,依此类推)分配键。但是,这将需要一些辅助工作来检查减速器输出并执行最终的中值计算(例如,知道每个减速器中的键数,可以计算哪个减速器输出将包含中值,以及在哪个偏移量)

O((n log n)/p)对其排序,然后O(1)获得中值

是的。。。您可以获得O(n/p),但不能使用Hadoop中的开箱即用排序功能。除非你能证明2-20小时的开发时间来编码并行的第k个最大算法,否则我只需要排序并获取中心项。

你真的需要精确的中位数和分位数吗

很多时候,您最好只获取近似值,并使用它们,特别是在您将其用于数据分区的情况下

事实上,您可以使用近似分位数加快查找精确分位数的速度(实际上是在
O(n/p)
时间内),下面是该策略的大致轮廓:

  • 让每个分区的映射器计算所需的分位数,并将它们输出到新的数据集。这个数据集应该小几个数量级(除非你要求太多的分位数!)
  • 在此数据集中,再次计算分位数,类似于“中间值的中值”。这是你的初步估计
  • 根据这些分位数(或通过这种方式获得的附加分区)重新划分数据。目标是最终保证真正的分位数在一个分区中,并且每个分区中最多应有一个所需的分位数
  • 在每个分区中,执行快速选择(在
    O(n)
    中)以查找真正的分位数
  • 每个步骤都是线性时间。最昂贵的步骤是第3部分,因为它需要重新分配整个数据集,因此它会生成
    O(n)
    网络流量。
    您可能可以通过为第一次迭代选择“备用”分位数来优化该过程。比如说,你想找到全球中值。在线性过程中很难找到它,但当它被划分为k个分区时,可以将其缩小到数据集的1/kt。因此,与其让每个节点报告其中值,不如让每个节点另外报告(k-1)/(2k)和(k+1)/(2k)处的对象。这将允许您缩小真实中值必须显著位于的值范围。因此,在下一步中,您可以让每个节点将所需范围内的对象发送到单个主节点,并仅选择该范围内的中间值。

    在许多真实场景中,数据集中的值基数相对较小。在这种情况下,可以通过两个MapReduce作业有效地解决问题:

  • 计算数据集中值的频率(基本上是字数计算作业)
  • 身份映射器+基于<值-频率>对计算中值的减缩器
  • 工作1。将大大减少数据量,并且可以完全并行执行。工作2的减速器。只需处理
    n
    n
    =
    值集的基数
    )项,而不必像原始方法那样处理所有值

    下面是作业2的示例。这是可以直接用于Hadoop流的python脚本。假设数据集中的值为
    ints
    ,但可以很容易地用于
    double
    s

    import sys
    
    item_to_index_range = []
    total_count = 0
    
    # Store in memory a mapping of a value to the range of indexes it has in a sorted list of all values
    for line in sys.stdin:
        item, count = line.strip().split("\t", 1)
        new_total_count = total_count + int(count)
        item_to_index_range.append((item, (total_count + 1,   new_total_count + 1)))
        total_count = new_total_count
    
    # Calculate index(es) of middle items
    middle_items_indexes = [(total_count / 2) + 1]
    if total_count % 2 == 0:
        middle_items_indexes += [total_count / 2]
    
    # Retrieve middle item(s) 
    middle_items = []
    for i in middle_items_indexes:
        for item, index_range in item_to_index_range:
            if i in range(*index_range):
                middle_items.append(item)
                continue
    
    print sum(middle_items) / float(len(middle_items))
    
    这个答案建立在最初来自of的建议之上。答案建议使用组合器作为计算值频率的平均值。然而,在MapReduce中,组合器不能保证总是执行。这有一些副作用:

    • 减速器首先必须计算最终<值-频率>对,然后计算中值
    • 在最坏的情况下,组合器将永远不会执行,减速机仍将不得不处理所有单个值

    在这种方法中,找到精确的分位数可能非常昂贵,但可能比单纯的方法要好。第1步到第4步实际帮助将集合分成两半,并在较小的空间内解决相同的问题。但在这种方法中,可能需要步骤1到步骤4的logn迭代才能得到分位数。