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

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

timestamp  user_id  page_id  action_id

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

user_id  page_id  number_of_actions

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

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

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

Ответ 1

Просто создайте свой собственный 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 - хороший сервис Guava.

Не забудьте переопределить равные и хэш-коды! Разделитель определит редуктор по хэш-коду ключа.

Ответ 2

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

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