MongoDB как база данных временных рядов

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

Данные временных рядов очень похожи на историю цен на акции. У меня есть набор данных из различных датчиков, взятых с разных машин. Существуют значения в миллиард временных меток, и я хотел бы задать следующие вопросы (желательно из базы данных, а не уровня приложения):

  • Для данного набора датчиков и временного интервала я хочу, чтобы все временные метки и значения датчиков находились в пределах этого интервала по времени. Предположим, что все датчики имеют одни и те же метки времени (все они были отобраны одновременно).

  • Для данного набора датчиков и временного интервала я хочу, чтобы каждый k-й элемент (метка времени и соответствующие значения датчика) лежал в пределах заданного интервала по времени.

Любая рекомендация о том, как наилучшим образом настроить это и выполнить запросы?

Спасибо за предложения.

Ответ 1

Если вам не нужно хранить данные навсегда (т.е. вы не возражаете против этого "стареет" ), вы можете захотеть рассмотреть "ограниченную коллекцию". Capped коллекции имеют ряд ограничений, которые, в свою очередь, предоставляют некоторые интересные преимущества, которые звучат так, как будто они соответствуют тому, что вы хотите достаточно хорошо.

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

Результат заключается в том, что вам гарантировано, что данные в вашей закрытой коллекции будут записаны и останутся на диске в порядке размещения, что очень быстро делает запросы по порядку вставки.

Насколько различны датчики и данные, которые они производят, между прочим? Если они относительно похожи, я бы предложил сохранить их все в одной коллекции для удобства использования - иначе их разделить.

Предполагая, что вы используете одну коллекцию, ваши запросы тогда звучат очень выполнимо. Одна вещь, о которой нужно помнить, состоит в том, чтобы получить выгоду от собранной коллекции, которую вам нужно было бы запросить в соответствии с естественным порядком коллекций, поэтому запрос с помощью ключа временной метки не будет таким быстрым. Если показания берутся через регулярные промежутки времени (поэтому вы знаете, сколько из них будет принято за определенный промежуток времени), я бы предложил примерно следующее для запроса 1:

db.myCollection.find().limit(100000).sort({ $natural : -1 })

Предполагая, например, что вы сохраняете 100 показаний в секунду, вышесказанное вернет данные за последние 100 секунд. Если вы хотели использовать предыдущие 100 секунд, вы можете добавить .skip(100000).

Для вашего второго запроса мне кажется, что вам понадобится MapReduce, но это звучит не очень сложно. Вы можете выбрать диапазон интересующих вас документов с похожим запросом к одному выше, а затем выбрать только те, которые вас интересуют с помощью функции map.

Здесь Mongo Docs на закрытых коллекциях: http://www.mongodb.org/display/DOCS/Capped+Collections

Надеюсь, это поможет!

Ответ 2

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

Представьте, что вы храните данные каждую минуту. Рассмотрим следующую структуру документа:

{
  timestamp: ISODate("2013-10-10T23:06:37.000Z"),
  type: "spot_EURUSD",
  value: 1.2345
},
{
  timestamp: ISODate("2013-10-10T23:06:38.000Z"),
  type: "spot_EURUSD",
  value: 1.2346
}

Это сопоставимо с стандартным реляционным подходом. В этом случае вы создаете один документ на записанное значение, что вызывает много операций вставки. Мы можем сделать лучше. Рассмотрим следующее:

{
  timestamp_minute: ISODate("2013-10-10T23:06:00.000Z"),
  type: "spot_EURUSD",
  values: {
    0: 1.2345,
    …  
    37: 1.2346,
    38: 1.2347,
    … 
    59: 1.2343
  }
}

Теперь мы можем написать один документ и выполнить 59 обновлений. Это намного лучше, потому что обновления являются атомарными, отдельные записи меньше, и есть другие преимущества производительности и concurrency. Но что, если мы хотим хранить весь день, а не только целый час, в одном документе. Тогда это потребует от нас пройти 1440 записей, чтобы получить последнее значение. Чтобы улучшить это, мы можем перейти к следующему:

{
  timestamp_hour: ISODate("2013-10-10T23:00:00.000Z"),
  type: "spot_EURUSD",
  values: {
    0: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    1: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    …,
    22: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343},
    23: { 0: 1.2343, 1: 1.2343, …, 59: 1.2343}
  }
}

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

Если мы создадим документы со всеми значениями, заполненными заполнением заранее, мы можем быть уверены, что документ не изменит размер и поэтому не будет перемещен.