Tableau Hyper API: el equipo de BI se lo agradecerá

Queremos contarle cómo ayudamos a nuestro equipo de BI a organizar el proceso automático de entrega de datos al servidor de Tableau desde MongoDB utilizando el formato de almacenamiento de datos tabloide "hyper", y el proceso de configuración de la generación de datos se lleva a cabo a través de una sencilla interfaz web.



Al principio, describiremos brevemente cómo se veía el proceso antes y después de que enseñáramos a nuestro producto interno A1 a recopilar fuentes de datos mediante programación y publicarlas en Tableau Server. Luego, analizaremos más de cerca el problema del comando BI y la solución encontrada, así como también buscaremos bajo el capó (aquí se trata de crear un archivo .hyper, publicar un archivo en un servidor de Tableau y actualizar un hiper). ¡Bienvenido al gato!



Tableau Hyper API: el equipo de BI se lo agradecerá




En el grupo de publicidad DAN trabajamos mucho con los datos de seguimiento publicitario de Mediascope , un medidor industrial en el mercado de los medios. Hay diferentes escenarios: algunos empleados cargan datos sin procesar, otros usan bases de datos preprocesadas y listas para usar y alguien ordena el desarrollo de paneles automatizados basados ​​en estos datos. Hablemos del último escenario con más detalle: nuestros desarrolladores de BI recopilan paneles en Tableau, pero antes de comenzar a "dibujar", también deben llevar los datos al formato deseado que sea conveniente para el desarrollo.



La ruta de vida de los datos, desde las materias primas hasta los hermosos gráficos automatizados, se puede dividir aproximadamente en 4 pasos:



  1. Obteniendo datos brutos
  2. Limpieza y revisión de datos
  3. Crear fuentes de datos para Tableau
  4. Desarrollo de visualizaciones


Era



Antes de que aprendiéramos cómo generar fuentes de datos mediante programación para Tableau, el proceso se veía así:



Proceso de la vieja vida


1. Obtención de datos sin procesar



Los usuarios generan informes tabulares a través de la herramienta interna A1. Hablaremos de ello con más detalle a continuación.



2. Limpieza y revisión de datos La



capacidad de transformación de datos también se incluye en la herramienta A1, después de lo cual los datos limpiados se pueden cargar a xslx / csv y continuar trabajando con ellos fuera de la herramienta. Vale la pena señalar aquí que algunos usuarios se limitan al 1er punto y, después de cargar los informes, modifican los datos por su cuenta.



3. Crear fuentes de datos para Tableau



Anteriormente, los clientes del tablero venían con un conjunto de Excels, que generaban en los párrafos anteriores. Y los desarrolladores de BI reunieron estos ex-works en una sola fuente de datos (jerga sensacionalista) por su cuenta. No siempre fue posible limitarnos solo a las herramientas de Tableau; a menudo escribían scripts en Python.



4. Desarrollo de visualizaciones



Finalmente, la punta del iceberg es crear un tablero y publicarlo en Tableau Server, donde el cliente puede verlo. En la práctica, la renderización suele llevar menos tiempo que la recopilación de datos y la configuración de actualizaciones.



El dolor se acumuló en el tercer paso, a medida que crecía el número de soluciones personalizadas, que eran caras de mantener e implementar. Además, los errores en los datos del segundo paso se filtraban regularmente: el Excel intermedio entre los dos sistemas (A1 y Tableau) empujaba al usuario: "corrijamos algo con bolígrafos, nadie lo notará".



Se ha convertido



La tarea principal consistía en eliminar el ex-pelaje entre 2 y 3 pasos. Como resultado, enseñamos a A1 a recopilar fuentes de datos y publicarlas en Tableau Server. Esto es lo que pasó:



Nuevo proceso de vida


Ahora los pasos del 1 al 3 se llevan a cabo en A1, en la salida, el equipo de BI recibe una fuente de datos publicada en Tableau Server para desarrollar visualizaciones. La Hyper API se convirtió en el enlace de conexión, que se discutirá más a fondo.



