Modelado TimeSeries sobre MongoDB

Introducción

Las series temporales se gestionan en la plataforma a nivel de ontología, ya que se trata de un tipo de datos especial en el que un conjunto de medidas o señales, se agrupan en una o varias ventanas temporales, que permitan su consulta gestión de forma conjunta.

En una ontología de tipo Timeseries, cada inserción en la plataforma se puede considerar como una señal o medida y deberá ir acompañada de un timestamp, que permita agrupar dicho  valor de la señal o medida en su ventana temporal correspondiente.

Una ontología de tipo TimeSeries se caracteriza por que su esquema describe la estructura de las instancias que recibe el IoTBroker, pero no la estructura de las instancias almacenadas en el motor de Base de datos, esto es, y como veremos mas adelante, la plataforma hace una gestión interna de los datos recibidos, para construir una agrupación mas eficiente de las distintas señales.

Conceptos

A la hora de trabajar con TimeSeries en la plataforma, hay que tener en cuenta los siguientes conceptos cuando se crea una ontología:

  • Timestamp: Momento exacto de la medida o señal, es obligatorio en todas las ontologías TimeSeries, de hecho la propia plataforma lo añade de forma transparente por defecto, por lo que no necesario añadir un campo de tipo Timestamp.

  • Etiquetas o Tags: Son las propiedades descriptoras de una señal o medida, pero no la medida en sí. Por ejemplo en una ontología TimeSeries que recibe datos de un contador, el identificador del contador y su titular serán etiquetas o tags.

  • Campos o Fields: Son las propiedades que representan el valor de una señal o medida en un momento dado.

  • Datos Auxiliares: En una ontología TimeSeries, también hay información que pese a estar almacenada en la estructura TimeSeries, es costosa de recuperar en tiempo de procesamiento, debido a la estructura con la que se almacena la información. Por ejemplo, recuperar el último valor recibido, que podria ser un dato muy común, tiene cierto coste computacional en una estructura TimeSeries. Para ello se proporciona la opción Datos auxiliares, que crea otra ontología con el mismo identificador dado a la ontología TimeSeries, junto con el sufijo _stats, de manera que accediendo a la ontología <identificadorOntologia>_stats se disponga de acceso inmediato a dichos datos.

  • Motor de Base de datos: La base de datos que se utilice como soporte para almacenar la serie temporal de la ontología es un aspecto muy importante a considerar, ya que de ello depende la estructura de almacenamiento. En un principio la plataforma da soporte a MongoDB, que ya propone una estructura para este tipo de datos que se describirá en puntos posteriores.

Todos estos conceptos los podemos encontrar a la hora de crear una entidad TimeSeries:

El ultimo concepto importante es el siguiente:

  • Ventanas temporales: Una ontología TimeSeries puede tener diferentes ventanas temporales. Una ventana temporal es la unidad de tiempo en la que se agrupan las señales o medidas recibidas. Pudiendo ser:

    • Minutal.

    • Horaria.

    • Diaria.

    • Mensual.

Una vez seleccionada la unidad de la ventana, se selecciona la frecuencia de muestreo, eso es, con qué frecuencia se almacenan señales o medidas (muestras) en la ventana. La frecuencia puede ser (siempre en una unidad inferior a la de la ventana):

  • Segundos.

  • Minutos.

  • Horas.

  • Dias.

  • Meses.

Además, como función de agregado, se puede indicar que política aplicar cuando se reciben varias medidas o señales para el mismo instante temporal en la ventana.

Persistencia en MongoDB

Como Base de datos de referencia para almacenar TimeSeries se ha elegido MongoDB, no obstante queda abierto a introducir nuevos sistemas gestores de base de datos en el futuro.

Una ontología TimeSeries cuyo soporte físico es MongoDB tiene las siguientes características:

  • Se crea una colección en MongoDB para dar soporte al almacenamiento de los datos.

  • Cuando se recibe una instancia de una ontología TimeSeries, se recupera su timestamp y se comprueba para cada ventana temporal que tenga definida en plataforma, si ya existe un documento en MongoDB para dicha señal y timestamp. Para ello se lanza una query con todos los tags o etiquetas con el valor recibido en estas y por el timestamp de cada ventana. Si existe un documento, este se actualiza en la entrada correspondiente al momento de la señal recibida. Si no existe, se crea un documento con las señales de todos los momentos a valor nulo, excepto para el momento al que pertenece la señal.

  • Cada Instancia tendrá un tipo de documento en la colección con la siguiente estructura:


