MongoDB Map-Reduce: один документ, который необходимо включить во все остальные, соответствующие условию? - PullRequest
4 голосов
/ 17 февраля 2020

Даже не уверен в правильной терминологии, которую можно использовать, чтобы задать этот вопрос, но здесь у нас go.

У меня есть коллекция, на которой я использую MapReduce для выполнения задачи агрегирования. Я не могу использовать конвейер агрегации, потому что мне нужно выполнить пользовательский код при сокращении.

Это немного упрощено, чтобы сделать вопрос более понятным.

  • У меня есть коллекция, где каждый документ содержит местоположение (т. е. идентификатор ячейки сетки) и отрезок времени (обозначенный меткой времени в начале этого отрезка времени) и содержит такую ​​информацию, как «количество автомобилей» и т. д .; для каждого местоположения может быть несколько тысяч таких документов, а также может быть несколько на отрезок времени.
  • Кроме того, для каждого местоположения могут быть документы, в которых свойство «отрезок времени» равно нулю. Он содержит информацию о функциях stati c и т. Д., Т. Е. Данные, с которыми не связана временная метка.

Я хочу запустить процесс сокращения карты, где выходные документы снабжаются ключом по идентификатору местоположения и интервалу времени, и, что особенно важно, я могу объединить несвязанные данные с синхронизированными данными.

Вот несколько примеров ввода (очень упрощенного с точки зрения данных , но значения cell_id и timeslice - это именно то, с чем мне нужно работать):

[
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 5,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 4,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 1,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 7,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 2,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 100,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 5,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 1,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 2,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 1,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 0,
    "num_residential_units": null,
    "num_commercial_units": null
  },
  {
    "cell_id": 101,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 10,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 9,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 5,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 4,
    "num_residential_units": 8,
    "num_commercial_units": 1
  }
]

... и вывод, который я хотел бы получить для этого ввода (я не разбивал это в _id и value, но, по сути, cell_id и timeslice будут _id:

[
  {
    "cell_id": 100,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 10,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 100,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 9,
    "num_residential_units": 30,
    "num_commercial_units": 12
  },
  {
    "cell_id": 101,
    "timeslice": null,
    "num_vehicles": null,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-20T00:00:00.000Z",
    "num_vehicles": 5,
    "num_residential_units": 8,
    "num_commercial_units": 1
  },
  {
    "cell_id": 101,
    "timeslice": "2019-03-21T00:00:00.000Z",
    "num_vehicles": 4,
    "num_residential_units": 8,
    "num_commercial_units": 1
  }
]

Если на этапе Emit вводятся ключи для документов по местоположению и времени, то У меня есть все синхронизированные данные, превращающие их в функцию сокращения должным образом, и у меня есть несвязанные данные, сокращаемые самостоятельно ... но мне нужно каким-то образом также включить эти несвязанные данные в каждый отдельный документ сокращенных синхронизированных данных. способ сделать это на этапе финализации, или есть какой-то умный способ настройки ключей ...? Я в тупике. Честно говоря, для меня не имеет значения, включает ли решение даже сокращение карты, но оно должно быть эффективным в больших масштабах на ограниченном оборудовании.

Ответы [ 2 ]

0 голосов
/ 25 февраля 2020

Вот подход, который может помочь вам решить эту проблему. Предположение: на основе предоставленных вами данных выглядит для каждого ячейки, есть одна запись с нулевым временным интервалом.

  1. Фильтруйте ваши данные основанный на нулевых и не нулевых значениях временного интервала. Это даст вам два набора данных.
  2. Выполните объединение на основе Cellid для этих двух наборов данных. Это объединит строки с ненулевым временным интервалом и строку с нулевым временным интервалом.
  3. Наконец, сгруппируйте по объединенному набору данных, используя cellid и timeslice. Вы можете запустить уменьшение для каждой группы, в которой будет ячейка с нулевым временным интервалом. Тем не менее, поскольку эта строка соединяется с каждой другой строкой, вам придется обрабатывать дубликаты в своем сокращении. Вы можете сделать это, возможно, установив флаг, который вы уже учли для строки, с нулевым временным интервалом.

Я приложил сюда картинку, которая может помочь вам понять, что я имею в виду. Обратите внимание, что для простоты я показал только столбцы CellId и timestamp.

enter image description here

0 голосов
/ 21 февраля 2020

Вы можете попробовать что-то вроде этого.

В приведенном ниже запросе будут собраны не пустые строки меток времени, за которыми следует группа, чтобы получить агрегированные значения. После того, как вы скомбинируете do c, вы присоединитесь к той же коллекции, чтобы вытащить несвязанный ряд.

db.collection.aggregate([
  {"$match":{"timeslice":{"$ne":null}}},
  {"$group":{
      "_id":{"cell_id":"$cell_id","timeslice":"$timeslice"},
      "num_vehicles":{"$sum":"$num_vehicles"}
  }},
  {"$lookup":{
     "from":"collection",
     "localField":"_id.cell_id",
     "foreignField":"cell_id",
     "as":"untimed_doc"
   }},
  {"$unwind":"$untimed_doc"},
  {"$match":{"untimed_doc.timeslice":{"$eq":null}}}
])
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...