То, что вы делаете выше, также должно работать, но это предполагает, что все данные для одного ключа поместятся в памяти. Если это так, то в Reducer вы можете хранить все значения в памяти, а затем вычислять общую сумму, чтобы затем вычислить маргинал для каждой пары ключ-значение. Это широко известно как подход «полос».
Однако в большинстве случаев это может быть правдой, и данные могут не помещаться в памяти. В этом случае вам нужно будет найти способ отправки значений для вычисления общей суммы перед фактической парой ключ-значение, чтобы, когда их можно было использовать для вычисления маргинала и сразу же выдавать значение.
Это кандидат на шаблон проектирования "порядок инверсии". Это полезно, когда вам нужно рассчитать относительные частоты. Основная идея заключается в том, что в конце Mapper вы создаете 2 пары ключ-значение для каждых промежуточных данных, где одна из пар ключ-значение будет иметь один и тот же общий ключ для всех значений. Это будет использоваться для расчета суммы.
Пример:
For a, (r, 5) :
---------------
emit (a, r), 5
emit (a, *), 5
For a, (e, 6) :
---------------
emit (a, e), 6
emit (a, *), 6
For a, (w, 7) :
---------------
emit (a, w), 7
emit (a, *), 7
Как только это будет сделано, вам понадобится разделитель, который разделит каждую промежуточную пару ключ-значение, используя только первое значение в ключе. В приведенном выше примере используется «а».
Вам также понадобится порядок сортировки ключей, который всегда ставит ключ, имеющий * во второй части ключа, выше всех.
Таким образом, все промежуточные ключи, имеющие «a» в первой части ключа, попадут в один и тот же редуктор. Кроме того, они будут отсортированы так, как показано ниже:
emit (a, *), 5
emit (a, *), 6
emit (a, *), 7
emit (a, e), 6
emit (a, r), 5
emit (a, w), 7
В редьюсере, когда вы перебираете пары ключ-значение, вам нужно будет просто накапливать значения из ключей, если они имеют * во второй части ключа. Затем вы можете использовать накопленное значение для расчета маргинала для всех остальных пар ключ-значение.
total = 0
for(value : values){
if (key.second == *)
total += value
else
emit (key.first , key.second, value, value/total)
}
Этот шаблон проектирования широко известен как порядок инверсии, в котором используется парный подход. Для получения дополнительной информации об этом и других шаблонах проектирования я бы посоветовал прочитать главу о шаблонах проектирования MapReduce в этой книге — http://lintool.github.com/MapReduceAlgorithms/. Это очень хорошо объяснено с примерами.
person
Pai
schedule
25.03.2013