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, чтобы получить последнее значение за день.
Если мы создадим документы со всеми значениями, заполненными заполнением заранее, мы можем быть уверены, что документ не изменит размер и поэтому не будет перемещен.