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