Можно ли обнаруживать и обрабатывать конфликты строк между сгруппированными значениями при группировании в Hadoop Pig?

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

Alice\tApple
Bob\tApple
Charlie\tGuava
Alice\tOrange

Я хотел бы создать запрос свиньи, который показывает любимый фрукт каждого пользователя. Если пользователь появляется несколько раз, я бы хотел показать «Несколько». Например, результат с приведенными выше данными должен быть:

Alice\tMultiple
Bob\tApple
Charlie\tGuava

В SQL это можно сделать примерно так (хотя это не обязательно будет работать очень хорошо):

select user, case when count(fruit) > 1 then 'Multiple' else max(fruit) end
from FruitPreferences
group by user

Но я не могу понять эквивалент PigLatin. Есть идеи?


person Chris Phillips    schedule 13.09.2011    source источник
comment
Я должен отметить, что эта проблема похожа на другой вопрос, который я задал, но отличается от него: stackoverflow .com/questions/7406522/   -  person Chris Phillips    schedule 13.09.2011


Ответы (1)


Напишите "Агрегатная функция" Pig UDF (прокрутите вниз до "Агрегатные функции"). Это определяемая пользователем функция, которая берет сумку и выводит скаляр. Таким образом, ваша UDF будет брать в сумку, определять, есть ли в ней более одного элемента, и соответствующим образом преобразовывать ее с помощью оператора if.

Я могу придумать способ сделать это без UDF, но это определенно неудобно. После вашего GROUP используйте SPLIT, чтобы разделить набор данных на два: один, в котором счетчик равен 1, и другой, в котором счетчик больше единицы:

SPLIT grouped INTO one IF COUNT(fruit) == 0, more IF COUNT(fruit) > 0;

Затем отдельно используйте FOREACH ... GENERATE для каждого, чтобы преобразовать его:

one = FOREACH one GENERATE name, MAX(fruit); -- hack using MAX to get the item
more = FOREACH more GENERATE name, 'Multiple';

Наконец, объедините их обратно:

out = UNION one, more;

На самом деле я не нашел лучшего способа обработки одного и того же набора данных двумя разными способами на основе некоторых условных выражений, как вы хотите. Обычно я делаю какое-то разделение/рекомбинацию, как здесь. Я верю, что Свин будет умным и составит план, который не использует более 1 работы M/R.

Отказ от ответственности: в данный момент я не могу протестировать этот код, поэтому в нем могут быть ошибки.


Обновлять:

Присмотревшись повнимательнее, я вспомнил оператор bicond, и я думаю, что это будет работать здесь.

b = FOREACH a GENERATE name, (COUNT(fruit)==1 ? MAX(FRUIT) : 'Multiple');
person Donald Miner    schedule 14.09.2011
comment
Круто, я не был уверен, сработает ли для этого оператор bicond или нет — сначала попробую. В противном случае я вернусь к описанному вами методу разделения/объединения. - person Chris Phillips; 14.09.2011