В Hadoop - составной ключ

Предположим, у меня есть файл с разделителями табуляции, содержащий данные о действиях пользователей формат:

timestamp  user_id  page_id  action_id

Я хочу написать задание hadoop для подсчета действий пользователя на каждой странице, поэтому выходной файл должен выглядеть так:

user_id  page_id  number_of_actions

мне нужно что-то вроде составного ключа здесь - он будет содержать user_id и товары. Есть ли общий способ сделать это с Hadoop? Я не нашел ничего полезного. До сих пор я излучаю ключ, как это в mapper:

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

Это работает, но я чувствую, что это не лучшее решение.

2 ответов


просто составьте свой собственный 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();
  }

}

хотя я думаю, что ваши документы могут быть long, вот вам String версия. В основном просто нормальная сериализация над Writable интерфейс, обратите внимание, что ему нужен конструктор по умолчанию, поэтому вы всегда должны его предоставлять.

на compareTo логика говорит, очевидно, как сортировать набор данных, а также сообщает редуктору, какие элементы равны, чтобы их можно было сгруппировать.

ComparisionChain хороший util гуавы.

не забудьте переопределить equals и hashcode! разделитель будет определять редуктор по хэш-коду ключа.


вы можете написать свой собственный класс, который реализует Writable и WritableComparable, который будет сравнивать ваши два поля.

Пьер-Люк Бертран