Хорошая схема для повышения производительности.

MongoDB - это база данных документов, в которой вы можете хранить данные прямо в формате JSON. Запустить и создать приложение с помощью MongoDB очень просто. Тем не менее, это мощный инструмент.

И вы можете использовать его для хранения в нем данных временного ряда.

Вступление

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

В реальном мире есть много ситуаций, в которых используются данные временных рядов:

  • Метеостанция, получающая данные о влажности, температуре и давлении. Вы хотите знать, когда была получена одна заданная температура, чтобы предсказать, нужно ли вам надевать куртку, чтобы выйти на улицу.
  • Аналитик фондового рынка, который использует все курсы акций с течением времени, чтобы провести некоторый анализ и определить возможности.
  • Автомобиль формулы один, который каждую секунду отправляет телеметрическую информацию, такую ​​как скорость, расход топлива, температуры, чтобы инженеры могли рассчитать и сообщить водителю, что делать дальше.

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

Единый документ

Первый метод - хранить все полученные данные как отдельный документ в базе данных. То есть каждая временная метка (или интервал) будет соответствовать записи в базе данных.

Представьте, что у нас есть погодная система, которая ежесекундно выдает данные с датчиков. Образец содержит такие данные, как температура, влажность и давление, а также идентификатор погоды.

Каждый раз, когда информация получена, датчик отправляет ее в базу данных, которая хранит ее как единый документ.

Как видите, есть повторяющаяся или бесполезная информация, например _id и deviceId. Каждую секунду эти две информации будут сохраняться снова и снова, увеличивая размер коллекции.

В нашем сценарии он создаст 3600 документов всего за час, или 86400 в день! Это повлияет на производительность и использование диска.

Вставить его с помощью Python тривиально:

Документ временного диапазона

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

Если сравнивать с предыдущим вариантом, у нас больше полей:

  • d: datetime информация о минуте сбора выборок данных. Если мы хотим, это может быть другое групповое время, например часы или дни. Это будет зависеть от частоты использования наших данных или приложения.
  • nsamples: количество отсчетов, полученных за эту минуту.
  • samples: массив, содержащий все образцы с датчика. Поскольку у нас уже есть информация о временной метке и данные равномерно распределены, мы можем проигнорировать ее и сохранить только фактические данные датчика.

Эти дополнительные поля помогают нам запрашивать данные позже и как способ лучше агрегировать данные.

Чтобы вставить его с помощью Python, мы должны изменить наши данные:

Мы используем функцию update_one вместо insert_one. Он найдет документ с deviceId равным 1 и таким же minute и вставит данные в поле samples.

Если не было найдено ни одного документа с такими характеристиками (то есть новая минута), будет создан новый документ.

Примечание: убедитесь, что в функцию передан флаг upsert=True, иначе она не создаст новый документ.

Документ с ведром размера

Некоторые данные генерируются с нерегулярными временными интервалами, и некоторые датчики могут предоставить больше данных, чем другие.

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

В нашем документе есть еще две информации, которые помогут с запросами и агрегированием позже:

  • first: метка времени первых данных, вставленных в поле samples;
  • last: отметка времени последних данных, вставленных в поле samples;

Примечание: при желании мы можем получить другие данные, например максимальные и минимальные значения.

Чтобы вставить его, он почти такой же, как и наши предыдущие данные. Мы должны изменить, чтобы мы могли вычислить данные, которые нам нужны:

Мы снова используем функцию update_one, но теперь сравнение будет с полем nsamples: оно должно быть меньше 200 (размер нашего сегмента, вы можете выбрать любое значение) и с тем же значением deviceId.

Мы используем операторы $min и $max для автоматического вычисления минимального и максимального значений временных меток вставленных данных.

Последние мысли

Давайте сравним три коллекции, которые мы создали.

Примерно через час после сбора данных у нас есть несколько хороших выводов:

  • Коллекция single на 65% больше, чем time_bucket. Если бы мы взяли больше данных, разница могла бы быть еще больше.
  • Поскольку коллекция size_bucket содержит больше информации, общий размер превышает time_bucket. Но даже в этом случае он намного меньше, чем single.
  • Для равномерно разнесенных данных, как в нашем случае, time_bucket - лучший подход, поскольку в нем меньше информации, которую нужно сохранить.

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

А с Python их легко вставить в базу данных, почти без усилий.

Вы можете создать API с красивым фреймворком FastAPI, как объясняется в этой статье:



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