resultados



Reducción del número de nodos al trabajar en diferentes herramientas. Ahora es más difícil cometer un error en algún lugar del proceso, y es más fácil detectar dónde ocurrió el error, la investigación de fallas lleva menos tiempo. El sistema advierte a los usuarios sobre errores comunes.



Libere el tiempo del equipo de BI . Anteriormente, había pocas soluciones de plantillas y muchas personalizaciones. La mayoría de las veces, se agregó procesamiento en Python para cada proyecto. En casos excepcionales, en los que no era necesario procesar, trabajamos directamente en Tableau Desktop (la principal herramienta de desarrollo).



Ahora la preparación de la fuente de datos es: haga clic en los campos requeridos en la interfaz A1, marque cuál de ellos expandimos en líneas (si es necesario) y opcionalmente definimos el tipo de campos con anticipación.



No cargamos Tableau ServerActualización de fuentes de datos voluminosas: la actualización la realiza A1 y se descarga un hiperactivo listo para usar en el servidor.



* Bonificación: animamos a los usuarios a trabajar dentro de A1. Si antes algunos usuarios, después de descargar los informes sin procesar, los modificaban manualmente fuera de la herramienta, ahora, dado que todo el proceso desde los pasos 1 al 3 tiene lugar en A1, es más fácil para los usuarios configurar el proceso de limpieza allí.



Problema y solución



Un poco sobre A1



Antes de empezar a hablar de nuestra solución, necesitamos hablar de nuestro producto interno A1, al que hemos adjuntado la generación de fuentes de datos.



A1 es un producto interno de la empresa, que está diseñado para simplificar el flujo de trabajo para los empleados cuyo trabajo principal es el siguiente:



  • Recuperar datos de productos de software MediaScope
  • Traiga (limpie) estos datos en una forma conveniente para los analistas de temas
  • Si es necesario, prepare los datos para crear paneles (hablaremos de esto hoy)


Una vez que el usuario termina de limpiar los datos, se almacenan en el sistema A1. En nuestra terminología, esto se llama "contenedor". Un contenedor es un documento normal en MongoDB, que debemos transferir al servidor de Tableau.



Problema del equipo de BI



Nuestro equipo de desarrollo de BI necesitaba de alguna manera obtener datos de A1, que se almacenaron en MongoDB, y crear paneles basados ​​en los datos recibidos. En primer lugar, intentamos obtener datos de MongoDB utilizando herramientas de marcador habituales, pero esto no resolvió el problema:



  • Dado que los datos se almacenan en MongoDB, los datos con una estructura arbitraria se reciben en la entrada del marcador, lo que significa que tendríamos que mantener constantemente esta lógica.
  • Para agregar datos de MongoDB, era necesario arrastrar ciertos registros de la colección, y no toda la colección; el controlador de Tableau no puede hacer esto.
  • Entre otras cosas, no era suficiente obtener los datos: a veces tenía que "expandirse", para "desvincular" algunas columnas en filas. Lo cual tampoco fue tan fácil de hacer, por la palabra en absoluto.


Que se nos ha ocurrido



Se decidió intentar resolver este problema con mi bicicleta, utilizando la biblioteca Tableau Hyper API . Esta biblioteca le permite crear un archivo en formato .hyper, en el que es fácil agregar datos, y luego usarlo como fuente de datos para crear un tablero en el tablero del servidor.



Como describen los propios desarrolladores del cuadro de indicadores:

