Migración de Time Series Insights (TSI) Gen2 a Azure Data Explorer

Nota:

El servicio Time Series Insights (TSI) dejará de admitirse a partir de marzo de 2025. Considere la posibilidad de migrar los entornos de TSI existentes a soluciones alternativas lo antes posible. Para más información sobre la entrada en desuso y la migración, consulte nuestra documentación.

Información general

Recomendaciones generales de migración.

Característica Estado de Gen2 Migración recomendada
Ingesta de JSON desde el centro con aplanado y caracteres de escape Ingesta de TSI ADX: Ingesta en un clic y asistente
Almacenamiento de acceso esporádico abierto Cuenta de almacenamiento del cliente Exportación continua de datos a la tabla externa especificada por el cliente en ADLS.
Conector PBI Versión preliminar privada Use el conector PBI de ADX. Reescritura manual de TSQ en KQL.
Conector de Spark Versión preliminar privada. Consulta de datos de telemetría. Consulta de datos del modelo. Migración de datos a ADX. Use el conector de Spark de ADX para datos de telemetría, exporte el modelo a JSON y cargue en Spark. Reescritura de consultas en KQL.
Carga masiva Versión preliminar privada Use la ingesta de un clic de ADX y LightIngest. Opcionalmente, configure la creación de particiones en ADX.
Modelo de Time Series Se puede exportar como archivo JSON. Se puede importar a ADX para realizar combinaciones en KQL.
Explorador de TSI Alternar entre frecuente y esporádico Paneles de ADX
Lenguaje de consulta Consultas de serie temporal (TSQ) Reescritura de consultas en KQL. Use los SDK de Kusto en lugar de los de TSI.

Migración de telemetría

Use la carpeta PT=Time de la cuenta de almacenamiento para recuperar la copia de todos los datos de telemetría del entorno. Para más información, consulte Almacenamiento de datos.

Paso 1 de la migración: Obtención de estadísticas sobre los datos de telemetría

Data

  1. Información general del entorno
    • Registrar el identificador de entorno de la primera parte del FQDN de acceso a datos (por ejemplo, d390b0b0-1445-4c0c-8365-68d6382c1c2a desde .env.crystal-dev.windows-int.net)
  2. Información general del entorno -> Configuración del almacenamiento -> Cuenta de almacenamiento
  3. Uso del Explorador de Storage para obtener estadísticas de carpetas
    • Tamaño de registro y número de blobs de la carpeta PT=Time. Para los clientes de la versión preliminar privada de la importación masiva, registre también el tamaño de PT=Import y el número de blobs.

Paso 2 de la migración: Migración de datos de telemetría a ADX