Donde:

  • windowType: Indica el tipo de ventana a la que representa el documento. Dependiendo de las ventanas que se creen desde el control panel, podrá tomar los valores:

    • MINUTES

    • HOURS

    • DAYS

    • MONTHS

  • windowFrecuency: Indica la frecuencia de muestro (1 medida o señal cada X tiempo)

  • windowFrecuencyUnit: Indica la unidad de frecuencia de muestro. Se aplica junto con windowFrecuency. Pej: 1 medida o señal cada 5 (windowFrecuency) segundos (windowFrecuencyUnit). Podrá tomar los valores:

    • SECONDS

    • MINUTES

    • HOURS

    • DAYS

    • MONTHS

  • timestamp: Representa la fecha de agrupación de la ventana. En función del valor de windowType tendrá el siguiente formato:

    • MINUTES: yyyy-mm-dd HH:mm:00:00Z

    • HOURS: yyyy-mm-dd HH:00:00:00Z

    • DAYS: yyyy-mm-dd HH:00:00:00Z

    • MONTHS: yyyy-mm-01 00:00:00:00Z

  • owner y assetId: Son campos que se declararon como Etiquetas o Tags en la ontología (Ver imagen del punto anterior)

  • values: Estructura que contiene cada una de las señales o medidas recibidas en la ventana temporal que agrupa el documento. La estructura depende de la ventana temporal elegida, la unidad de frecuencia y la frecuencia con la que se reciben señales o muestras.

El primer nivel elemento de values será un objeto con la propiedad "v" cuyo valor será otro objeto con una estructura que permita recuperar/actualizar de forma sencilla a un valor, conociendo su timestamp. Para ello, dependiendo del tipo de ventana y de la frecuencia de muestreo, se construye una estructura de objetos donde el primer nivel es el tipo de ventana y los siguientes dependen de la frecuencia de muestreo, y cuyas claves son, el número de dia, hora, minuto o segundo que corresponda.
Por ejemplo: Para una ventana diaria con muestras cada segundo se tendrá la siguiente estructura:

En un primer nivel, las 24 horas del dia con claves del 0 al 23. Para cada uno de estos niveles, que representa una hora del dia:

Tenemos los 60 minutos de dicha hora, con claves que van del 0 al 59, y de nuevo, para cada uno de estos 60 minutos:

Tenemos los 60 segundos, en este caso ya con el valor asociado a cada uno.

 

Esta estructura tiene la ventaja de que permite acceder fácilmente a cualquier valor encadenando: <numero_dia>.<numero_hora>.<numero_minuto>.<numero_segundo>


  • En la colección se tendrá un documento por cada combinación de:

    • Tags cuyo valor sea igual.

    • Campo o field único.

    • Ventana temporal.


De manera que cada documento contiene todos los tags, pero solo un campo o field. En caso de que una ontología defina mas de un campo o field, se crean tantos documentos como campos de este tipo haya.
Asimismo, si se reciben instancias donde uno o varios tags cambian cambian entre ellas, se considera que cada combinación única de tags pertenece a un documento distinto.


Lo explicaremos con el siguiente ejemplo:

 

Crearemos una nueva ontología TimeSeries llamada MeterBox01:

Le añadimos dos tags:

  • assetId

  • subassetId


Le añadimos dos señales (campos o fields):

  • power

  • intensity


Creamos dos ventanas:

  • Horaria con señales cada segundo

  • Diaria con señales cada minuto



En este punto la platafoma ha creado la coleccón en MongoDB y está vacia:

Enviamos una señal a través del IoT Broker:

Comprobamos la colección en MongoDB y vemos que se han creado 4 colecciones:

Tiene lógica, ya que tenemos dos ventanas temporales y dos campos o fields, de manera que tenemos:

Ventana Diaria con frecuencia 1 Minuto para propiedad intensity:

Ventana Diaria con frecuencia 1 Minuto para propiedad power:

Ventana Horaria con frecuencia 1 Segundo para propiedad intensity:

Ventana Horaria con frecuencia 1 Segundo para propiedad power



Volvemos a hacer otra inserción, pero esta vez cambiando uno de los tags. En concreto el subassetId a CUPS-2:

Volvemos a consultar la ontología y vemos que se han añadido otros 4 documentos:

Que se corresponden a las dos ventanas y dos propiedadades, para la combinación assetId="CUPS" y subassetId="CUPS-2":

A continuación comprobamos que para cualquiera de las instancias se ha introducido el valor enviado en la petición, en el instante de tiempo correcto. Por ejemplo, para la primera instancia:
{"TimeSerie":{ "timestamp":{"$date": "2019-06-12T00:00:00Z"},"assetId":"CUPS","subassetId":"CUPS-1","power":28.6,"intensity":2.5}}
Vemos que se envió para la fecha 2019-06-12T00:00:00Z
Miramos la ventana Horaria con frecuencia 1 segundo para el campo intensidad:
Podemos ver que el timestamp corresponde al dia 2019-06-12 a la hora 00:
Y si desplegamos values a lo que seria la posición de la hora enviada, en este caso de la instancia enviada, minuto 0, segundo 0, comprobamos que tiene el valor 2.5, que es el que se envió:

A continuación, actualizaremos con una nueva señal pero para el siguiente segundo:

Comprobamos que se ha introducido en el minuto 0, segundo 1

A continuación incrementaremos la hora y enviaremos una señal para la fecha 2019-06-12T01:00:00Z

Consultando de nuevo la colección vemos que tenemos dos nuevos documentos:

Que al haber cambiado de hora se corresponden con la ventana horaria con frecuencia 1 segundo, para las propiedades intensity y power de los tags con valores assetId="CUPS" subassetId="CUPS-1":

Donde podemos ver que el campo timestamp ya pertenece a la hora 01.