将ID映射到Hadoop/MapReduce中的矩阵行

将ID映射到Hadoop/MapReduce中的矩阵行,hadoop,matrix,mapreduce,uniqueidentifier,unique-index,Hadoop,Matrix,Mapreduce,Uniqueidentifier,Unique Index,我有用户购买产品的数据。我想创建一个大小为| users |x| products |的二进制矩阵,这样矩阵中的元素(I,j)在user|I购买了product|j时为1,否则值为0 现在,我的数据看起来像 userA, productX userB, productY userA, productZ ... 1,1 2,2 1,3 userid和productid都是字符串。我的问题是,如何将这些ID映射到矩阵中的行索引(对于用户)和列索引(对于产品) 有超过一百万个独特的用户ID和大约三

我有用户购买产品的数据。我想创建一个大小为
| users |
x
| products |
的二进制矩阵,这样矩阵中的元素
(I,j)
user|I
购买了
product|j
时为1,否则值为0

现在,我的数据看起来像

userA, productX
userB, productY
userA, productZ
...
1,1
2,2
1,3
userid和productid都是字符串。我的问题是,如何将这些ID映射到矩阵中的行索引(对于用户)和列索引(对于产品)

有超过一百万个独特的用户ID和大约三百万个产品ID

为了更好地定义问题:给定上面类似的
user1,product1
输入,如何将其转换为类似的内容

userA, productX
userB, productY
userA, productZ
...
1,1
2,2
1,3
其中,
userA
映射到矩阵的第0行,
userB
映射到第1行,
productX
映射到第0列,依此类推

考虑到数据的大小,我不得不使用Hadoop Map Reduce,但无法想出一种简单有效的方法

如果我们能做到以下几点,就可以解决这个问题:

  • 转储唯一的用户标识
  • 转储唯一的ProductID
  • 将(1)中的每个唯一用户标识映射到行索引
  • 将(2)中的每个唯一productId映射到列索引
  • 我可以很容易地完成(1)和(2),但很难想出一个有效的方法来解决(3)(如果我们解决了3,4就会解决)

    我有几个解决方案,但它们不是万无一失的

    以上步骤3的解决方案1(简单)

    • 映射所有用户标识,并为所有映射任务发出相同的键(如“1”)
    • 在减速器的
      setup()
      中,将
      long
      计数器初始化为0
    • reduce()
      中,将计数器值与输入的userId一起发出,并将计数器增加1
    这将是非常低效的,因为所有1亿个用户ID都将由一个reducer处理

    以上步骤3的解决方案2

    • 映射userId时,根据一个键发出每个userId,该键是从1,2,3…N中统一采样的整数(其中N是可配置的。例如,N=100)。在某种程度上,我们正在对输入集进行分区
    • 在映射程序中,使用Hadoop计数器计算分配给每个随机分区的用户ID的数量
    • 在reducer设置中,首先在映射阶段访问计数器,以确定为每个分区分配了多少ID。使用这些计数器确定该分区的
      start
      end
    • reduce
      中迭代(计数)每个用户标识,并将矩阵rowId生成为
      start\u分区
      +
      计数器
    • write(用户Id、矩阵行Id)
    这种方法应该有效,但我不确定如何处理reducer任务失败/终止的情况


    我相信应该有一些我不知道的方法。我们可以使用散列/模来实现这一点吗?我们将如何处理比例冲突?

    首先在映射阶段访问计数器
    这将无法正常工作。我建议在本例中使用spark并使用
    zipWithIndex()
    ,它使整个任务基本上有3-4行代码。如果您对它的工作原理感到好奇的话。它并行地对所有分区进行计数,然后在下一阶段,它只使用每个分区的长度来生成每个分区的索引偏移量和每行的增量。这相当于有两个仅映射作业,其中通过configs或hdfs文件传输索引信息
    zipwithIndex
    似乎是解决方案。然而,我不知道如何用
    1,1
    替换
    userA,productX
    zipWithIndex
    将如何替换产品ID?你有一些示例代码吗?你需要在产品名称本身上加入产品名称和zipWithIndex结果,这将在该列中为你提供索引。谢谢@ThomasJungblut。
    首先在映射阶段访问计数器
    这不会奏效。我建议在本例中使用spark并使用
    zipWithIndex()
    ,它使整个任务基本上有3-4行代码。如果您对它的工作原理感到好奇的话。它并行地对所有分区进行计数,然后在下一阶段,它只使用每个分区的长度来生成每个分区的索引偏移量和每行的增量。这相当于有两个仅映射作业,其中通过configs或hdfs文件传输索引信息
    zipwithIndex
    似乎是解决方案。然而,我不知道如何用
    1,1
    替换
    userA,productX
    zipWithIndex
    将如何替换产品ID?你有一些示例代码吗?你需要在产品名称本身上加入产品名称和zipWithIndex结果,这将在该列中为你提供索引。谢谢@ThomasJungblut。