Creación de un clúster de ADX

  1. Defina el tamaño del clúster en función del tamaño de los datos mediante el estimador de costos de ADX.

    1. Desde las métricas de Event Hubs (o IoT Hub), recupere la velocidad de la cantidad de datos que se ingieren al día. Desde la cuenta de almacenamiento conectada al entorno de TSI, recupere la cantidad de datos que hay en el contenedor de blobs que usa TSI. Esta información se usará para calcular el tamaño ideal de un clúster de ADX para su entorno.
    2. Abra el estimador de costos de Azure Data Explorer y rellene los campos existentes con la información encontrada. Establezca "Tipo de carga de trabajo" como "Optimizada para almacenamiento" y "Datos de acceso frecuente" con la cantidad total de datos que se consultan activamente.
    3. Después de proporcionar toda la información, el estimador de costos de Azure Data Explorer sugerirá un tamaño de máquina virtual y un número de instancias para el clúster. Analice si el tamaño de los datos que se consultan activamente se ajustará a la memoria caché activa. Multiplique el número de instancias sugeridas por el tamaño de caché del tamaño de máquina virtual, por ejemplo:
      • Sugerencia del estimador de costos: 9 x DS14 + 4 TB (caché)
      • Caché activa total sugerida: 36 TB = [9x (instancias) x 4 TB (de caché activa por nodo)]
    4. Más factores a tener en cuenta:
      • Crecimiento del entorno: al planear el tamaño del clúster de ADX, tenga en cuenta el crecimiento de los datos a lo largo del tiempo.
      • Hidratación y creación de particiones: al definir el número de instancias del clúster de ADX, considere la posibilidad de usar nodos adicionales (entre 2 y 3 veces) para acelerar la hidratación y la creación de particiones.
      • Para más información sobre la selección del recurso de proceso, consulte Selección de la SKU de proceso correcta para el clúster de Azure Data Explorer.
  2. Para supervisar mejor el clúster y la ingesta de datos, debe habilitar la configuración diagnóstico y enviar los datos a un área de trabajo de Log Analytics.

    1. En la hoja Azure Data Explorer, vaya a "Monitoring | Diagnostic settings" (Supervisión | Configuración de diagnóstico) y haga clic en "Add diagnostic setting" (Agregar configuración de diagnóstico).

      Captura de pantalla de la hoja de Azure Data Explorer Supervisión | Configuración de diagnóstico

    2. Rellene la siguiente información:

      1. Nombre de la configuración de diagnóstico: nombre para mostrar de esta configuración
      2. Registros: como mínimo, seleccione SucceededIngestion, FailedIngestion e IngestionBatching.
      3. Seleccione el área de trabajo de Log Analytics a la que se van a enviar los datos (si no tiene una, deberá aprovisionar una antes de este paso).

      Captura de pantalla del área de trabajo de Log Analytics en Azure Data Explorer

  3. Creación de particiones de datos.

    1. En la mayoría de los conjuntos de datos, la creación de particiones predeterminada de ADX es suficiente.
    2. La creación de particiones de datos es beneficiosa en un conjunto muy específico de escenarios; no debe aplicarse en otros:
      1. Mejora de la latencia de consultas en conjuntos de macrodatos donde la mayoría de las consultas filtran por una columna de cadena de cardinalidad alta, por ejemplo, un id. de serie temporal.
      2. Al ingerir datos desordenados, por ejemplo, cuando los eventos del pasado se pueden ingerir días o semanas después de su generación en el origen.
    3. Para más información, consulte Directiva de creación de particiones de datos de ADX.

Preparación para la ingesta de datos

  1. Ir a https://dataexplorer.azure.com.

    Captura de pantalla de la página de aterrizaje de Azure Data Explorer

  2. Vaya a la pestaña Data (Datos) y seleccione "Ingest from blob container" (Ingesta desde un contenedor de blobs).

    Captura de pantalla de la ingesta de Azure Data Explorer desde el contenedor de blobs

  3. Seleccione el clúster, la base de datos y cree una nueva tabla con el nombre que elija para los datos de TSI.

    Captura de pantalla de la selección de clúster, base de datos y tabla en la ingesta de Azure Data Explorer

  4. Seleccione Next: Source (Siguiente: Origen).

  5. En la pestaña Source (Origen), seleccione:

    1. Datos históricos
    2. "Select Container" (Seleccionar contenedor)
    3. Elija la suscripción y la cuenta de almacenamiento para los datos de TSI.
    4. Elija el contenedor que se correlaciona con el entorno de TSI.

    Captura de pantalla de la selección de contenedor en la ingesta de Azure Data Explorer

  6. Seleccione Advanced settings (Configuración avanzada).

    1. Creation time pattern (Patrón de tiempo de creación): '/'yyyyMMddHHmmssfff'_'
    2. Blob name pattern (Patrón de nombre de blob): *.parquet
    3. Seleccione "Don’t wait for ingestion to complete" (No esperar a que se complete la ingesta).

    Captura de pantalla de la selección de la configuración avanzada en la ingesta de Azure Data Explorer

  7. En File Filters (Filtros de archivos), agregue la ruta de acceso a la carpeta V=1/PT=Time.

    Captura de pantalla de la selección de la ruta de acceso a la carpeta en la ingesta de Azure Data Explorer

  8. Seleccione Next: Schema (Siguiente: Esquema).

    Nota:

    TSI aplica algunos aplanados y caracteres de escape al conservar columnas en archivos Parquet. Consulte estos vínculos para más detalles: Acoplamiento de JSON, escape y control de matrices y Próximos cambios en las reglas de aplanamiento y escape de JSON para los entornos nuevos.

  • Si el esquema es desconocido o varía

    1. Quite todas las columnas que se consultan con poca frecuencia, dejando al menos las columnas timestamp y TSID.

      Captura de pantalla de la selección de esquemas en la ingesta de Azure Data Explorer

    2. Agregue una nueva columna de tipo dinámico y asígnela a todo el registro mediante $ path.

      Captura de pantalla de la ingesta de Azure Data Explorer para un tipo dinámico

      Ejemplo:

      Captura de pantalla del ejemplo de la ingesta de Azure Data Explorer para un tipo dinámico

  • Si el esquema es conocido o fijo

    1. Confirme que los datos tengan un aspecto correcto. Corrija los tipos si es necesario.
    2. Seleccione Next: Summary (Siguiente: Resumen).

