MapReduce в MongoDB не уменьшает все пары k-v с одним и тем же ключом за один раз - PullRequest
0 голосов
/ 30 октября 2018

Я импортировал БД из CSV с информацией о:

  • страна
  • регион
  • 1008 * товарный *
  • цена
  • дата

(Это CSV: https://www.kaggle.com/jboysen/global-food-prices)

строки в CSV упорядочены следующим образом:

  • страна 1, регион 1.1, товар X, цена, датаA
  • страна 1, регион 1.1, товар X, цена, дата B
  • страна 1, регион 1.1, товар Y, цена, датаA
  • страна 1, регион 1.1, товар Y, цена, дата B
  • ...
  • страна 1, регион 1.2, товар X, цена, датаA
  • страна 1, регион 1.2, товар X, цена, дата B
  • страна 1, регион 1.2, товар Y, цена, датаA
  • страна 1, регион 1.2, товар Y, цена, дата B
  • ...
  • страна 2, регион 2.1, товар X, цена, датаA
  • ...

Мне нужно показать для каждой страны, для каждого продукта самую большую цену.

Я написал:

1) карта с указанием ключевой страны + цена товара и стоимости

var map = function() {
   emit({country: this.country_name, commodity: this.commodity_name}, {price: this.price});
};

2) снижение, которое сканирует цены, связанные с ключом, и проверяет, какая цена самая высокая

var reduce = function(key, values) {

   var maxPrice = 0.0;

   values.forEach(function(doc) {
      var thisPrice = parseFloat(doc.price);
      if( typeof doc.price != "undefined") {
            if (thisPrice > maxPrice) {
               maxPrice = thisPrice; 
            }
      }
   });

   return {max_price: maxPrice};
};

3) Я отправляю вывод карты уменьшить в коллекцию "mr"

db.prices.mapReduce(map, reduce, {out: "mr"});

ПРОБЛЕМА:

Например, если я открою csv и вручную закажу:

  • страна (в порядке возрастания)
  • товар (в порядке возрастания)
  • цена (в порядке убывания)

Я могу проверить, что (для примера) в Афганистане самая высокая цена на товарный хлеб - 65,25

.

Когда я проверяю M-R, он выдает 0 для максимальной цены на хлеб в Афганистане.

ЧТО ПРОИСХОДИТ:

В CSV есть 10 регионов, в которых Хлеб зарегистрирован для Афганистана. Я добавил в последней строке уменьшения:

print("reduce with key: " + key.country + ", " + key.commodity + "; max price: " + maxPrice);

Теоретически, если я ищу в журнале mongodb, я должен найти только ОДИН вход с "уменьшить с помощью ключа: Афганистан, Хлеб; максимальная цена: ???". Вместо этого я вижу десять линий (одинаковые номера регионов), каждая из которых имеет свою максимальную цену. Последний имеет "максимальную цену 0".

МОЙ ГИПОТЕЗ:

Похоже, что после emit, когда вызываетсяужение, вместо поиска ВСЕХ пар k-v с одним и тем же ключом, он рассматривает подгруппы, находящиеся в расплывчатости.

Итак, вспоминая мой начальный пример структуры csv:

  • до тех пор, пока при сканировании с уменьшением не выдаст выходные данные, относящиеся к "афганисте, регион 1, хлеб", он не уменьшит их
  • затем сокращаются результаты, связанные с "Афганистаном, регион 1, товаромX"
  • затем он еще раз сокращает результаты, относящиеся к «Афганистану, регион 2, хлеб» (вместо сокращения ВСЕХ пар k-v с Афганистаном + хлеб за одно сокращение)

Нужно ли выполнять повторное сокращение, чтобы работать на всех работах с частичным сокращением?

1 Ответ

0 голосов
/ 30 октября 2018

Мне удалось решить это. MongoDB не обязательно сокращает все пары k-v одним и тем же ключом за один раз.

Может случиться, что (как в этом случае) MongoDB выполнит уменьшение для подмножества пар kv, связанных с конкретным ключом, а затем отправит выходные данные этого первого уменьшения, когда выполнит второе уменьшение для другого подмножество, связанное с тем же ключом.

Мой код не работал, потому что:

  • MongoDB выполнил уменьшение поднабора пар k-v, связанных с ключом «Афганистан, хлеб», с помощью выходной переменной с именем «maxPrice»
  • MongoDB продолжит сокращать другие подмножества
  • MongoDB, столкнувшись с другим подмножеством «Афганистан, Хлеб», получит результат первого сокращения и использует его в качестве значения
  • Результат редукции называется «maxPrice», а остальные значения называются «цена»
  • Поскольку я запрашиваю значение «doc.price», при сканировании документа, содержащего «maxPrice», он игнорируется

Есть 2 подхода для решения этой проблемы:

1) Вы используете то же имя для выходной переменной сокращения, что и для выходного значения emit

2) Вы индексируете свойства, выбранные в качестве ключа, и используете опцию «sort» в mapReduce (), чтобы все пары k-v, связанные с ключом, сокращались за один раз

Второй подход заключается в том, что если вы не хотите отказываться от использования другого имени в качестве имени сокращения (плюс оно имеет лучшую производительность, поскольку выполняет только одно сокращение на ключ).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...