В 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, который будет сравнивать ваши два поля.
Пьер-Люк Бертран