Copie el comando LightIngest y almacénelo en algún lugar para poder usarlo en el paso siguiente.

Captura de pantalla de la ingesta de Azure Data Explorer para el comando Lightingest

Ingesta de datos

Antes de ingerir datos, debe instalar la herramienta LightIngest. El comando generado desde la herramienta de un clic incluye un token de SAS. Es mejor generar uno nuevo para que tenga control sobre la hora de expiración. En el portal, vaya al contenedor de blobs del entorno de TSI y seleccione "Token de acceso compartido".

Captura de pantalla de la ingesta de Azure Data Explorer para el token de SAS

Nota:

También se recomienda escalar verticalmente el clúster antes de iniciar una ingesta de gran tamaño. Por ejemplo, D14 o D32 con más de 8 instancias.

  1. Configure las opciones siguientes:

    1. Permisos: Lectura y Lista
    2. Expiración: establezca un período en el que estime que se completará la migración de datos.

    Captura de pantalla de la ingesta de Azure Data Explorer para la expiración de permisos

  2. Haga clic en "Generate SAS token and URL" (Generar URL y token de SAS) y copie el valor de "Blob SAS URL" (URL de SAS de Blob).

    Captura de pantalla de la ingesta de Azure Data Explorer para la URL de SAS de Blob

  3. Vaya al comando LightIngest que copió anteriormente. Reemplace el parámetro -source del comando por el valor de "Blob SAS URL" (URL de SAS de Blob).

  4. Opción 1: Ingesta de todos los datos. En entornos más pequeños, puede ingerir todos los datos con un solo comando.

    1. Abra un símbolo del sistema y cambie al directorio en el que se extrajo la herramienta LightIngest. Una vez allí, pegue el comando LightIngest y ejecútelo.

    Captura de pantalla de la ingesta de Azure Data Explorer para el símbolo del sistema

  5. Opción 2: Ingesta de datos por año o mes. Para entornos más grandes o para probar en un conjunto de datos más pequeño, puede filtrar aún más el comando Lightingest.

    1. Por año: cambio del parámetro -prefix

      • Antes: -prefix:"V=1/PT=Time"
      • Después: -prefix:"V=1/PT=Time/Y=<Year>"
      • Ejemplo: -prefix:"V=1/PT=Time/Y=2021"
    2. Por mes: cambio del parámetro -prefix

      • Antes: -prefix:"V=1/PT=Time"
      • Después: -prefix:"V=1/PT=Time/Y=<Year>/M=<month #>"
      • Ejemplo: -prefix:"V=1/PT=Time/Y=2021/M=03"

Una vez que haya modificado el comando, ejecútelo como se ha indicado anteriormente. Una vez completada la ingesta (mediante la opción de supervisión siguiente), modifique el comando para el próximo año y mes que quiera ingerir.

Supervisión de la ingesta

El comando LightIngest incluía la marca -dontWait, por lo que el propio comando no esperará a que se complete la ingesta. La mejor manera de supervisar el progreso mientras se está produciendo es usar la pestaña "Insights" en el portal. Abra la sección del clúster de Azure Data Explorer en el portal y vaya a "Monitoring | Insights" (Supervisión | Insights).

Captura de pantalla de la ingesta de Azure Data Explorer para Supervisión Insights

Puede usar la sección "Ingestion (preview)" (Ingesta [versión preliminar]) con la configuración siguiente para supervisar la ingesta a medida que se está produciendo.

  • Time range (Intervalo de tiempo): últimos 30 minutos
  • Observe el contenido de Successful (Correcto) y By Table (Por tabla).
  • Si tiene algún error, Observe el contenido de Failed (Error) y By Table (Por tabla).

