102.1. Comenzando con TAP#
102.1. Comenzando con TAP¶
Para la Plataforma Científica de Rubin en data.lsst.cloud.
Divulgación de Datos: Vista Previa de Datos 1
Tamaño del contenedor (Container size): large
Versión de las Pipelines Científicas de LSST: r29.2.0
Última verificación de ejecución: 2025-11-10
Repositorio: github.com/lsst/tutorial-notebooks
DOI: 10.11578/rubin/dc.20250909.20
Objetivo de aprendizaje: Cómo usar eficientemente el servicio TAP.
Productos de datos LSST: Tabla Object
Paquetes: lsst.rsp.get_tap_service
Créditos: Desarrollado originalmente por el equipo científico de la comunidad de Rubin. Por favor, considerar reconocer su trabajo si este notebook se utiliza para la preparación de artículos de revistas, lanzamientos de software u otros notebooks.
Soporte: Se invita a toda la comunidad a hacer preguntas o plantear problemas en la Categoría de asistencia del Foro de la Comunidad de Rubin. El equipo de Rubin responderá a todas las preguntas publicadas allí.
1. Introducción¶
El Protocolo de Acceso a Datos Tabulados TAP (Table Access Protocol) provee acceso estandarizado a los datos de los catálogos para exploración, búsqueda y recuperación. La documentación completa de TAP es proporcionada por la Alianza Internacional de Observatorios Virtuales (IVOA - International Virtual Observatory Alliance).
Este tutorial muestra cómo comenzar a utilizar el servicio TAP, explorar el esquema TAP y realizar consultas de manera eficiente.
Buenas prácticas para consultas TAP:
- Usar consultas asíncronas.
- Especificar las columnas que se desean obtener.
- Utilizar restricciones espaciales en coordenadas celestes.
- Aplicar restricciones sobre columnas (cuando corresponda).
Tutoriales relacionados: Los demás tutoriales de nivel 100 de esta serie presentan sentencias ADQL avanzadas. Los tutoriales de nivel 200 describen el contenido de los datos del catálogo e incluyen consultas de ejemplo para cada uno.
1.1. Glosario de TAP¶
- esquema - Término de bases de datos para el diseño abstracto que representa el almacenamiento de datos en una base de datos.
- esquema TAP - El conjunto de tablas que describen las tablas de datos y sus columnas.
- colección de tablas - Una colección de tablas (catálogos), por ejemplo, para una dada divulgación de datos.
- tabla - Una colección de datos relacionados almacenados en formato tabular en una base de datos.
- consulta - Una cadena formateada en ADQL que selecciona datos de una tabla, con restricciones si se desea.
- resultados - La salida del método de búsqueda del servicio TAP cuando se envía una consulta.
1.2. Sentencias ADQL¶
La documentación de ADQL incluye más información sobre sintaxis, palabras clave, operadores, funciones, etc. ADQL es similar a SQL (Structured Query Language).
Una sentencia típica de ADQL tiene al menos tres componentes:
SELECT <columnas> FROM <catálogo> WHERE <restricciones>
donde
<columnas>es una lista separada por comas de las columnas a devolver,<catálogo>es el nombre del catálogo del cual obtener los datos, y<restricciones>impone una restricción para que sólo se devuelvan las filas cuyos valores de columna cumplan las condiciones.
Por ejemplo, supongamos que existe un catálogo llamado "mysurveydata" con 5 columnas, "col1", "col2", y así sucesivamente. La sentencia ADQL:
SELECT col3, col4, col5 FROM mysurveydata WHERE col1 > 0.5 AND col5 < 10
devolvería una tabla que contiene tres columnas y todas las filas que cumplan las dos restricciones de la cláusula WHERE.
import numpy as np
from lsst.rsp import get_tap_service
2. Instanciar el servicio TAP¶
Obtener una instancia del servicio TAP y asegurarse que exista.
service = get_tap_service("tap")
assert service is not None
3. Explorar el esquema TAP¶
Los esquemas TAP navegables están disponibles en sdm-schemas.lsst.io y en la interfaz de usuario de la Faceta Portal.
Esta sección muestra cómo interactuar programáticamente con el esquema TAP.
3.1. Tener precaución con las consultas síncronas¶
Una consulta “síncrona” es aquella en la que la búsqueda se ejecuta y los resultados se recuperan al mismo tiempo, y ninguna otra celda puede ejecutarse mientras la búsqueda está en curso.
Las consultas síncronas deben usarse con moderación y sólo para recuperar metadatos de tablas, como se muestra en esta sección.
Las consultas asíncronas deben utilizarse cuando se recuperan datos de tablas (Sección 4.1).
3.2. Tener precaución con SELECT *¶
Las consultas que usan SELECT *, a partir del cual se devuelven todas las columnas, sólo son apropiadas para esquemas (esta sección) o para tablas con muy pocas columnas (<20).
Las consultas que devuelven datos deben especificar cuáles de las decenas o cientos de columnas son necesarias recuperar (Sección 4.2).
3.3. Listar todos los esquemas¶
Enviar una consulta al servicio TAP para obtener los esquemas TAP y almacenar los resultados en results.
results = service.search('SELECT * FROM tap_schema.schemas')
Mostrar los resultados.
results
<DALResultsTable length=4>
schema_name utype ... schema_index
str64 str512 ... int32
----------------- ------ ... ------------
dp02_dc2_catalogs ... 2
dp1 ... 0
ivoa ... 1
tap_schema ... 100000
El método to_table() convierte results en una
tabla de Astropy.
Convertir results en una tabla y mostrarla.
results.to_table()
| schema_name | utype | description | schema_index |
|---|---|---|---|
| str64 | str512 | str512 | int32 |
| dp02_dc2_catalogs | Data Preview 0.2 contains the image and catalog products of the Rubin Science Pipelines v23 processing of the DESC Data Challenge 2 simulation, which covered 300 square degrees of the wide-fast-deep LSST survey region over 5 years. | 2 | |
| dp1 | Data Preview 1 contains image and catalog products from the Rubin Science Pipelines v29 processing of observations obtained with the LSST Commissioning Camera of seven ~1 square degree fields, over seven weeks in late 2024. | 0 | |
| ivoa | ObsCore v1.1 attributes in ObsTAP realization | 1 | |
| tap_schema | A TAP-standard-mandated schema to describe tablesets in a TAP 1.1 service | 100000 |
del results
3.4. Listar todas las tablas¶
Crear una consulta que seleccione todos los nombres de tablas del esquema TAP para DP1. Recuperar los resultados como una tabla de Astropy y mostrarla.
query = "SELECT * FROM tap_schema.tables " \
"WHERE tap_schema.tables.schema_name = 'dp1'" \
"ORDER BY table_index ASC"
results = service.search(query).to_table()
results
| schema_name | table_name | table_type | utype | description | table_index |
|---|---|---|---|---|---|
| str512 | str64 | str8 | str512 | str512 | int32 |
| dp1 | dp1.Object | table | Descriptions of static astronomical objects (or the static aspects of variable and slowly-moving objects) detected and measured on coadds. | 10 | |
| dp1 | dp1.Source | table | Properties of detections on the single-epoch visit images, performed independently of the Object detections on coadded images. | 20 | |
| dp1 | dp1.ForcedSource | table | Forced-photometry measurements on individual single-epoch visit images and difference images, based on and linked to the entries in the Object table. Point-source PSF photometry is performed, based on coordinates from a reference band chosen for each Object and reported in the Object.refBand column. | 30 | |
| dp1 | dp1.DiaObject | table | Properties of time-varying astronomical objects based on association of data from one or more spatially-related DiaSource detections on individual single-epoch difference images. | 40 | |
| dp1 | dp1.DiaSource | table | Properties of transient-object detections on the single-epoch difference images. | 50 | |
| dp1 | dp1.ForcedSourceOnDiaObject | table | Point-source forced-photometry measurements on individual single-epoch visit images and difference images, based on and linked to the entries in the DiaObject table. | 60 | |
| dp1 | dp1.CoaddPatches | table | Static information about the subset of tracts and patches from the standard LSST skymap that apply to coadds in these catalogs | 70 | |
| dp1 | dp1.Visit | table | Metadata about the pointings of the telescope, largely associated with the boresight of the LSSTComCam focal plane as a whole. | 80 | |
| dp1 | dp1.CcdVisit | table | Metadata about the nine individual CCD images for each Visit in the DP1 LSSTComCam dataset. | 90 | |
| dp1 | dp1.MPCORB | table | Orbit catalog produced by the Minor Planet Center based on submissions from DP1 processing. The columns are described at https://minorplanetcenter.net//iau/info/MPOrbitFormat.html . | 100 | |
| dp1 | dp1.SSObject | table | LSST-computed per-object quantities. 1:1 relationship with MPCORB. | 110 | |
| dp1 | dp1.SSSource | table | LSST-computed per-source quantities. 1:1 relationship with DiaSource. | 120 |
del query, results
3.5. Listar todas las columnas¶
Crear una consulta que seleccione todos los nombres de columnas, tipos de datos, descripciones y unidades de la tabla Object de DP1. Recuperar los resultados como una tabla de Astropy.
query = "SELECT column_name, datatype, description, unit " \
"FROM tap_schema.columns " \
"WHERE table_name = 'dp1.Object'"
results = service.search(query).to_table()
Opción para mostrar los resultados almacenados en results. La visualización de la tabla será truncada automáticamente por el notebook, ya que la tabla Object tiene 1296 columnas.
# results
Usar un bucle for para buscar la presencia de coord en la columna
column_name de cada fila de la tabla de resultados
y escribir el nombre cuando haya una coincidencia.
search_string = 'coord'
# search_string = 'g_psfFlux'
for cname in results['column_name']:
if cname.find(search_string) > -1:
print(cname)
coord_dec coord_decErr coord_ra coord_ra_dec_Cov coord_raErr
Descomentar la segunda línea en la celda anterior y volver a ejecutarla para imprimir todas las columnas que contengan la cadena g_psfFlux.
Imprimir el conjunto único de tipos de datos o unidades.
print(np.unique(results['datatype']))
# print(np.unique(results['unit']))
datatype
--------
boolean
char
double
float
int
long
del query, results
4. Buenas prácticas para consultas TAP¶
Se recomienda seguir las indicaciones de esta sección al consultar y recuperar datos, ya que el servicio TAP es un recurso limitado compartido por toda la comunidad usuaria.
Este tutorial mostrará cómo realizar consultas eficientes que devuelvan sólo los datos necesarios para un análisis determinado.
La tabla Object utilizada en esta demostración contiene mediciones forzadas en las imágenes multibanda deepCoadd en las coordenadas de todas las detecciones con relación señal-ruido >5 en un deepCoadd de cualquier filtro.
El tutorial de nivel 200 del catálogo Object contiene más detalles.
4.1. Usar consultas asíncronas¶
Una consulta “asíncrona” significa que la consulta se envía como un trabajo al servicio TAP y se ejecuta en segundo plano hasta completarse. Los resultados pueden recuperarse de inmediato o en un momento posterior.
El proceso general para consultas asíncronas es el siguiente:
- Definir el trabajo en la variable
jobpasando la consultaqueryal servicio TAP.
job = service.submit_job(query)
- Ejecutar el trabajo y esperar a que devuelva un resultado
COMPLETEDoERROR. La espera es opcional, pero los notebooks de tutoriales siempre esperan porque los siguientes pasos del tutorial dependen de los datos obtenidos.
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
- Mostrar el mensaje de error si la consulta no fue exitosa.
if job.phase == 'ERROR':
job.raise_if_error()
- Si la consulta se completó, recuperar los resultados.
assert job.phase == 'COMPLETED'
results = job.fetch_result()
4.2. Usar SELECT para especificar columnas¶
Las consultas de datos no deben usar SELECT *, ya que esto devolverá todas las columnas, y algunas tablas tienen cientos de columnas.
Se recomienda primero decidir qué columnas son necesarias recuperar.
Usar el esquema TAP para entender las columnas disponibles.
Luego, especificar únicamente las columnas deseadas en la declaración SELECT de la consulta TAP.
4.3. Usar restricciones espaciales¶
Todas las búsquedas TAP en tablas que incluyen coordenadas celestes deben incluir restricciones espaciales.
Se recomienda comenzar siempre con restricciones espaciales para una región pequeña y luego ampliar el área de búsqueda.
Las restricciones espaciales deben implementarse utilizando una búsqueda cónica o poligonal en ADQL.
Para consultas pequeñas de "exploración rápida", se recomienda usar una región espacial pequeña en lugar de simplemente limitar los resultados devueltos con TOP.
4.3.1. Fragmentación de tablas por coordenadas¶
En disco, las tablas del catálogo están fragmentadas por coordenadas (RA, Dec). Esto puede entenderse como que la base de datos está segmentada por región espacial (fragmento - shard) y distribuida en múltiples servidores. Las consultas que incluyen restricciones espaciales que minimizan el número de fragmentos que deben buscarse serán mucho más rápidas que las consultas que no tienen restricciones (o tienen restricciones muy amplias).
4.3.2. Búsquedas cónicas¶
Una búsqueda cónica es una consulta al catálogo que devuelve todos los objetos dentro de un radio determinado de una coordenada celeste. Dado que un diámetro angular determinado corresponde a un diámetro físico mayor a distancias mayores, el volumen consultado tiene forma de cono en 3D, no de cilindro.
En ADQL, una búsqueda cónica se ejecuta con WHERE CONTAINS(POINT(), CIRCLE()) = 1.
POINT()pasa las columnas del catálogo correspondientes a las coordenadas celestes.CIRCLE()define el centro y el radio del círculo de búsqueda.CONTAINS() = 1restringe la consulta para devolver únicamente las filas para las cuales la afirmación "este círculo contiene este punto" es "Verdadera" (=1).
No se recomienda aplicar restricciones sobre las columnas de coordenadas, ya sea con ADQL con una sentencia similar a -30 < coord_dec AND coord_dec < -25 o usando una cláusula WHERE ... BETWEEN, porque el servicio TAP no las interpreta de la misma manera que una búsqueda cónica o poligonal.
Crear una búsqueda cónica en la tabla Object para los objetos a distancias de 0.01 grados de las coordenadas cercanas al centro del campo ECDFS, con RA, Dec = 53, -28 grados.
query = """SELECT coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1"""
print(query)
SELECT coord_ra, coord_dec
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.01)) = 1
Ejecutar la consulta de manera asíncrona y mostrar el número de filas recuperadas.
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
assert job.phase == 'COMPLETED'
results = job.fetch_result()
print(len(results))
141
Limpieza.
job.delete()
del query, results
4.3.3. Búsquedas poligonales¶
Para una búsqueda poligonal, reemplazar CIRCLE por POLYGON(ra1, dec1, ra2, dec2, ra3, dec3, ...), donde cada par ra, dec corresponde a un vértice del polígono.
4.4. Usar restricciones en columnas¶
Se recomienda comprender las columnas que se están recuperando (Sección 4.2) y, cuando corresponda, aplicar también restricciones sobre los valores de esas columnas. El objetivo es devolver únicamente las filas de la tabla que sean relevantes para el análisis (e.g., sólo los objetos de interés).
Por ejemplo, una restricción simple en una columna consiste en establecer un límite superior o inferior en sus valores, como un límite de magnitud.
Usar la misma búsqueda cónica que antes, pero ampliar el radio a $0.3$ grados y devolver únicamente los objetos de Object con una magnitud cModel en banda $g$ más brillante que 20 mag.
query = """SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.3)) = 1
AND g_cModelMag < 20"""
print(query)
SELECT coord_ra, coord_dec, g_cModelMag
FROM dp1.Object
WHERE CONTAINS(POINT('ICRS', coord_ra, coord_dec),
CIRCLE('ICRS', 53, -28, 0.3)) = 1
AND g_cModelMag < 20
job = service.submit_job(query)
job.run()
job.wait(phases=['COMPLETED', 'ERROR'])
print('La fase del trabajo es', job.phase)
if job.phase == 'ERROR':
job.raise_if_error()
La fase del trabajo es COMPLETED
assert job.phase == 'COMPLETED'
results = job.fetch_result()
print(len(results))
452
Limpieza.
job.delete()
del query, results