Hyper es un motor de datos en memoria de alto rendimiento que ayuda a los clientes a analizar rápidamente conjuntos de datos grandes o complejos mediante la evaluación eficiente de consultas de bases de datos. Hyper, basado en la plataforma Tableau, utiliza técnicas de generación de código dinámico patentadas y tecnologías de concurrencia avanzadas para lograr un alto rendimiento en extracciones y consultas.
El proceso aproximado de trabajo en nuestro programa es el siguiente:



  • El usuario selecciona contenedores y columnas deseadas
  • El sistema extrae datos de los contenedores
  • Basado en los datos recibidos, el sistema determina los tipos de columnas
  • Se inicializa la creación del hiper y la inserción de datos en él
  • El hiper se carga en el servidor del marcador
  • Los desarrolladores de BI ven el hiper en el servidor y crean un tablero basado en él


Cuando se vierten nuevos datos en los contenedores, el sistema recibirá una señal de que el hiper debe actualizarse:



  • El sistema descargará el hiper desde el servidor del marcador.
  • Tomará datos nuevos de MongoDB y actualizará el hiper
  • Después de eso, el sistema carga un nuevo hiper al servidor, sobrescribiendo el existente.
  • El usuario solo necesita hacer clic en el botón "Actualizar" para mostrar información actualizada en el panel.


Lo que ve el usuario



Como se indicó anteriormente, A1 es una aplicación web. Usamos Vue.js y Vuetify para crear un servicio de hipergeneración de front-end.



La interfaz de la aplicación se divide en tres pantallas.



Pantalla de selección de contenedores



En la primera pantalla, el usuario selecciona los contenedores y columnas deseados.



Si la opción "Desvivar" está habilitada, se crearán dos columnas adicionales en la hiper: variable: los nombres de las columnas seleccionadas por la columna Métricas y los valores: los valores de estas columnas.



La columna Dimensión agrega una columna con la columna seleccionada del mismo nombre al hiper. El número de columnas seleccionadas Dimensiones y sus nombres deben ser iguales en todos los contenedores para que no se viole la integridad de la tabla en el hiper, por lo tanto existe una columna "Hipernombre", que permite especificar el nombre de la columna seleccionada si se nombran de manera diferente en los contenedores.



Registros del proceso de hiper creación



Esto concluye el proceso de creación del hyiper. El usuario solo necesita ir a la segunda pantalla, hacer clic en "Crear hiper" y ver el progreso de los eventos en los registros.



Ajustes adicionales



La tercera pantalla contiene configuraciones adicionales:



  • Puede activar ignorar actualizaciones si no necesitamos que el sistema actualice automáticamente el hiper
  • Puede especificar un correo electrónico para enviar informes de actualización
  • Puede especificar manualmente el tipo de datos para la columna de valores (se usa solo en modo sin divisiones): flotante, cadena o determinado automáticamente por el sistema (hablaremos más sobre los tipos)
  • También puede especificar tipos de datos para columnas seleccionadas en contenedores.


Que hay debajo del capó



A1 está escrito en Python. Para trabajar con datos, usamos Pandas y serializamos los datos de pandas para encurtirlos y almacenarlos en MongoDB GridFS.



Cuando se recibe un comando para crear un hiper, el sistema realiza las siguientes operaciones:



  • Descarga todos los contenedores necesarios de MongoDB y deserializa los datos en pandas datafremes
  • Prepara los datos: deja solo las columnas requeridas en los marcos de datos, les da nuevos nombres, expande las tablas si es necesario a través de pandas.melt
  • Si el usuario ha establecido el tipo de datos para las columnas, convierta los datos en float32 o en cadena
  • Después de todo el trabajo preparatorio con los datos, el sistema crea un archivo a través de hyper api y envía el archivo al servidor del marcador a través de tabcmd.


Vale la pena hablar un poco sobre los tipos de datos de las columnas. Una de las características de almacenar datos en contenedores A1 es que los usuarios no se preocupan por qué tipos asignar a las columnas, los pandas lo hacen perfectamente: el sistema hace frente con calma a situaciones en las que los números y valores de cadena están presentes en una columna. Sin embargo, al hiper no le gusta esto: si le dices que la columna debe ser de tipo int, el sistema jurará cuando intente insertar algo que no sea un entero. Por lo tanto, se decidió utilizar solo dos tipos de datos en hypers: string y float.