Captura de pantalla de la ingesta de Azure Data Explorer para los resultados de la Supervisión

Sabrá que la ingesta se ha completado una vez que vea que las métricas bajan a 0 para la tabla. Si quiere ver más detalles, puede usar Log Analytics. En la sección del clúster de Azure Data Explorer, seleccione la pestaña "Log" (Registro):

Captura de pantalla de la ingesta de Azure Data Explorer para los registros de la Supervisión

Consultas útiles

Descripción del esquema si se usa un esquema dinámico

| project p=treepath(fullrecord)
| mv-expand p 
| summarize by tostring(p)

Acceso a los valores de una matriz

| where id_string == "a"
| summarize avg(todouble(fullrecord.['nestedArray_v_double'])) by bin(timestamp, 1s)  
| render timechart 

Migración del modelo de serie temporal (TSM) a Azure Data Explorer

El modelo se puede descargar en formato JSON desde el entorno de TSI mediante la experiencia de usuario del explorador de TSI o la API de Batch de TSM. A continuación, el modelo se puede importar en otro sistema, como Azure Data Explorer.

  1. Descargue el TSM desde la experiencia de usuario de TSI.

  2. Elimine las tres primeras líneas mediante VSCode u otro editor.

    Captura de pantalla de la migración de TSM a Azure Data Explorer: Eliminación de las tres primeras líneas

  3. Con VSCode u otro editor, busque y reemplace como expresión regular \},\n \{ por }{.

    Captura de pantalla de la migración de TSM a Azure Data Explorer: Buscar y reemplazar

  4. Realice la ingesta como JSON en ADX como una tabla independiente mediante la funcionalidad de carga desde archivo.

    Captura de pantalla de la migración de TSM a Azure Data Explorer: Ingesta como JSON

Traducción de consultas de serie temporal (TSQ) a KQL

GetEvents

{
  "getEvents": {
    "timeSeriesId": [
      "assest1",
      "siteId1",
      "dataId1"
    ],
    "searchSpan": {
      "from": "2021-11-01T00:00:0.0000000Z",
      "to": "2021-11-05T00:00:00.000000Z"
    },
    "inlineVariables": {},
  }
}
events
| where timestamp >= datetime(2021-11-01T00:00:0.0000000Z) and timestamp < datetime(2021-11-05T00:00:00.000000Z)
| where assetId_string == "assest1" and siteId_string == "siteId1" and dataid_string == "dataId1"
| take 10000

GetEvents con filtro

{
  "getEvents": {
    "timeSeriesId": [
      "deviceId1",
      "siteId1",
      "dataId1"
    ],
    "searchSpan": {
      "from": "2021-11-01T00:00:0.0000000Z",
      "to": "2021-11-05T00:00:00.000000Z"
    },
    "filter": {
      "tsx": "$event.sensors.sensor.String = 'status' AND $event.sensors.unit.String = 'ONLINE"
    }
  }
} 
events
| where timestamp >= datetime(2021-11-01T00:00:0.0000000Z) and timestamp < datetime(2021-11-05T00:00:00.000000Z)
| where deviceId_string== "deviceId1" and siteId_string == "siteId1" and dataId_string == "dataId1"
| where ['sensors.sensor_string'] == "status" and ['sensors.unit_string'] == "ONLINE"
| take 10000

GetEvents con variable proyectada

{
  "getEvents": {
    "timeSeriesId": [
      "deviceId1",
      "siteId1",
      "dataId1"
    ],
    "searchSpan": {
      "from": "2021-11-01T00:00:0.0000000Z",
      "to": "2021-11-05T00:00:00.000000Z"
    },
    "inlineVariables": {},
    "projectedVariables": [],
    "projectedProperties": [
      {
        "name": "sensors.value",
        "type": "String"
      },
      {
        "name": "sensors.value",
        "type": "bool"
      },
      {
        "name": "sensors.value",
        "type": "Double"
      }
    ]
  }
}	 
events
| where timestamp >= datetime(2021-11-01T00:00:0.0000000Z) and timestamp < datetime(2021-11-05T00:00:00.000000Z)
| where deviceId_string== "deviceId1" and siteId_string == "siteId1" and dataId_string == "dataId1"
| take 10000
| project timestamp, sensorStringValue= ['sensors.value_string'], sensorBoolValue= ['sensors.value_bool'], sensorDoublelValue= ['sensors.value_double']

AggregateSeries

{
  "aggregateSeries": {
    "timeSeriesId": [
      "deviceId1"
    ],
    "searchSpan": {
      "from": "2021-11-01T00:00:00.0000000Z",
      "to": "2021-11-05T00:00:00.0000000Z"
    },
    "interval": "PT1M",
    "inlineVariables": {
      "sensor": {
        "kind": "numeric",
        "value": {
          "tsx": "coalesce($event.sensors.value.Double, todouble($event.sensors.value.Long))"
        },
        "aggregation": {
          "tsx": "avg($value)"
        }
      }
    },
    "projectedVariables": [
      "sensor"
    ]
  }	
events
| where timestamp >= datetime(2021-11-01T00:00:00.0000000Z) and timestamp < datetime(2021-11-05T00:00:00.0000000Z)
| where  deviceId_string == "deviceId1"
| summarize avgSensorValue= avg(coalesce(['sensors.value_double'], todouble(['sensors.value_long']))) by bin(IntervalTs = timestamp, 1m)
| project IntervalTs, avgSensorValue

AggregateSeries con filtro

{
  "aggregateSeries": {
    "timeSeriesId": [
      "deviceId1"
    ],
    "searchSpan": {
      "from": "2021-11-01T00:00:00.0000000Z",
      "to": "2021-11-05T00:00:00.0000000Z"
    },
    "filter": {
      "tsx": "$event.sensors.sensor.String = 'heater' AND $event.sensors.location.String = 'floor1room12'"
    },
    "interval": "PT1M",
    "inlineVariables": {
      "sensor": {
        "kind": "numeric",
        "value": {
          "tsx": "coalesce($event.sensors.value.Double, todouble($event.sensors.value.Long))"
        },
        "aggregation": {
          "tsx": "avg($value)"
        }
      }
    },
    "projectedVariables": [
      "sensor"
    ]
  }
}	
events
| where timestamp >= datetime(2021-11-01T00:00:00.0000000Z) and timestamp < datetime(2021-11-05T00:00:00.0000000Z)
| where  deviceId_string == "deviceId1"
| where ['sensors.sensor_string'] == "heater" and ['sensors.location_string'] == "floor1room12"
| summarize avgSensorValue= avg(coalesce(['sensors.value_double'], todouble(['sensors.value_long']))) by bin(IntervalTs = timestamp, 1m)
| project IntervalTs, avgSensorValue

Migración del conector de Power BI de TSI al conector de Power BI de ADX

Los pasos manuales implicados en esta migración son:

  1. Conversión de la consulta de Power BI a TSQ
  2. Conversión de TSQ a una consulta de Power BI de KQL a TSQ: la consulta de Power BI copiada desde el explorador de la experiencia de usuario de TSI es similar a la que se muestra a continuación.

Para datos sin procesar (API GetEvents)

{"storeType":"ColdStore","isSearchSpanRelative":false,"clientDataType":"RDX_20200713_Q","environmentFqdn":"6988946f-2b5c-4f84-9921-530501fbab45.env.timeseries.azure.com", "queries":[{"getEvents":{"searchSpan":{"from":"2019-10-31T23:59:39.590Z","to":"2019-11-01T05:22:18.926Z"},"timeSeriesId":["Arctic Ocean",null],"take":250000}}]}
  • Para convertirlo a TSQ, cree un archivo JSON a partir de la carga anterior. La documentación de la API GetEvents también contiene ejemplos para entenderla mejor. Consulta: ejecución: API REST (Azure Time Series Insights) | Microsoft Docs
  • La consulta TSQ convertida es similar a la que se muestra a continuación. Es la carga JSON dentro de "consultas".
{
  "getEvents": {
    "timeSeriesId": [
      "Arctic Ocean",
      "null"
    ],
    "searchSpan": {
      "from": "2019-10-31T23:59:39.590Z",
      "to": "2019-11-01T05:22:18.926Z"
    },
    "take": 250000
  }
}

Para datos agregados (API AggregateSeries)

  • En el caso de una sola variable insertada, la consulta de PowerBI desde el explorador de la experiencia de usuario de TSI tiene el siguiente aspecto:
{"storeType":"ColdStore","isSearchSpanRelative":false,"clientDataType":"RDX_20200713_Q","environmentFqdn":"6988946f-2b5c-4f84-9921-530501fbab45.env.timeseries.azure.com", "queries":[{"aggregateSeries":{"searchSpan":{"from":"2019-10-31T23:59:39.590Z","to":"2019-11-01T05:22:18.926Z"},"timeSeriesId":["Arctic Ocean",null],"interval":"PT1M", 		"inlineVariables":{"EventCount":{"kind":"aggregate","aggregation":{"tsx":"count()"}}},"projectedVariables":["EventCount"]}}]}
{
  "aggregateSeries": {
    "timeSeriesId": [
      "Arctic Ocean",
      "null"
    ],
    "searchSpan": {
      "from": "2019-10-31T23:59:39.590Z",
      "to": "2019-11-01T05:22:18.926Z"
    },
    "interval": "PT1M",
    "inlineVariables": {
      "EventCount": {
        "kind": "aggregate",
        "aggregation": {
          "tsx": "count()"
        }
      }
    },
    "projectedVariables": [
      "EventCount",
    ]
  }
}
  • Para más de una variable insertada, anexe el código JSON a "inlineVariables", como se muestra en el ejemplo siguiente. La consulta de Power BI para más de una variable insertada tiene el siguiente aspecto:
{"storeType":"ColdStore","isSearchSpanRelative":false,"clientDataType":"RDX_20200713_Q","environmentFqdn":"6988946f-2b5c-4f84-9921-530501fbab45.env.timeseries.azure.com","queries":[{"aggregateSeries":{"searchSpan":{"from":"2019-10-31T23:59:39.590Z","to":"2019-11-01T05:22:18.926Z"},"timeSeriesId":["Arctic Ocean",null],"interval":"PT1M", "inlineVariables":{"EventCount":{"kind":"aggregate","aggregation":{"tsx":"count()"}}},"projectedVariables":["EventCount"]}}, {"aggregateSeries":{"searchSpan":{"from":"2019-10-31T23:59:39.590Z","to":"2019-11-01T05:22:18.926Z"},"timeSeriesId":["Arctic Ocean",null],"interval":"PT1M", "inlineVariables":{"Magnitude":{"kind":"numeric","value":{"tsx":"$event['mag'].Double"},"aggregation":{"tsx":"max($value)"}}},"projectedVariables":["Magnitude"]}}]}

{
  "aggregateSeries": {
    "timeSeriesId": [
      "Arctic Ocean",
      "null"
    ],
    "searchSpan": {
      "from": "2019-10-31T23:59:39.590Z",
      "to": "2019-11-01T05:22:18.926Z"
    },
    "interval": "PT1M",
    "inlineVariables": {
      "EventCount": {
        "kind": "aggregate",
        "aggregation": {
          "tsx": "count()"
        }
      },
      "Magnitude": {
        "kind": "numeric",
        "value": {
          "tsx": "$event['mag'].Double"
        },
        "aggregation": {
          "tsx": "max($value)"
        }
      }
    },
    "projectedVariables": [
      "EventCount",
      "Magnitude",
    ]
  }
}
  • Si desea consultar los datos más recientes ("isSearchSpanRelative": true), calcule manualmente el valor de searchSpan como se menciona a continuación.
    • Busque la diferencia entre los elementos "from" y "to" en la carga de Power BI. Vamos a llamar "D" a esa diferencia, donde "D" = "from" - "to".
    • Tome la marca de tiempo actual ("T") y reste la diferencia obtenida en el primer paso. Será el nuevo "from" (F) de searchSpan, donde "F" = "T" - "D".
    • Ahora, el nuevo "from" es el valor de "F" obtenido en el paso 2 y el nuevo "to" es "T" (marca de tiempo actual).