D i s e ñ o e i mp l e me n tac i ón d e u n p r ototi p o d e u n a b as e d e...
Transcript of D i s e ñ o e i mp l e me n tac i ón d e u n p r ototi p o d e u n a b as e d e...
Diseño e implementación de un prototipo de una base de datos no relacional con manejo de flujo eficiente en el contexto de alertas astronómicas
por
Diego Mesa Muñoz
Patrocinantes: Guillermo Cabrera Vives, Andrea Rodríguez Tastets
Memoria presentada
para la obtención del título de
INGENIERO CIVIL INFORMÁTICO
Departamento de Ingeniería Informática y Ciencias de la Computación
de la
UNIVERSIDAD DE CONCEPCIÓN
Concepción, Chile
Diciembre, 2018
Índice
Resumen 2
1. Introducción 3
1.1 Objetivo General 4
1.2 Objetivos Específicos 4
2. Conceptos previos y trabajo relacionado 5
2.1 Conceptos previos 5
2.1.1 AVRO 5
2.1.2 Bases de datos NoSQL 6
2.1.3 Streaming de datos 7
2.2 Trabajo relacionado 7
3. Sistema Desarrollado 11
3.1 Análisis 11
3.2 Cassandra 12
3.3 Arquitectura del Sistema y herramientas utilizadas 18
3.4 Modelos de Datos 22
4. Experimentos y Resultados 24
5. Conclusiones 35
6. Trabajo Futuro 36
7. Bibliografía 37
8. Anexo 39
1
Resumen
Dado que en la actualidad el avance de la tecnología en los telescopios modernos
genera más y más datos, la forma de trabajar con estos debe cambiar. Es necesario contar con
sistemas que vayan a la par con las nuevas formas de observar el universo, que puedan
procesar, manejar, clasificar y ayudar al seguimiento de las alertas generadas por la nueva
generación de telescopios de rastreo, que escanean el cielo obteniendo imágenes de regiones
en el espacio. Actualmente se está desarrollando un nuevo sistema de procesamiento de
alertas astronómicas (estos sistemas se conocen como broker) llamado ALeRCE (Automatic
Learning for the Rapid Classification of Events). En el contexto de este sistema, el objetivo
de esta memoria de título fue evaluar mediante la implementación de un prototipo, la
eficiencia del sistema gestor de bases de datos no relacional Apache Cassandra para el
almacenamiento y consultas de un stream de datos en tiempo real de un telescopio. Se simuló
el stream de datos del telescopio Zwicky Transient Facility (ZTF) a través del software de
streaming Apache Kafka y se realizó un análisis experimental sobre el rendimiento de la base
de datos con respecto al tiempo de respuesta tanto de ingestión y consultas. Los resultados
muestran que Cassandra puede soportar la ingestión del stream de datos del telescopio
Zwicky Transient Facility, y responder a las consultas para la clasificación de ALeRCE de
los objetos astronómicos con un tiempo de respuesta que permite procesarlas en tiempo real.
2
1. Introducción
En la actualidad, con el avance de la tecnología, los telescopios modernos cada vez
generan más y más datos, por lo que la forma de trabajar con estos también debe cambiar. En
el caso particular del norte de Chile en que la ciencia de la astronomía se está desarrollando
fuertemente, es necesario contar con sistemas que vayan a la par con las nuevas formas de
observar el universo, que puedan procesar, manejar, clasificar y ayudar al seguimiento de las
alertas generadas por la nueva generación de telescopios de rastreo. Uno de estos telescopios
en construcción es el Large Synoptic Survey Telescope (LSST) que se ubicará en el Cerro
Pachón en la Región de Coquimbo, el cual entrará en funcionamiento el 2022.
Las alertas se generan cada vez que un objeto varía ya sea en posición o brillo con
respecto a una imagen de referencia (por ejemplo explosiones de estrellas, asteroides u
objetos periódicos, entre otros) y se estima que el LSST generará 10 millones de alertas por
noche.
Actualmente se está desarrollando un nuevo sistema de procesamiento de alertas
astronómicas (estos sistemas se conocen como broker) llamado ALeRCE (Automatic
Learning for the Rapid Classification of Events), haciendo referencia al árbol endémico de
Chile y Argentina, que tiene como propósito la rápida clasificación de alertas para poder
realizar un seguimiento en tiempo real a los eventos astronómicos de interés. Esto permitirá
conocer y estudiar objetos o eventos que no se han visto antes en el espacio, o profundizar el
conocimiento de objetos ya conocidos, lo que significa un gran avance en la Astronomía. El
objetivo es poder integrar el sistema ALeRCE a telescopios de rastreo como el Zwicky
Transient Facility (ZTF) ubicado en Estados Unidos, en el observatorio Palomar de San
Diego, y el LSST.
En el contexto del sistema ALeRCE, el desafío del proyecto de memoria de título es
el diseño e implementación de prototipo del sistema de alertas, de una base de datos no
relacional que permita almacenar y consultar en tiempo real los datos de las alertas, con
manejo de flujo (streaming) y restricciones de tiempos de respuesta, es decir, debe ser
3
eficiente debido al gran número de alertas, y de esta forma permitir el uso pertinente de los
recursos astronómicos para poder dar seguimiento a los eventos de interés.
Para el desarrollo de este proyecto se definió un objetivo general y objetivos
específicos que se describirán a continuación.
1.1 Objetivo General
El objetivo general es diseñar e implementar una base de datos no relacional, para
posteriormente, realizar una simulación del streaming de las alertas astronómicas y un
análisis experimental de la eficiencia de la base de datos en tiempo real.
1.2 Objetivos Específicos
● Analizar las diferentes alternativas de bases de datos no relacionales (noSQL).
● Tomar los requisitos del tipo de consultas para el sistema ALeRCE.
● Diseñar la base de datos para las alertas.
● Implementar la base de datos y un prototipo del sistema de alertas.
● Simular el flujo de datos de los telescopios.
● Realizar y analizar pruebas experimentales de escalabilidad.
4
2. Conceptos previos y trabajo relacionado
Para entender de manera correcta el trabajo de memoria de título se explicarán
algunos conceptos asociados a continuación.
2.1 Conceptos previos
2.1.1 AVRO
Las alertas generadas por los telescopios de interés del proyecto, tienen el formato de
archivo AVRO [1]. Este es un sistema de serialización de datos perteneciente a la fundación
de software Apache , y provee lo siguiente:
● Un formato de datos binario compacto y rápido.
● Un contenedor de archivos para guardar datos persistentes.
● Integración simple con lenguajes dinámicos.
Un archivo avro consiste de un encabezado y uno o más bloques de datos. El
encabezado consiste en:
● 4 bytes, ASCII 'O', 'b', 'j', seguido de 1.
● Los metadatos del archivo, incluyendo la definición del esquema, para definirlo
utiliza JSON(JavaScript Object Notation). En la Figura 1 se puede ver un ejemplo de
esquema de un archivo AVRO.
● La marca de sincronización generada al azar de 16 bytes para este archivo.
Un bloque de datos consiste en:
● Un long indicando la cantidad de objetos JSON en el bloque.
● Un long indicando el tamaño en bytes de los objetos JSON serializados en el bloque
actual, después de que se haya aplicado un códec de compresión.
Los códec de compresión pueden ser: null (que simplemente no comprime), deflate
(que utiliza el algoritmo de compresión de deflación), y snappy (que utiliza el
algoritmo de Google snappy).
5
● Los objetos JSON serializados. Si se especificó un códec entonces estarán
comprimidos por ese códec.
● La marca de sincronización del archivo de 16 bytes.
Figura 1. Ejemplo de esquema de un archivo AVRO [1].
2.1.2 Bases de datos NoSQL
Debido a la cantidad de datos que se generan en la actualidad, ya sea en las redes
sociales, en investigaciones científicas, en los telescopios, etc., los sistemas de gestión de
bases de datos relacionales o SGBD comenzaron a presentar dificultades en los aspectos de
escalabilidad y rendimiento, es por esto que surgieron las bases de datos no relacionales o
NoSQL (Non Structured Query Language). Estas difieren del modelo clásico de base de datos
relacionales, ya que poseen una forma de almacenamiento no estructurada, son flexibles y
generalmente no poseen atomicidad ni operaciones JOIN. Además, normalmente las bases de
datos noSQL son sistemas distribuidos, por ende, se debe mencionar el teorema CAP
(Consistency, Availability and Partition Tolerance), que en resumen, enuncia que un sistema
distribuido sólo puede garantizar 2 de las siguientes 3 características:
● Consistencia: Cuando se realice una consulta, el sistema retorne la escritura más
reciente de un registro dado.
● Disponibilidad: Cuando se realice una consulta, el sistema debe retornar una respuesta
en un tiempo razonable, es decir, que no retorne error ni timeout.
● Tolerancia de particiones o tolerancia a fallos: El sistema puede seguir funcionando
aunque fallen nodos o instancias del sistema, se produzcan problemas en la
comunicación entre los nodos, etc.
6
En general los sistemas distribuidos se inclinan por garantizar 2 y parcialmente la
tercera característica dependiendo del problema al que estén dando solución. Al comparar con
un sistema no distribuido, se compensa el no poder garantizar las tres características, al tener
un mayor rendimiento.
Todo lo mencionado anteriormente, permite a las bases de datos NoSQL tener un
rendimiento, flexibilidad y escalabilidad mayor a las bases de datos relacionales a la hora de
trabajar con grandes volúmenes de datos.
2.1.3 Streaming de datos
El Streaming de datos se refiere al flujo de datos, en este caso el de los datos
generados por los telescopios. Específicamente en ZTF se utiliza el software de streaming
Apache Kafka, con el que al generarse alertas, estas son enviadas a un servidor de Kafka
provisto por ZTF permitiendo a los distintos sistemas o brokers conectarse a este para obtener
los datos en tiempo real.
2.2 Trabajo relacionado
El almacenamiento de grandes volúmenes de datos es un tema ampliamente abordado
hace años por todo tipo de organizaciones, específicamente en astronomía, lo cual se
convierte en una de las principales dificultades debido a la cantidad de datos observacionales
que se generan cada noche, por lo que varios estudios se han realizado que proponen mejorar
y/o superar esta dificultad.
Rabl (2012) [2], de la Universidad de Toronto, realizó benchmarks sobre bases de
datos NoSQL de código abierto de distintos tipos. De clave-valor se evaluó Project
Voldemort y Redis, de columnas HBase y Cassandra, y bases de datos de tipo relacionales
escalables VoltDB y MySQL Cluster. Utilizando la herramienta Yahoo! Cloud Serving
Benchmark (YCSB) para las cargas de trabajo o workload, junto con un Application
Performance Management (APM) obtuvo las métricas de las pruebas mostradas en las
7
Figuras 2, en donde se muestra el rendimiento como operaciones por segundo de las distintas
bases de datos versus el número de nodos o instancias de las bases de datos. En la Figura 2.a
se utilizó una carga de trabajo de lectura y escritura, y para en la Figura 2.b se utilizó una
carga de trabajo de lectura, escaneo (lectura de toda la tabla) y escritura.
(a) (b)
Figura 2. (a) Rendimiento para una carga de lectura y escritura, (b) Rendimiento para una
carga de lectura, escaneo (lectura de toda la tabla) y escritura. Imagen reproducida de Rabl
(2012) [2].
(a) (b)
Figura 3. (a) Latencia de lectura para una carga de lectura y escritura, (b) Latencia de
escritura para una carga de lectura y escritura. Imagen reproducida de Rabl (2012) [2].
De acuerdo con esto, Cassandra sobresalió sobre las otras en rendimiento y
escalabilidad, pero no así con respecto a la latencia. Ahora, considerando que Cassandra
escala linealmente en su rendimiento, y que la latencia es un poco mayor con respecto a las
otras bases de datos (10 ms aproximadamente), además, de que esta se mantiene constante
8
con respecto a los nodos, entonces, a una mayor cantidad de nodos Cassandra posee una
ventaja sobre las otras bases de datos.
Ramakrishnan (2013) [3] realizó una evaluación de bases de datos NoSQL, en específico
Cassandra, HBase y MongoDB, para aplicaciones científicas, utilizando datos tanto de
bioinformática como de astronomía. Los resultados se pueden ver en la Figura 4, que muestra
el rendimiento como transacciones o operaciones por segundo de las tres bases de datos
versus distintas cargas de trabajo. Cassandra en la mayoría de las pruebas tuvo un
rendimiento superior a las otras bases de datos.
Figura 4. Benchmark sobre bases de datos noSQL utilizando YCSB. Imagen reproducida de
Ramakrishnan (2013) [3].
Wang (2014) [4], de la Universidad de Ciencia y Tecnología de Kunming en China,
realizó un estudio en el cual se propuso usar la base de datos Fastbit para implementarla en el
NVST (New Vacuum Solar Telescope), el cual genera datos de formato FITS (Flexible
Image Transport System), comúnmente usado en astronomía. En los experimentos obtuvo un
buen rendimiento pero no soporta lectura y escritura de datos concurrentemente, y por ende
no puede guardar los datos en tiempo real. Cabe destacar que este trabajo propone una
solución para almacenar datos astronómicos en una base de datos NoSQL.
9
Zhao (2015) [5], de la Universidad de Massey en Nueva Zelanda, propone usar una
base de datos NoSQL, en específico MongoDB, para almacenar datos astronómicos. Utilizó
los datos del telescopio MOA (Microlensing Observations in Astrophysics), obteniendo
resultados que muestran que es posible almacenar y consultar los datos en tiempo real
utilizando MongoDB. Cabe señalar que MongoDB permite almacenar datos en formato
JSON, lo que sería una propuesta interesante debido a que AVRO es JSON serializado.
Md Athiq Ur Raza Ahamed (2016) [6], evaluó el rendimiento de 3 bases de datos
Cassandra, HBase y MongoDB, utilizando la herramienta Yahoo! Cloud Serving Benchmark
(YCSB) para las cargas de trabajo. Los resultados obtenidos se ven en la Figura 5, que
muestra el rendimiento de las distintas bases de datos como operaciones por segundo versus
el número de nodos o instancias de las bases de datos. Se puede apreciar a Cassandra con un
rendimiento superior sobre las demás al incrementar los nodos.
Figura 5. Benchmark sobre base de datos noSQL sobre un workload de lectura/escritura.
Imagen reproducida de Md Athiq Ur Raza Ahamed (2016) [6].
10
3. Sistema Desarrollado
3.1 Análisis
Primero para elegir la base de datos no relacional adecuada al proyecto es necesario
comprender los datos con los que se trabajará, los que son de formato AVRO. ZTF utiliza un
esquema anidado llamado ztf.alert para organizar los contenidos de una alerta (ver Figura 6),
y a continuación, se explicarán los campos más relevantes del esquema:
● objectId: El identificador único del objeto.
● candidate: Es un esquema llamado ztf.alert.candidate que contiene las características
del objeto observado, dentro de las más importantes están: el tiempo en que fue
observado JD, las coordenadas espaciales RA y DEC, la magnitud de la curva de luz
magpsf, entre otros. Se adjuntará en el anexo el esquema ztf.alert.candidate.
● prv_candidates: Es un arreglo de datos que poseen el esquema ztf.alert.prv_candidate,
esto contiene observaciones anteriores del objeto pero con menos campos que
candidate. Cabe señalar que este valor puede ser null debido a que puede ser la
primera vez que se observa dicho objeto. Se adjuntará en el anexo el esquema
ztf.alert.prv_candidate
● cutoutScience: Imagen actual del objeto en el esquema ztf.alert.cutout que contiene
los bytes de la imagen en formato FITS. Se adjuntará el esquema en el anexo.
● cutoutTemplate: Imagen de referencia para realizar la resta con la actual, también
posee el mismo esquema ztf.alert.cutout
● cutoutDifference: Imagen obtenida de la diferencia entre las imágenes anteriores en el
esquema ztf.alert.cutout.
11
Figura 6. Esquema AVRO de las alertas generadas por ZTF [7].
Actualmente el telescopio ZTF en promedio por día está generando alertas entre los 5
a 15 GigaBytes aproximadamente, lo que se traduce a una cantidad entre 100.000 y 300.000
archivos AVRO, por lo que debe implementar una base de datos capaz de soportar este flujo
de datos.
Existen diversos tipos de bases de datos entre las cuales existen clave-valor, de
columnas (más parecidas a las relacionales), de documentos y orientada a grafos. Para el
efecto de la memoria de título se tomaron en cuenta las bases de datos open-source o de
código abierto, es decir, gratuitas para la elección de un sistema de gestión de bases de datos.
Además de los siguientes puntos a considerar: rendimiento, escalabilidad, flexibilidad,
tolerancia a fallos (si un componente falla no detiene su funcionamiento), sin un único punto
de fallo (que no posee un componente clave, que al fallar detenga el funcionamiento de todo
el sistema), documentación y comunidad.
3.2 Cassandra
El sistema de gestión de bases de datos Apache Cassandra es usado ampliamente en la
actualidad, debido a sus características y su funcionamiento, que serán mencionadas a
continuación. Pero antes, para comprender de mejor manera este trabajo, desde ahora en
12
adelante se llamará nodo a un servidor o máquina que tenga instalada una instancia de
Cassandra, y clúster al conjunto de nodos interconectados.
● Posee tolerancia a fallos debido a su replicación de los datos a otros nodos, puede
soportar la caída de estos y reemplazarlos sin tiempo de inactividad.
● Es descentralizado, todos los nodos tienen el mismo rol dentro del clúster, lo que se
traduce a no tener un punto único de fallo.
● Es flexible, permite tener tuplas con distintos tamaños y campos.
● Como se apreció en los trabajos relacionados mencionados anteriormente, Cassandra
posee escalabilidad y rendimiento superior a otras alternativas NoSQL.
● Posee durabilidad, para aplicaciones que no pueden soportar la pérdida de datos, una
vez que se escribe en la base de datos, estos sobrevivirán permanentemente.
El proceso de escritura en Cassandra es de la siguiente forma (ver Figura 7):
● Lo primero que hace es escribir los datos en el Commit log para asegurar durabilidad.
● Luego se escriben los datos en la estructura en memoria memtable, la cual los
almacena de forma ordenada y hasta un tamaño configurable.
● Memtable envía los datos a disco a una estructura llamada SSTable (operación Flush),
esta es inmutable después de ser escrita.
● A la vez que se realiza la operación Flush, los datos que estaban en Commit log son
eliminados y se crea un índice de partición en disco que mapea el lugar en disco en
donde están las SSTables.
Figura 7. Proceso de escritura de Cassandra [8].
13
Los datos en Cassandra se mantienen de la siguiente forma (ver Figura 8):
● Dado que la estructura SSTable es inmutable, para inserciones o actualizaciones para
un registro, Cassandra inserta nuevas SSTable con estampillas de tiempo, lo que hace
que pueden existir varias para un mismo dato.
● Para las operaciones de eliminación no se borra inmediatamente el o los datos, si no
que son marcados como tumbas (Tombstones).
● Para reducir la cantidad de SSTables, Cassandra realiza un proceso de compactación
que consiste en lo siguiente:
○ Se compacta una colección de SSTables, de esta se toman todas las versiones
de cada registro único con la fecha más reciente de cada uno.
○ Se realiza una unión de estas tuplas actualizadas en una nueva SSTable y los
registros antiguos o marcados como tumbas se borran.
○ Existen varias estrategias configurables para la compactación.
Figura 8. Compactación de Cassandra [8].
14
El proceso de lectura en Cassandra es de la siguiente forma (ver Figura 9):
● Para completar una lectura, se lee de memtable y de SSTables.
● Se lee memtable, si está el dato requerido se mezclará con el dato de la SSTable.
● Se chequea la caché de filas (row cache) que como toda base de datos mantiene una
caché de los datos accedidos recientemente.
● Si el dato no está en la caché de filas, se chequea el Bloom Filter, una función
probabilística que permite saber qué SSTables son las más probables a tener los datos
requeridos.
● Luego se lee la caché de clave de partición (Partition key cache), si se tiene encuentra
la clave de la partición requerida se sigue a Compression offset, si no está se va a el
resumen de particiones (Partition Summary).
● En el resumen de particiones se encuentra una muestreo del índice de partición
(Partition index), este contiene una clave de partición cada X claves, y mapea la
ubicación dentro del índice de partición, para un acceso más rápido a disco.
● Se accede al índice de particiones en donde se encuentra el mapeo a la posición en
disco de cada partición.
● Posteriormente se accede a Compression offsets en donde se encuentra el puntero a
disco para el dato requerido.
● Finalmente se recupera el dato en disco y se mezcla con el dato en memtable.
Figura 9. Proceso de lectura de Cassandra [8].
15
Lo anterior mencionado se aplica a un nodo de Cassandra, para comprender cómo
funciona un clúster de nodos, primero se debe explicar cómo se comunican, y luego cómo
realiza la distribución y la replicación de datos en su arquitectura descentralizada de forma de
“anillo” (Ver Figura 10).
Figura 10. Clúster de nodos de Cassandra. [9]
Los nodos se comunican entre sí a través de un protocolo de comunicación de igual a
igual llamado gossip, en el cual periódicamente se intercambia información sobre el estado
del mismo nodo y sobre otros nodos que conozca. Esto se ejecuta cada ciertos segundos y la
comunicación de un nodo va de 1 hasta 3, con distintos nodos en cada periodo, de esta
manera cada nodo conoce el estado del clúster.
Cassandra distribuye los datos automaticamente a través del clúster, y para determinar
cómo distribuirlos utiliza un particionador. Este es un algoritmo hash que toma la clave
primaria de una tupla, computa una cadena de caracteres o token y luego lo asigna a uno de
los nodos. Cabe señalar que cada nodo tiene un rango de tokens, de ahí su representación en
forma de anillo.
El particionador es un elemento configurable en Cassandra y el por defecto es
murmur3, que asegura una distribución equitativa entre los nodos. Cabe señalar que
Cassandra automáticamente mantiene una distribución equitativa después de remover o
añadir nodos al clúster.
16
La replicación de datos en Cassandra es directa y fácilmente configurable. Se llama
factor de replicación a la cantidad de copias de datos que se encuentra en el clúster, por
ejemplo, con un factor de replicación de 2 se encontrarán 2 copias de cada tupla en el clúster.
Esto es para asegurar la tolerancia a fallos, ya que al fallar un nodo del clúster todavía se
tendrán los datos en otros nodos que están funcionando correctamente.
Dado esto, por su escalabilidad y rendimiento, además de que Cassandra cumple con
los requisitos descritos anteriormente, se eligió como la posible solución a ser la base de
datos NoSQL que almacenará las alertas de los telescopios, y será sometida a pruebas de
rendimiento.
3.3 Arquitectura del Sistema y herramientas utilizadas
Para el efecto de la memoria de título se trabajó en un ambiente de desarrollo,
específicamente en el servidor Rafike del departamento de Ingeniería Informática y Ciencias
de la Computación de la Universidad de Concepción, que tiene las siguientes
especificaciones:
● Marca: HP
● Modelo: ProLiant DL180 G6
● CPU: 2x Intel Xeon E5620
● Memoria: 64GB
● 4x Kingston DDR3 8GB (9965516-069.A00LF)
● 8x Micron DDR3 4GB (36JSZF51272PZ1G4F1)
● Disco duro: 9TB
● 4x Western Digital Red 3TB (RAID5)
● SO: Ubuntu 18.04
● Fecha Inst. SO: 26/04/2018
En este servidor se instalaron máquinas virtuales a través de Oracle VM VirtualBox y
cada una de las siguientes especificaciones:
17
● CPU: 1 Core del CPU de Rafike
● Memoria: 8 GB
● Disco duro: 250 GB
● Conexión interna: nat network para la comunicación entre las máquinas
● Conexión externa: NAT
● SO: Ubuntu 16.04 LTS
En las máquinas virtuales se instaló la base de datos Apache Cassandra,
específicamente la versión 3.11.2.
La configuración de Cassandra para la base de datos que será sometida a pruebas es:
● Estrategia de Replicación: NetworkTopologyStrategy, para que Cassandra tome en
cuenta la ubicación de los nodos para almacenar los datos y sus réplicas (racks y
datacenters)
● Comunicación entre Nodos: GossipingPropertyFileSnitch, para que se comuniquen
los nodos de manera correcta con la estrategia de replicación NetworkTopology (se
toma en cuenta racks y datacenters, acercándose a la realidad).
También en la configuración más específica se cambió la estrategia de disco a
“spinning” ya que por defecto se utiliza para discos de estado sólido, también se amplió el
rendimiento de compactación de 16 a 32 MB (A mayor cantidad de datos insertándose se
necesita mayor velocidad de compactación).
Se programó un script en Python 3.5 elegido debido a su integración con Kafka,
Cassandra y los códigos públicos de los telescopios, dentro de los que se usó como base un
“Jupyter Notebook” provisto por ZTF [10] y las siguientes librerías:
➔ tarfile: Para descomprimir las alertas comprimidas.
➔ fastavro: Para leer los archivos de formato avro y procesarlos.
➔ cassandra-driver: Para conectarse y realizar las queries a Cassandra
➔ kafka: Para conectarse al servidor de kafka, enviar y recibir las alertas.
18
Se simuló la conexión a las alertas astronómicas provenientes de los telescopios a
través del software de streaming Apache Kafka elegido debido a que es utilizado por ZTF. En
una de las máquinas se implementó el servidor principal de Kafka, que funciona de
intermediario para enviar y recibir datos, para esto se crea un tema o topic al cual los
interesados pueden conectarse o suscribirse ya sea para mandar datos o recibirlos. Luego en
la misma máquina a través de Python se implementó la API “Producer”, qué es la encargada
de “producir” datos en el tema, se tomaron las alertas en formato AVRO y se enviaron como
mensajes, es decir, secuencialmente una después de la otra. Simultáneamente se implementó
la API “Consumer” que como su nombre lo describe es la encargada de “consumir” o recibir
datos al suscribirse al topic. En esta última máquina se programó la conexión a la base de
datos para que al recibir los mensajes de Kafka los enviara al clúster de Cassandra para
realizar las inserciones y consultas de los datos con el objetivo de hacer las mediciones
correspondientes (ver Figura 11).
Figura 11. Arquitectura del sistema con la simulación de streaming.
Para acercarse a la situación real en la cual se le harán consultas a la base de datos
Cassandra, se implementaron máquinas virtuales en el servidor Coliumo también del
departamento de Ingeniería Informática y Ciencias de la Computación de la Universidad de
Concepción, que tiene las siguientes especificaciones:
19
● Marca: Dell
● Modelo: PowerEdge R530
● CPU: 1x Intel Xeon E5-2620
● Memoria: 32GB
● 2x DIMM Synchronous 2400 Mhz 16GB (M393A2K43BB1-CRC)
● Disco duro: 2TB
● 1x Seagate ST2000NM0145-2DC 2TB
● SO: Ubuntu 16.04
● Fecha Inst. SO: 19/01/2017
En este servidor se instalaron máquinas virtuales a través de Oracle VM VirtualBox y
cada una de las siguientes especificaciones:
● CPU: 1 Core del CPU de Coliumo
● Memoria: 2 GB
● Disco duro: 50 GB
● Conexión externa: NAT
● SO: Ubuntu 16.04 LTS
Cada máquina realizará consultas a Cassandra simultáneamente a través de scripts en
Python con la librería cassandra-driver mencionada anteriormente, con el objetivo de estresar
a la base de datos y medir los tiempos de respuesta. Luego, el sistema en conjunto se describe
en la Figura 12.
20
Figura 12. Arquitectura global del sistema.
3.4 Modelos de Datos
Lo primero antes de crear un modelo de datos, es saber qué tipo de consultas o queries
se realizarán sobre él, las cuales son:
● Consultas sobre el objeto de la alerta que se ingiere, es decir, recuperar el historial del
objeto ingresado para clasificar.
● Consultas sobre rangos, por ejemplo pueden ser las alertas que ocurrieron entre
coordenadas en el espacio en los campos RA (right ascension) y DEC (declination).
Estas coordenadas son llamadas ecuatoriales y permiten ubicar un objeto en el
espacio, RA tiene su equivalente con la longitud geográfica y DEC tiene su
equivalente con la latitud geográfica. Otro ejemplo es el de consultas por rango de
alertas que ocurrieron entre un determinado tiempo, con el campo MJD (Modified
Julian Date), este es un formato de fecha, y proviene de una variación del formato JD
(Julian Date). El formato JD es un número decimal que cuenta los días desde que
comenzó el periodo Julian el 1 de enero de 4713 AC al mediodía. Para transformar de
JD a MJD simplemente se resta el número 2400000.5.
21
● Consultas sobre un registro puntual, por ejemplo buscar una alerta en específico de un
objeto.
Tomando esto en cuenta, se diseñó un modelo de datos para Cassandra, con el
siguiente esquema de tablas (amarillo significa Primary Key):
ztf_alert_candidate_simple
Campo ObjID MJD band ...
Tipo de dato text double text ...
Tabla 1. Primera tabla de alertas con los datos de candidate.
La Tabla 1 posee dos claves primarias, siendo ObjID el identificador del objeto y
MJD la fecha en que se observó, luego están los campos con los datos astronómicos del
objeto, en total son 101 columnas.
ztf_alert_prv_candidate_simple
Campo ObjID MJD_cand mjd band ...
Tipo de dato text double double text ...
Tabla 2. Segunda tabla de datos de alertas con los datos de prv_candidate.
La Tabla 2 posee 3 claves primarias, ObjID siendo el identificador del objeto,
MJD_cand el campo MJD de la tabla candidate y mjd la fecha del “previous candidate” de
modo que para un objeto de un día, pueden existir cero o varios previous candidate. Esta
tabla posee 52 columnas.
ztf_alert_cutout_simple
Campo ObjID MJD_cand cutoutScience cutoutTemplate cutoutDifference
Tipo de dato text double text text text
Tabla 3. Tercera tabla de datos de alertas con los datos de cutout.
22
La Tabla 3 guardará las imágenes del objeto, teniendo como clave primaria el
identificador del objeto y el MJD de la tabla candidate, y luego los campos de tipo text, que
almacenará la ruta en donde estará la imagen correspondiente, debido a que al guardar la
imagen en la base de datos incrementa mucho su tamaño, y eso dificultará la labor de
administración (backups y restauraciones más lentos, tiempos de bloqueo de la base de datos
mayores).
4. Experimentos y Resultados
Con el objetivo de evaluar los tiempos de respuesta de Apache Cassandra con los
datos de ZTF, se realizaron varios experimentos tanto de inserción como de consultas,
utilizando la arquitectura descrita anteriormente. Cabe señalar que para el efecto de las
pruebas con el simulador de streaming, se tomó un conjunto de alertas astronómicas al azar
desde la página oficial de ZTF [11].
Se realizaron experimentos utilizando el simulador de streaming de ZTF, con el
objetivo de medir, simultáneamente, los tiempos de respuesta de las inserciones de alertas, y
las consultas por el historial del objeto al cual pertenece la alerta, es decir, buscar todas las
alertas sobre ese objeto. Se utilizó la configuración de 3 nodos de Cassandra, implementados
con 3 máquinas virtuales en el servidor Rafike, con un factor de replicación de datos de 2. En
la Figura 13, se muestra el tiempo, en segundos, de la inserción de alertas a través del
simulador de streaming versus el tamaño de la base de datos en registros o tuplas. Cabe
señalar que cada registro representa una alerta insertada en la base de datos. En la Figura 14,
se muestra el tiempo, en segundos, de las consultas por historial de objeto versus el tamaño
de la base de datos.
23
Figura 13. Tiempo de inserción versus Tamaño base de datos
Viendo el gráfico de inserción (segundos) versus el tamaño de la base de datos
(registros), se puede apreciar en primera instancia que se mantiene constante con respecto al
tamaño de la base de datos.
Figura 14. Tiempo de consulta historial de objeto versus Tamaño base de datos.
Según el gráfico de tiempo de consultas por historial de objeto versus el tamaño de la
base de datos, se puede notar que el tiempo también ha permanecido constante, pero su
desviación estándar fue en aumento.
24
Para realizar pruebas de mayor estrés para Cassandra, se construyeron varias bases de
datos desde 10 mil registros creciendo exponencialmente a 100 mil, 1 millón, 10 millones y
50 millones de registros de alertas con datos fabricados de igual magnitud que los reales,
debido a que todavía no existen 50 millones de alertas en la página oficial de ZTF. Estas
bases de datos fueron sometidas a experimentos de ingestión, a través del simulador de
streaming de datos, con el objetivo de medir los tiempos de respuesta de la inserción y las
consultas por historial de objeto, a medida que incrementa el tamaño de la base de datos. Se
utilizó la misma configuración mencionada anteriormente, de 3 nodos de Cassandra con un
factor de replicación de 2. Los resultados se pueden ver en la Figura 15, que muestra el
tiempo de inserción versus el tamaño de la base de datos, en este gráfico se puede apreciar
que el tiempo de inserción en Cassandra se mantiene constante con respecto al tamaño de la
base de datos. De lo que también se puede concluir es que Cassandra puede soportar la
ingestión del telescopio de ZTF si tomamos el promedio de inserción menor a 0.05 segundos
y lo multiplicamos por el promedio de alertas por día de 200000, da un valor de 2.77 horas,
es lo que se demoraría en la ingestión, lo que está dentro del tiempo válido para procesar el
streaming de datos, que dura aproximadamente de 10 a 12 horas.
Los resultados de las mediciones del tiempo de respuesta de las consultas se pueden
ver en la Figura 16, en donde se muestra el tiempo de consultas por historial del objeto
durante el streaming de datos versus el tamaño de la base de datos. Viendo este gráfico, se
puede apreciar que el tiempo de respuesta de las consultas por el historial de objetos durante
el streaming en Cassandra, se mantienen constantes, pero no así su desviación estándar que
aumenta con el tamaño de la base de datos. Aún así si tomamos el promedio de tiempo de
0.025 segundos y lo multiplicamos por un día promedio de alertas de 200000, da el valor de
1.38 horas, lo que es un tiempo relativamente corto con respecto a lo que demora el streaming
de datos, además de que esto es en concurrencia con la ingestión.
25
Figura 15. Ingestión streaming de datos: Tiempo inserción versus Tamaño base de datos.
Figura 16. Tiempo de consultas por historial del objeto durante streaming versus Tamaño
base de datos.
También se realizaron experimentos con el objetivo de evaluar el comportamiento del
rendimiento del clúster en una situación más cercana a la realidad en donde se estará
constantemente consultando a la base de datos. Esto se realizó efectuando 10 mil consultas
simultáneamente por registros y por rangos, mediante 5 máquinas virtuales implementadas en
el servidor Coliumo, las que de ahora en adelante serán denominadas workers. Primero, se
realizaron las pruebas por registros, los resultados se pueden ver en la Figura 17, la que
muestra el tiempo promedio de respuesta de las consultas por registros puntuales de alertas
26
versus el tamaño de la base de datos. Los resultados de las consultas por historial de objeto se
pueden ver en la Figura 18, que muestra el promedio de los tiempos de respuesta de las
consultas del historial de un objeto versus el tamaño de la base de datos. En estas dos pruebas
el tiempo de respuesta de Cassandra se mantiene constante al aumentar el tamaño de la base
de datos.
Figura 17. Tiempo consultas con 5 workers versus Tamaño base de datos (Prueba consulta
Alerta)
Figura 18. Tiempo consultas con 5 workers versus Tamaño base de datos (Prueba consulta H
historial objeto).
27
Posteriormente, se sometió al clúster de 3 nodos a un workload de lectura de consultas
por rango a través de los workers. Cabe señalar que las consultas por rango fueron de rangos
al azar, pero estaban limitadas a retornar 1000 registros. La primera prueba de rango fue de
los campos ra y dec, es decir, una búsqueda de alertas que estén en un sector del espacio. Los
resultados se pueden ver en la Figura 19, que muestra el promedio de los tiempos de
respuesta de las consultas por rango espacial versus el tamaño de la base de datos. Después se
realizó la prueba con las consultas por rango de tiempo con el campo mjd. Los resultados se
pueden ver en la Figura 20, que muestra el promedio de los tiempo de respuesta de las
consultas por rango temporal versus el tamaño de la base de datos.
La hipótesis que se tiene a que los tiempos de respuesta sean mayores en las bases de
datos de menor tamaño, es debido a que son consultas del tipo rango, por lo cual se deben
revisar los datos que están distribuidos en 3 nodos, lo que significa que mientras menos datos
existan en la base de datos, más probabilidad hay de que Cassandra tenga que pasar al
siguiente nodo buscando el rango deseado. Esto se traduce a más tiempo ya que los otros
nodos también están procesando consultas.
Figura 19. Tiempo consultas con 5 workers vs Tamaño base de datos (Prueba rango por ra y
dec).
28
Figura 20. Tiempo consultas con 5 workers vs Tamaño base de datos (Prueba rango por mjd).
Con el objetivo de ver el comportamiento del clúster al variar el número de máquinas
o workers realizando consultas, se realizó el experimento de efectuar consultas por historial
de objeto a la base de datos de 50 millones de registros variando el número de workers. Los
resultados se pueden ver en la Figura 21, que muestra el promedio de los tiempos de
respuesta de las consultas por historial de objeto versus el número de workers, en donde se
puede apreciar que los tiempos de respuesta se mantienen constantes hasta 5 workers.
Figura 21. Tiempo consultas por objeto versus Número de workers (Base de datos con 50
millones de registros).
29
Para los siguientes experimentos se incrementó la cantidad de nodos del clúster de
Cassandra con el objetivo de evaluar el comportamiento de los tiempos de respuesta. Cabe
señalar que el proceso de añadir nodos o máquinas con instancias de Cassandra es
relativamente simple y el tiempo depende del tamaño de la base de datos, como también del
factor de replicación, lo que hace de Cassandra aún más apta para la escalabilidad. Se sometió
a pruebas de estrés los nuevos clúster de Cassandra de 4, 5 y 6 nodos, todos con un factor de
replicación de 2, incluyendo el primer clúster de 3 nodos. Con el fin de comparar el
comportamiento de los tiempos de respuesta de los distintos clúster, se realizó la prueba de la
ingestión y consultas por el historial de objetos del streaming de datos, en la base de datos de
50 millones de registros para cada clúster. Los resultados se pueden ver en la Figura 22, que
muestra los tiempos de respuesta de inserción de los distintos clúster versus el número de
nodos del clúster. Luego en la Figura 23, se muestran los resultados de los tiempos de
respuesta de consultas por historial de objeto durante la ingestión del streaming de datos
versus el número de nodos. Estas dos pruebas se realizaron con bases de datos de 50 millones
de registros para cada clúster. Los resultados muestran que Cassandra se mantiene en
promedio constante y que su desviación estándar en ambos casos disminuye al incrementar
los nodos.
Figura 22. Tiempo promedio inserción versus Número de nodos Cassandra.
30
Figura 23. Tiempo consulta promedio por historial de objeto durante streaming de datos
versus Número de nodos de Cassandra.
Con el objetivo de evaluar y comparar el comportamiento de los distintos clúster,
utilizando los workers se realizó la prueba de estrés de lectura sobre registros puntuales de
alertas, los resultados se ven en la Figura 24, que muestra el comportamiento de los distintos
clúster con los tiempos promedio de respuesta de las consultas por alertas versus el tamaño de
la base de datos. De la misma forma, se ejecutó la prueba sobre el historial de objetos, los
resultados se ven en la Figura 25, que muestra el comportamiento de los distintos clúster con
los tiempos promedio de respuesta de las consultas por historial de objeto versus el tamaño de
la base de datos. Los resultados muestran que los tiempos de respuesta se mantienen
constantes en ambas pruebas y que tiene un rendimiento más estable incrementando nodos.
31
Figura 24. Comparación nodos de Cassandra: Tiempo consultas por alertas con 5
workers versus Tamaño Base de Datos.
Figura 25. Comparación nodos de Cassandra: Tiempo consultas por historial de objeto
con 5 workers versus Tamaño Base de datos.
Posteriormente se realizaron las pruebas por rango espacial, los resultados se ven en la
Figura 26, que muestra el comportamiento de los distintos clúster con los tiempos promedio
de respuesta de las consultas por rango espacial versus el tamaño de la base de datos. Luego
se efectuaron las pruebas por rango temporal, los resultados se ven en la Figura 27, que
muestra el comportamiento de los distintos clúster con los tiempos promedio de respuesta de
las consultas por rango temporal versus el tamaño de la base de datos. En ambos casos se
32
puede ver que Cassandra mejora sus tiempos de respuesta al incrementar nodos, debido a que
permite más operaciones simultáneamente, este resultado se torna importante a la hora de
consultas que toman más tiempo como son las de rango, ya que aliviana el trabajo de cada
nodo y lo distribuye hacia otros.
Figura 26. Comparación nodos Cassandra: Tiempo consultas por rango espacial con 5
workers versus Tamaño Base de datos.
Figura 27. Comparación nodos Cassandra: Tiempo consultas por rango temporal con
5 workers versus Tamaño Base de datos.
33
5. Conclusiones
Debido a que en la actualidad las observaciones al universo están generando una
cantidad de datos cada vez mayor, se necesitan de sistemas capaces de procesarlos. En este
contexto nace ALeRCE, dentro del cual se requiere una base de datos capaz de soportar la
ingestión de los streaming de datos de los telescopios en un tiempo razonable, como también
responder a las consultas que se realizarán eficientemente debido a la cantidad de registros
que tendrá.
En este trabajo de memoria de título se cumplieron los objetivos propuestos, se
investigaron distintas opciones de sistemas gestores de bases de datos, se tomaron los
requisitos del tipo de consultas que se realizarán, y luego diseñó e implementó un prototipo
del sistema de alertas, que propone usar Apache Cassandra como el motor de base de datos
de ALeRCE.
Se realizaron pruebas para evaluar si el sistema de gestión de bases de datos Apache
Cassandra, podría soportar en tiempo real un día promedio de inserciones de alertas y
consultas por el historial del objeto al que pertenece la alerta, simulando el streaming de datos
de ZTF, que duraría aproximadamente 10 a 12 horas. Los resultados de las pruebas muestran
que el sistema de bases de datos puede soportar simultáneamente la ingestión del streaming
de ZTF y las consultas por el historial de objetos, en un tiempo promedio considerablemente
menor al que duraría el streaming, de 2.77 horas aproximadamente para la ingestión, y 1.38
horas aproximadamente para las consultas.
En los experimentos realizados a través de los workers, los resultados muestran que
los tiempos de respuesta de Cassandra con 5 máquinas realizando consultas simultáneamente,
aún escalando a un tamaño de 50 millones de registros, se mantienen en promedio constantes
y menores a 0.03 segundos, a excepción de las consultas por rango, como fueron definidas en
este trabajo, los tiempos de respuesta en promedio se mantienen bajo los 2 segundos. Esto se
traduce en que los distintos programas que se conecten y realicen consultas a la base de datos
podrán hacerlo con dichos tiempos de respuesta. Lo que significa que Cassandra puede
34
soportar tanto la ingestión, como las consultas en una situación real, sin ningún
inconveniente, y en un tiempo válido para procesar el streaming de alertas astronómicas de
ZTF. Por lo tanto, se propone a Apache Cassandra como una solución posible a implementar
en el sistema ALeRCE.
En términos de escalabilidad al implementar más nodos se permitirán más consultas y
a tiempos de respuesta menores de los que se obtuvieron en este trabajo, lo que significa que
de abrirse el sistema a la comunidad científica, permitirá a más astrónomos buscar datos
relevantes sobre los objetos deseados, y así poder realizar su investigación.
6. Trabajo Futuro
En las ciencias como astronomía una de las grandes dificultades es el almacenamiento
de datos debido a su gran tamaño, es por esto que se actualmente se están estudiando varios
motores de bases de datos tanto relacional como NoSQL para superar esta situación. En este
contexto de esta memoria de título se evalúo Cassandra simulando el streaming de datos de
ZTF y realizando consultas sobre esta, pero se requiere una evaluación más rigurosa para los
telescopios que se construirán a futuro, debido a las especulaciones que estos generarán hasta
100 veces más datos que los actuales. A continuación se dan sugerencias de un posible
trabajo a futuro en el contexto de esta memoria:
● Realizar evaluaciones experimentales con Cassandra con más de 100 millones de
registros o alertas e incrementar el tamaño exponencialmente si el hardware lo
soporta.
● Añadir más nodos a Cassandra y realizar experimentos con más workers estresando a
la base de datos.
● Realizar varios experimentos con distintas bases de datos NoSQL, Cassandra incluida,
con el objetivo de evaluarlas y compararlas para el contexto de astronomía.
35
7. Bibliografía
[1] Apache Avro, Apache Avro 1.8.2 Documentation,
http://avro.apache.org/docs/1.8.2/
[2] Tilmann Rabl, Mohammad Sadoghi, Hans-Arno Jacobsen, Sergio Gomez-Villamor,
Victor Muntes-Mulero & Serge Mankovskii, Solving Big Data Challenges for Enterprise
Application Performance Management, 2012.
[3] Lavanya Ramakrishnan, Pradeep K. Mantha, Yushu Yao, Richard S. Canon, Evaluation
of NoSQL and Array Databases for Scientific Applications, Lawrence Berkeley National Lab,
2013.
[4] Feng Wang, Ying-Bo Liu, Kai-Fan Ji, Hui Deng, Wei Dai, Bo Liang, NVST Data
Archiving System Based On Fastbit NoSQL Database, 2014.
[5] Yu Zhao, Event based transient notification architecture and NoSQL solution for
astronomical data management, 2015.
[6] Md Athiq Ur Raza Ahamed, Benchmarking Top NoSQL Databases, 2016.
[7] Zwicky Transient Facility, Schema, alert.avsc,
https://github.com/ZwickyTransientFacility/ztf-avro-alert/blob/master/schema/alert.avsc
[8] DataStax, How cassandra reads and writes data,
https://docs.datastax.com/en/cassandra/3.0/cassandra/dml/dmlIntro.html
[9] DataStax Academy, Brief introduction to Apache Cassandra,
https://academy.datastax.com/units/brief-introduction-apache-cassandra?resource=brief-intro
duction-apache-cassandra
36
[10] Zwicky Transient Facility, Working with avro files,
https://github.com/ZwickyTransientFacility/ztf-avro-alert/blob/master/notebooks/Working_w
ith_avro_files.ipynb
[11] Zwicky Transient Facility, ZTF Alert Archive,
https://ztf.uw.edu/alerts/public/
37
8. Anexo
Para la mejor comprensión de los datos con los que se trabajaron en esta memoria de
título, se presentarán los siguientes esquemas AVRO: ztf.alert.candidate,
ztf.alert.prv_candidate y ztf.alert.cutout.
● ztf.alert.candidate:
{
"namespace": "ztf.alert",
"name": "candidate",
"doc": "avro alert schema",
"version": "3.2",
"type": "record",
"fields": [
{"name": "jd", "type": "double", "doc": "Observation Julian date at start of exposure [days]"},
{"name": "fid", "type": "int", "doc": "Filter ID (1=g; 2=R; 3=i)"},
{"name": "pid", "type": "long", "doc": "Processing ID for science image to facilitate archive
retrieval"},
{"name": "diffmaglim", "type": ["float", "null"], "default": null, "doc": "Expected 5-sigma
mag limit in difference image based on global noise estimate [mag]"},
{"name": "pdiffimfilename", "type": ["string", "null"], "default": null, "doc": "filename of
positive (sci minus ref) difference image"},
{"name": "programpi", "type": ["string", "null"], "default": null, "doc": "Principal investigator
attached to program ID"},
{"name": "programid", "type": "int", "doc": "Program ID: encodes either public, collab, or
caltech mode"},
{"name": "candid", "type": "long", "doc": "Candidate ID from operations DB"},
{"name": "isdiffpos", "type": "string", "doc": "t or 1 => candidate is from positive (sci minus
ref) subtraction; f or 0 => candidate is from negative (ref minus sci) subtraction"},
{"name": "tblid", "type": ["long", "null"], "default": null, "doc": "Internal pipeline table
extraction ID"},
{"name": "nid", "type": ["int", "null"], "default": null, "doc": "Night ID"},
38
{"name": "rcid", "type": ["int", "null"], "default": null, "doc": "Readout channel ID [00 ..
63]"},
{"name": "field", "type": ["int", "null"], "default": null, "doc": "ZTF field ID"},
{"name": "xpos", "type": ["float", "null"], "default": null, "doc": "x-image position of
candidate [pixels]"},
{"name": "ypos", "type": ["float", "null"], "default": null, "doc": "y-image position of
candidate [pixels]"},
{"name": "ra", "type": "double", "doc": "Right Ascension of candidate; J2000 [deg]"},
{"name": "dec", "type": "double", "doc": "Declination of candidate; J2000 [deg]"},
{"name": "magpsf", "type": "float", "doc": "Magnitude from PSF-fit photometry [mag]"},
{"name": "sigmapsf", "type": "float", "doc": "1-sigma uncertainty in magpsf [mag]"},
{"name": "chipsf", "type": ["float", "null"], "default": null, "doc": "Reduced chi-square for
PSF-fit"},
{"name": "magap", "type": ["float", "null"], "default": null, "doc": "Aperture mag using 14
pixel diameter aperture [mag]"},
{"name": "sigmagap", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty in
magap [mag]"},
{"name": "distnr", "type": ["float", "null"], "default": null, "doc": "distance to nearest source
in reference image PSF-catalog [pixels]"},
{"name": "magnr", "type": ["float", "null"], "default": null, "doc": "magnitude of nearest
source in reference image PSF-catalog [mag]"},
{"name": "sigmagnr", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty in
magnr [mag]"},
{"name": "chinr", "type": ["float", "null"], "default": null, "doc": "DAOPhot chi parameter of
nearest source in reference image PSF-catalog"},
{"name": "sharpnr", "type": ["float", "null"], "default": null, "doc": "DAOPhot sharp
parameter of nearest source in reference image PSF-catalog"},
{"name": "sky", "type": ["float", "null"], "default": null, "doc": "Local sky background
estimate [DN]"},
{"name": "magdiff", "type": ["float", "null"], "default": null, "doc": "Difference: magap -
magpsf [mag]"},
{"name": "fwhm", "type": ["float", "null"], "default": null, "doc": "Full Width Half Max
assuming a Gaussian core, from SExtractor [pixels]"},
{"name": "classtar", "type": ["float", "null"], "default": null, "doc": "Star/Galaxy classification
score from SExtractor"},
39
{"name": "mindtoedge", "type": ["float", "null"], "default": null, "doc": "Distance to nearest
edge in image [pixels]"},
{"name": "magfromlim", "type": ["float", "null"], "default": null, "doc": "Difference:
diffmaglim - magap [mag]"},
{"name": "seeratio", "type": ["float", "null"], "default": null, "doc": "Ratio: difffwhm /
fwhm"},
{"name": "aimage", "type": ["float", "null"], "default": null, "doc": "Windowed profile RMS
afloat major axis from SExtractor [pixels]"},
{"name": "bimage", "type": ["float", "null"], "default": null, "doc": "Windowed profile RMS
afloat minor axis from SExtractor [pixels]"},
{"name": "aimagerat", "type": ["float", "null"], "default": null, "doc": "Ratio: aimage /
fwhm"},
{"name": "bimagerat", "type": ["float", "null"], "default": null, "doc": "Ratio: bimage /
fwhm"},
{"name": "elong", "type": ["float", "null"], "default": null, "doc": "Ratio: aimage / bimage"},
{"name": "nneg", "type": ["int", "null"], "default": null, "doc": "number of negative pixels in a
5 x 5 pixel stamp"},
{"name": "nbad", "type": ["int", "null"], "default": null, "doc": "number of prior-tagged bad
pixels in a 5 x 5 pixel stamp"},
{"name": "rb", "type": ["float", "null"], "default": null, "doc": "RealBogus quality score; range
is 0 to 1 where closer to 1 is more reliable"},
{"name": "ssdistnr", "type": ["float", "null"], "default": null, "doc": "distance to nearest
known solar system object if exists within 30 arcsec [arcsec]"},
{"name": "ssmagnr", "type": ["float", "null"], "default": null, "doc": "magnitude of nearest
known solar system object if exists within 30 arcsec (usually V-band from MPC archive)
[mag]"},
{"name": "ssnamenr", "type": ["string", "null"], "default": null, "doc": "name of nearest
known solar system object if exists within 30 arcsec (from MPC archive)"},
{"name": "sumrat", "type": ["float", "null"], "default": null, "doc": "Ratio: sum(pixels) /
sum(|pixels|) in a 5 x 5 pixel stamp where stamp is first median-filtered to mitigate outliers"},
{"name": "magapbig", "type": ["float", "null"], "default": null, "doc": "Aperture mag using 18
pixel diameter aperture [mag]"},
{"name": "sigmagapbig", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty
in magapbig [mag]"},
{"name": "ranr", "type": "double", "doc": "Right Ascension of nearest source in reference
40
image PSF-catalog; J2000 [deg]"},
{"name": "decnr", "type": "double", "doc": "Declination of nearest source in reference image
PSF-catalog; J2000 [deg]"},
{"name": "sgmag1", "type": ["float", "null"], "default": null, "doc": "g-band PSF-fit
magnitude of closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "srmag1", "type": ["float", "null"], "default": null, "doc": "r-band PSF-fit magnitude
of closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "simag1", "type": ["float", "null"], "default": null, "doc": "i-band PSF-fit magnitude
of closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "szmag1", "type": ["float", "null"], "default": null, "doc": "z-band PSF-fit
magnitude of closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "sgscore1", "type": ["float", "null"], "default": null, "doc": "Star/Galaxy score of
closest source from PS1 catalog; if exists within 30 arcsec: 0 <= sgscore <= 1 where closer to
1 implies higher likelihood of being a star"},
{"name": "distpsnr1", "type": ["float", "null"], "default": null, "doc": "Distance to closest
source from PS1 catalog; if exists within 30 arcsec [arcsec]"},
{"name": "ndethist", "type": "int", "doc": "Number of spatially-coincident detections falling
within 1.5 arcsec going back to beginning of survey; only detections that fell on the same field
and readout-channel ID where the input candidate was observed are counted"},
{"name": "ncovhist", "type": "int", "doc": "Number of times input candidate position fell on
any field and readout-channel going back to beginning of survey"},
{"name": "jdstarthist", "type": ["double", "null"], "default": null, "doc": "Earliest Julian date
of epoch corresponding to ndethist [days]"},
{"name": "jdendhist", "type": ["double", "null"], "default": null, "doc": "Latest Julian date of
epoch corresponding to ndethist [days]"},
{"name": "scorr", "type": ["double", "null"], "default": null, "doc": "Peak-pixel signal-to-noise
ratio in point source matched-filtered detection image"},
{"name": "tooflag", "type": ["int", "null"], "default": 0, "doc": "1 => candidate is from a
Target-of-Opportunity (ToO) exposure; 0 => candidate is from a non-ToO exposure"},
{"name": "objectidps1", "type": ["long", "null"], "default": null, "doc": "Object ID of closest
source from PS1 catalog; if exists within 30 arcsec"},
{"name": "objectidps2", "type": ["long", "null"], "default": null, "doc": "Object ID of second
closest source from PS1 catalog; if exists within 30 arcsec"},
{"name": "sgmag2", "type": ["float", "null"], "default": null, "doc": "g-band PSF-fit
magnitude of second closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
41
{"name": "srmag2", "type": ["float", "null"], "default": null, "doc": "r-band PSF-fit magnitude
of second closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "simag2", "type": ["float", "null"], "default": null, "doc": "i-band PSF-fit magnitude
of second closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "szmag2", "type": ["float", "null"], "default": null, "doc": "z-band PSF-fit
magnitude of second closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "sgscore2", "type": ["float", "null"], "default": null, "doc": "Star/Galaxy score of
second closest source from PS1 catalog; if exists within 30 arcsec: 0 <= sgscore <= 1 where
closer to 1 implies higher likelihood of being a star"},
{"name": "distpsnr2", "type": ["float", "null"], "default": null, "doc": "Distance to second
closest source from PS1 catalog; if exists within 30 arcsec [arcsec]"},
{"name": "objectidps3", "type": ["long", "null"], "default": null, "doc": "Object ID of third
closest source from PS1 catalog; if exists within 30 arcsec"},
{"name": "sgmag3", "type": ["float", "null"], "default": null, "doc": "g-band PSF-fit
magnitude of third closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "srmag3", "type": ["float", "null"], "default": null, "doc": "r-band PSF-fit magnitude
of third closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "simag3", "type": ["float", "null"], "default": null, "doc": "i-band PSF-fit magnitude
of third closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "szmag3", "type": ["float", "null"], "default": null, "doc": "z-band PSF-fit
magnitude of third closest source from PS1 catalog; if exists within 30 arcsec [mag]"},
{"name": "sgscore3", "type": ["float", "null"], "default": null, "doc": "Star/Galaxy score of
third closest source from PS1 catalog; if exists within 30 arcsec: 0 <= sgscore <= 1 where
closer to 1 implies higher likelihood of being a star"},
{"name": "distpsnr3", "type": ["float", "null"], "default": null, "doc": "Distance to third closest
source from PS1 catalog; if exists within 30 arcsec [arcsec]"},
{"name": "nmtchps", "type": "int", "doc": "Number of source matches from PS1 catalog
falling within 30 arcsec"},
{"name": "rfid", "type": "long", "doc": "Processing ID for reference image to facilitate archive
retrieval"},
{"name": "jdstartref", "type": "double", "doc": "Observation Julian date of earliest exposure
used to generate reference image [days]"},
{"name": "jdendref", "type": "double", "doc": "Observation Julian date of latest exposure used
to generate reference image [days]"},
{"name": "nframesref", "type": "int", "doc": "Number of frames (epochal images) used to
42
generate reference image"},
{"name": "rbversion", "type": "string", "doc": "version of RealBogus model/classifier used to
assign rb quality score"},
{"name": "dsnrms", "type": ["float", "null"], "default": null, "doc": "Ratio: D/stddev(D) on
event position where D = difference image"},
{"name": "ssnrms", "type": ["float", "null"], "default": null, "doc": "Ratio: S/stddev(S) on
event position where S = image of convolution: D (x) PSF(D)"},
{"name": "dsdiff", "type": ["float", "null"], "default": null, "doc": "Difference of statistics:
dsnrms - ssnrms"},
{"name": "magzpsci", "type": ["float", "null"], "default": null, "doc": "Magnitude zero point
for photometry estimates [mag]"},
{"name": "magzpsciunc", "type": ["float", "null"], "default": null, "doc": "Magnitude zero
point uncertainty (in magzpsci) [mag]"},
{"name": "magzpscirms", "type": ["float", "null"], "default": null, "doc": "RMS (deviation
from average) in all differences between instrumental photometry and matched photometric
calibrators from science image processing [mag]"},
{"name": "nmatches", "type": "int", "doc": "Number of PS1 photometric calibrators used to
calibrate science image from science image processing"},
{"name": "clrcoeff", "type": ["float", "null"], "default": null, "doc": "Color coefficient from
linear fit from photometric calibration of science image"},
{"name": "clrcounc", "type": ["float", "null"], "default": null, "doc": "Color coefficient
uncertainty from linear fit (corresponding to clrcoeff)"},
{"name": "zpclrcov", "type": ["float", "null"], "default": null, "doc": "Covariance in magzpsci
and clrcoeff from science image processing [mag^2]"},
{"name": "zpmed", "type": ["float", "null"], "default": null, "doc": "Magnitude zero point
from median of all differences between instrumental photometry and matched photometric
calibrators from science image processing [mag]"},
{"name": "clrmed", "type": ["float", "null"], "default": null, "doc": "Median color of all PS1
photometric calibrators used from science image processing [mag]: for filter (fid) = 1, 2, 3,
PS1 color used = g-r, g-r, r-i respectively"},
{"name": "clrrms", "type": ["float", "null"], "default": null, "doc": "RMS color (deviation
from average) of all PS1 photometric calibrators used from science image processing
[mag]"},
{"name": "neargaia", "type": ["float", "null"], "default": null, "doc": "Distance to closest
source from Gaia DR1 catalog irrespective of magnitude; if exists within 90 arcsec [arcsec]"},
43
{"name": "neargaiabright", "type": ["float", "null"], "default": null, "doc": "Distance to closest
source from Gaia DR1 catalog brighter than magnitude 14; if exists within 90 arcsec
[arcsec]"},
{"name": "maggaia", "type": ["float", "null"], "default": null, "doc": "Gaia (G-band)
magnitude of closest source from Gaia DR1 catalog irrespective of magnitude; if exists within
90 arcsec [mag]"},
{"name": "maggaiabright", "type": ["float", "null"], "default": null, "doc": "Gaia (G-band)
magnitude of closest source from Gaia DR1 catalog brighter than magnitude 14; if exists
within 90 arcsec [mag]"},
{"name": "exptime", "type": ["float", "null"], "default": null, "doc": "Integration time of
camera exposure [sec]"}
]
}
● ztf.alert.prv_candidate:
{
"namespace": "ztf.alert",
"name": "prv_candidate",
"doc": "avro alert schema",
"version": "3.2",
"type": "record",
"fields": [
{"name": "jd", "type": "double", "doc": "Observation Julian date at start of exposure [days]"},
{"name": "fid", "type": "int", "doc": "Filter ID (1=g; 2=R; 3=i)"},
{"name": "pid", "type": "long", "doc": "Processing ID for image"},
{"name": "diffmaglim", "type": ["float", "null"], "default": null, "doc": "Expected 5-sigma
mag limit in difference image based on global noise estimate [mag]"},
{"name": "pdiffimfilename", "type": ["string", "null"], "default": null, "doc": "filename of
positive (sci minus ref) difference image"},
{"name": "programpi", "type": ["string", "null"], "default": null, "doc": "Principal investigator
attached to program ID"},
{"name": "programid", "type": "int", "doc": "Program ID: encodes either public, collab, or
caltech mode"},
{"name": "candid", "type": ["long", "null"], "doc": "Candidate ID from operations DB"},
44
{"name": "isdiffpos", "type": ["string", "null"], "doc": "t or 1 => candidate is from positive
(sci minus ref) subtraction; f or 0 => candidate is from negative (ref minus sci) subtraction"},
{"name": "tblid", "type": ["long", "null"], "default": null, "doc": "Internal pipeline table
extraction ID"},
{"name": "nid", "type": ["int", "null"], "default": null, "doc": "Night ID"},
{"name": "rcid", "type": ["int", "null"], "default": null, "doc": "Readout channel ID [00 ..
63]"},
{"name": "field", "type": ["int", "null"], "default": null, "doc": "ZTF field ID"},
{"name": "xpos", "type": ["float", "null"], "default": null, "doc": "x-image position of
candidate [pixels]"},
{"name": "ypos", "type": ["float", "null"], "default": null, "doc": "y-image position of
candidate [pixels]"},
{"name": "ra", "type": ["double", "null"], "doc": "Right Ascension of candidate; J2000
[deg]"},
{"name": "dec", "type": ["double", "null"], "doc": "Declination of candidate; J2000 [deg]"},
{"name": "magpsf", "type": ["float", "null"], "doc": "Magnitude from PSF-fit photometry
[mag]"},
{"name": "sigmapsf", "type": ["float", "null"], "doc": "1-sigma uncertainty in magpsf
[mag]"},
{"name": "chipsf", "type": ["float", "null"], "default": null, "doc": "Reduced chi-square for
PSF-fit"},
{"name": "magap", "type": ["float", "null"], "default": null, "doc": "Aperture mag using 14
pixel diameter aperture [mag]"},
{"name": "sigmagap", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty in
magap [mag]"},
{"name": "distnr", "type": ["float", "null"], "default": null, "doc": "distance to nearest source
in reference image PSF-catalog [pixels]"},
{"name": "magnr", "type": ["float", "null"], "default": null, "doc": "magnitude of nearest
source in reference image PSF-catalog [mag]"},
{"name": "sigmagnr", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty in
magnr [mag]"},
{"name": "chinr", "type": ["float", "null"], "default": null, "doc": "DAOPhot chi parameter of
nearest source in reference image PSF-catalog"},
{"name": "sharpnr", "type": ["float", "null"], "default": null, "doc": "DAOPhot sharp
parameter of nearest source in reference image PSF-catalog"},
45
{"name": "sky", "type": ["float", "null"], "default": null, "doc": "Local sky background
estimate [DN]"},
{"name": "magdiff", "type": ["float", "null"], "default": null, "doc": "Difference: magap -
magpsf [mag]"},
{"name": "fwhm", "type": ["float", "null"], "default": null, "doc": "Full Width Half Max
assuming a Gaussian core, from SExtractor [pixels]"},
{"name": "classtar", "type": ["float", "null"], "default": null, "doc": "Star/Galaxy classification
score from SExtractor"},
{"name": "mindtoedge", "type": ["float", "null"], "default": null, "doc": "Distance to nearest
edge in image [pixels]"},
{"name": "magfromlim", "type": ["float", "null"], "default": null, "doc": "Difference:
diffmaglim - magap [mag]"},
{"name": "seeratio", "type": ["float", "null"], "default": null, "doc": "Ratio: difffwhm /
fwhm"},
{"name": "aimage", "type": ["float", "null"], "default": null, "doc": "Windowed profile RMS
afloat major axis from SExtractor [pixels]"},
{"name": "bimage", "type": ["float", "null"], "default": null, "doc": "Windowed profile RMS
afloat minor axis from SExtractor [pixels]"},
{"name": "aimagerat", "type": ["float", "null"], "default": null, "doc": "Ratio: aimage /
fwhm"},
{"name": "bimagerat", "type": ["float", "null"], "default": null, "doc": "Ratio: bimage /
fwhm"},
{"name": "elong", "type": ["float", "null"], "default": null, "doc": "Ratio: aimage / bimage"},
{"name": "nneg", "type": ["int", "null"], "default": null, "doc": "number of negative pixels in a
5 x 5 pixel stamp"},
{"name": "nbad", "type": ["int", "null"], "default": null, "doc": "number of prior-tagged bad
pixels in a 5 x 5 pixel stamp"},
{"name": "rb", "type": ["float", "null"], "default": null, "doc": "RealBogus quality score; range
is 0 to 1 where closer to 1 is more reliable"},
{"name": "ssdistnr", "type": ["float", "null"], "default": null, "doc": "distance to nearest
known solar system object if exists within 30 arcsec [arcsec]"},
{"name": "ssmagnr", "type": ["float", "null"], "default": null, "doc": "magnitude of nearest
known solar system object if exists within 30 arcsec (usually V-band from MPC archive)
[mag]"},
{"name": "ssnamenr", "type": ["string", "null"], "default": null, "doc": "name of nearest
46
known solar system object if exists within 30 arcsec (from MPC archive)"},
{"name": "sumrat", "type": ["float", "null"], "default": null, "doc": "Ratio: sum(pixels) /
sum(|pixels|) in a 5 x 5 pixel stamp where stamp is first median-filtered to mitigate outliers"},
{"name": "magapbig", "type": ["float", "null"], "default": null, "doc": "Aperture mag using 18
pixel diameter aperture [mag]"},
{"name": "sigmagapbig", "type": ["float", "null"], "default": null, "doc": "1-sigma uncertainty
in magapbig [mag]"},
{"name": "ranr", "type": ["double", "null"], "doc": "Right Ascension of nearest source in
reference image PSF-catalog; J2000 [deg]"},
{"name": "decnr", "type": ["double", "null"], "doc": "Declination of nearest source in
reference image PSF-catalog; J2000 [deg]"},
{"name": "scorr", "type": ["double", "null"], "default": null, "doc": "Peak-pixel signal-to-noise
ratio in point source matched-filtered detection image"},
{"name": "magzpsci", "type": ["float", "null"], "default": null, "doc": "Magnitude zero point
for photometry estimates [mag]"},
{"name": "magzpsciunc", "type": ["float", "null"], "default": null, "doc": "Magnitude zero
point uncertainty (in magzpsci) [mag]"},
{"name": "magzpscirms", "type": ["float", "null"], "default": null, "doc": "RMS (deviation
from average) in all differences between instrumental photometry and matched photometric
calibrators from science image processing [mag]"},
{"name": "clrcoeff", "type": ["float", "null"], "default": null, "doc": "Color coefficient from
linear fit from photometric calibration of science image"},
{"name": "clrcounc", "type": ["float", "null"], "default": null, "doc": "Color coefficient
uncertainty from linear fit (corresponding to clrcoeff)"},
{"name": "rbversion", "type": "string", "doc": "version of RealBogus model/classifier used to
assign rb quality score"}
]
}
47
● ztf.alert.cutout:
{
"namespace": "ztf.alert",
"type": "record",
"name": "cutout",
"doc": "avro alert schema",
"version": "3.2",
"fields": [
{"name": "fileName", "type": "string"},
{"name": "stampData", "type": "bytes", "doc": "fits.gz"}
]
}
48