11

假设我有一个包含用户活动数据的制表符分隔文件,格式如下:

timestamp  user_id  page_id  action_id

我想编写一个 hadoop 作业来计算每个页面上的用户操作,因此输出文件应如下所示:

user_id  page_id  number_of_actions

我在这里需要像复合键这样的东西——它将包含 user_id 和 page_id。有没有什么通用的方法可以用 hadoop 做到这一点?我找不到任何有用的东西。到目前为止,我在映射器中发出这样的密钥:

context.write(new Text(user_id + "\t" + page_id), one);

它有效,但我觉得这不是最好的解决方案。

4

2 回答 2

14

只需编写自己的Writable. 在您的示例中,解决方案可能如下所示:

public class UserPageWritable implements WritableComparable<UserPageWritable> {

  private String userId;
  private String pageId;

  @Override
  public void readFields(DataInput in) throws IOException {
    userId = in.readUTF();
    pageId = in.readUTF();
  }

  @Override
  public void write(DataOutput out) throws IOException {
    out.writeUTF(userId);
    out.writeUTF(pageId);
  }

  @Override
  public int compareTo(UserPageWritable o) {
    return ComparisonChain.start().compare(userId, o.userId)
        .compare(pageId, o.pageId).result();
  }

}

虽然我认为您的 ID 可能是 a long,但这里有String版本。基本上只是Writable接口上的正常序列化,请注意它需要默认构造函数,因此您应该始终提供一个。

逻辑清楚地告诉了如何对compareTo数据集进行排序,还告诉 reducer 哪些元素是相等的,以便可以对它们进行分组。

ComparisionChainGuava的一个很好的工具。

不要忘记覆盖equals和hashcode!partitioner 将通过 key 的 hashcode 来确定 reducer。

于 2012-09-14T16:17:17.020 回答
1

您可以编写自己的类来实现 Writable 和 WritableComparable 来比较您的两个字段。

皮埃尔-吕克·伯特兰

于 2012-09-14T16:12:01.543 回答