Entonces, descubrimos el principio general del trabajo, hablemos de trabajar con Hyper en sí.



Creando un archivo .hyper



Para trabajar con Hyper API, necesita instalar la biblioteca, puede descargarla del sitio web oficial aquí . También hay algunos buenos ejemplos de cómo trabajar con esta herramienta. Indicaremos brevemente los puntos principales.



El archivo hyiper en sí mismo es una especie de base de datos que recuerda algo a SQLite. A través de la API, puede acceder a los datos utilizando la sintaxis SQL:



f"SELECT {escape_name('Customer ID')} FROM {escape_name('Customer')}"


Dado que nuestro sistema está escrito en Python, también usaremos la biblioteca para el idioma correspondiente. Al crear un archivo, debemos especificar el nombre del esquema, el nombre de la tabla y las columnas con tipos. El nombre del esquema y la tabla deben llamarse "Extraer", ya que es en este esquema con la tabla donde Tableau Server sube para extraer datos para libros.



with HyperProcess(Telemetry.SEND_USAGE_DATA_TO_TABLEAU) as hyper:
    with Connection(
        hyper.endpoint, self.fullpath_hyper, CreateMode.CREATE_AND_REPLACE
    ) as connection:
        connection.catalog.create_schema("Extract")
        main_table = TableName("Extract", "Extract")
        example_table = TableDefinition(main_table)


Después de crear la tabla, necesitamos crear columnas y establecer tipos. Como dijimos anteriormente, nuestros datos solo tienen dos tipos (flotante o cadena), por lo que, según el tipo de columnas en el marco de datos, establecemos esto para las columnas:



for column in dataframe.columns:
    if dataframe[column].dtype.name in ("category", "object"):
        example_table.add_column(TableDefinition.Column(column, SqlType.text()))

    elif dataframe[column].dtype.name in ("float32"):
        example_table.add_column(
            TableDefinition.Column(column, SqlType.double())
        )

    connection.catalog.create_table(example_table)


Después de crear la tabla, puede insertar datos:



with Inserter(connection, example_table) as inserter:
    for val in dataframe.values:
        inserter.add_row(val.tolist())
    inserter.execute()


Aquí corremos a través del marco de datos línea por línea y acumulamos la lista con valores a través de inserter.add_row () . De hecho, hay una función add_rows () en la api hyper , que toma una lista de listas e inserta los valores. ¿Por qué no se hizo esto? Para ahorrar RAM: para proporcionar una lista de listas de valores del marco de datos, debe pedirle a los pandas que hagan values.tolist () . Y cuando tienes 150 millones de líneas de datos, resulta una operación muy costosa para la RAM, mientras que esto no afecta el rendimiento de ninguna manera (en cualquier caso, no se notó que debido a la iteración iterativa sobre las líneas, la velocidad de creación de un hiper de alguna manera se hundió). Además, add_rows ()funciona como azúcar sintáctico: en realidad, toma una lista de listas y agrega datos de forma iterativa.



Esto concluye la creación de nuestro hyper. A continuación, necesitamos publicarlo en el servidor.



Publicar un archivo en un servidor de Tableau



Para acceder a tableau-server, usaremos la utilidad tabcmd - esta es una utilidad de consola que le permite conectarse al servidor y realizar funciones administrativas - crear usuarios, grupos, libros y más.



Ejecutaremos el comando tabcmd a través del subproceso de Python.



popen = subprocess.Popen(
    f'/opt/tableau/tabcmd/bin/tabcmd publish "{fullpath_hyper}" -n "{filename}" -o -r "A1_test" '
    '-s http://tableau.domain.com -u "username" -p "password" --no-certcheck',
    shell=True,
    stderr=subprocess.PIPE,
    stdout=subprocess.PIPE,
)
return_code = popen.wait()
if return_code:
    error = str(popen.communicate()[1])
    return f"     . {error}"


Pasamos el siguiente comando y claves a tabcmd:



  • publicar : sube un archivo al servidor
  • -n (--name) : qué nombre de archivo estará en el servidor
  • -o (--overwrite) : si hay un archivo con este nombre, sobrescribir
  • -r “A1_test” (--project): ( )
  • -s (--server): tableau-
  • -u -p:
  • --no-certcheck: SSL-




Descubrimos cómo crear un nuevo hiper, pero ¿qué hacer cuando el hiper consta de diez contenedores y uno de ellos recibió nuevos datos? Actualizaremos el hyper.



Cuando llegan nuevos datos al contenedor, el sistema busca ver si hay hipers que usan este contenedor. Si lo hay, entonces la tarea es actualizar el hiper.



Para comprender qué datos de qué contenedor se encuentran en el hiper, el sistema también crea una columna container_id adicional al crear el hiper. Con este enfoque, la actualización se vuelve muy simple:



  • Tomamos el archivo del servidor
  • Eliminamos todas las líneas en el hiper, donde container_id es igual al contenedor actualizado
  • Insertar nuevas líneas
  • Vuelva a cargar el archivo sobrescrito en el servidor.


El proceso de recuperación de un archivo es ligeramente diferente del proceso de descarga. En primer lugar, no tomaremos el archivo .hyper del servidor, sino el archivo .tdsx, que luego descomprimiremos y abriremos el .hyper.



Para recoger el archivo, usamos tabcmd:



popen = subprocess.Popen(
    f'/opt/tableau/tabcmd/bin/tabcmd get "datasources/{filename_tdsx}" '
    f'-s http://tableau.domain.com -u "username" -p "password" '
    f'--no-certcheck -f "{fullpath_tdsx}"',
    shell=True,
    stderr=subprocess.PIPE,
    stdout=subprocess.PIPE,
)
return_code = popen.wait()
if return_code:
    error = str(popen.communicate()[1])
    return f". {error}"


Aquí usamos el siguiente comando y teclas:



  • get : obtiene un archivo del servidor. Si el archivo test.hyper está en el servidor, entonces debe consultar el archivo test.tdsx, y todos están en el directorio de origen de datos (no podría buscar en Google por qué esta característica del marcador, si lo sabe, comparta los comentarios)
  • -f (--nombre de archivo) : ruta completa, incluido el nombre y la extensión del archivo, donde guardar el archivo


Una vez descargado el archivo, debe descomprimirse mediante un archivo zip:



with zipfile.ZipFile(fullpath_tdsx, "r") as zip_ref:
    zip_ref.extractall(path)


Después de descomprimir, el hiperactivo estará en el directorio ./Data/Extracts .



Ahora que tenemos la versión actual del archivo, podemos eliminar las líneas innecesarias:



table_name = TableName("Extract", "Extract")

with HyperProcess(Telemetry.SEND_USAGE_DATA_TO_TABLEAU) as hyper:
    with Connection(hyper.endpoint, self.fullpath_hyper) as connection:
        connection.execute_query(
            f"DELETE FROM {table_name} WHERE "
            f'{escape_name("container_id")}={container_id}'
        ).close()


Bueno, la inserción y publicación de un archivo ya se describió anteriormente.



Conclusión



¿Cuál es el resultado final? Habiendo realizado el trabajo en la implementación de la generación de hiperarchivos y su entrega automática al servidor de tableau, redujimos significativamente la carga en el equipo de BI, se hizo más fácil actualizar los datos en el tablero y, lo más importante, más rápido. El conocimiento de Hyper Api no fue doloroso, la documentación está bien escrita y la integración de la tecnología en nuestro sistema fue fácil.



¡Le agradecemos su atención! Si tiene alguna pregunta o comentario, déjelo en los comentarios.



El artículo fue escrito junto con Vasily Lavrov (VasilyDeOpenSpace) — -



All Articles