Pydap es lento. ¿Cómo puedo mejorar el tiempo de descarga?#
Hay dos etapas en las que pydap descarga datos: a) durante la creación del dataset, y b) al descargar datos de arreglos. Estas pueden ser lentas por sí mismas debido a varios escenarios:
Datos detrás de autenticación.
Uso del protocolo DAP2 en lugar del protocolo DAP4.
El dataset remoto está fragmentado en chunks pequeños.
La API cliente está enviando demasiadas solicitudes innecesarias al servidor remoto.
El servidor no está configurado correctamente.
La conexión a internet es intermitente o deficiente.
Entre otros escenarios. En la gran mayoría de los casos, se considera una buena práctica mantener al mínimo la cantidad de solicitudes al servidor, es decir, solicitar solo lo necesario. Esto es aún más importante cuando los datos están detrás de autenticación, ya que puede haber muchas redirecciones por cada solicitud desde la API cliente.
A continuación se muestran algunas guías para mejorar el acceso a datos. Si sigues experimentando problemas de rendimiento, considera escribir un issue en el Github IssueTracker de Pydap. Abajo asumimos que las personas usuarias usan pydap como motor backend de Xarray. Esto es:
ds = xr.open_dataset(url, engine='pydap', ...) # or xr.open_mfdataset()
a) Crear el Dataset#
Al crear un Dataset, la lógica interna de Xarray envía solicitudes al servidor para:
Descargar metadatos. Para el protocolo
DAP2estos son.ddsy.das, uno de cada uno por archivo remoto. EnDAP4solo se envía una solicitud de metadatos por archivo remoto, el.dmr. Estos archivos de metadatos describen la estructura interna y la información dentro de cada archivo remoto (todos los nombres, tipos, formas y atributos de variables), queXarrayusa para crear el Dataset.Descargar todos los datos de arreglos de dimensiones. Por archivo,
Xarraydescarga de forma predeterminada todas las dimensiones y las carga en memoria. Al abrir múltiples archivos, este comportamiento puede producir bajo rendimiento, ya queXarraysolicitará todos los datos de dimensiones de cada archivo para realizar una comprobación de seguridad, incluso cuando la persona usuaria sabe de antemano que estos datos son idénticos en todos los archivos remotos. Aunque estas comprobaciones de seguridad son muy importantes (y deben existir), pueden causar grandes pérdidas de rendimiento al agregar cientos de archivos remotos, cada uno con 2 o más dimensiones, en particular al reiniciar el Kernel (y verse obligado a ejecutar el flujo de trabajo desde cero).
Note
A partir de xarray=v2025.10, Xarray envía una solicitud individual por variable dentro de un archivo remoto, en lugar de obtener los datos de arreglo de todas las variables en una sola solicitud. Este comportamiento no es óptimo y se mejorará en el futuro.
Para mejorar el rendimiento y evitar volver a descargar los datos necesarios para abrir un dataset recomendamos:
Usar DAP4. Es un protocolo DAP más moderno y mejor soportado por servicios OPeNDAP y por la comunidad geoespacial en general. Además, al elegir DAP4 automáticamente reduces a la mitad la cantidad de respuestas asociadas con metadatos del mismo archivo. Para especificar el protocolo DAP con
PyDAP, puedes cambiar el esquema de la URL así:
dap4_url = "dap4://<www.opendap.org/remote_file>" # <------- DAP4
dap2_url = "dap2://<www.opendap.org/remote_file>" # <------- DAP2
url = "https://<www.opendap.org/remote_file>" # <------- Pydap assumes DAP2.
Usar Constraint Expressions para producir un DMR restringido. Se puede agregar una
Constraint Expressiona una URLDAP4siguiendo esta sintaxis:
url = <https://...opendap_url..>
CE = "dap4.ce=/VarName1;/VarName2;/...;/VarNameN"
url_ce = url + "?" + CE
donde VarName1, VarName2 y VarNameN son variables presentes en un archivo remoto con M>=N variables. Pasar esta URL a Xarray usando pydap como motor permitirá que el servidor OPeNDAP remoto produzca un DMR restringido, que solo tendrá información sobre esas variables. Esto puede generar mejoras significativas de rendimiento cuando N<<M (por ejemplo N=4 y M=1000).
Note
Xarray tiene lógica interna para descartar variables. Pero Xarray analizará los metadatos de TODAS las variables y luego descartará las variables especificadas por la persona usuaria en .drop_vars(). Con un DMR restringido mediante la Constraint Expression del ejemplo anterior, por ejemplo, Xarray solo procesaría las N variables.
Warning
Xarray requiere la presencia de datos de dimensión para coincidir con la forma de cualquier data variable. Al construir una Constraint Expression como arriba, incluye en la CE todas las dimensiones asociadas con las variables de interés.
Consolidar metadatos.
PyDAPtiene un método para persistir metadatos y reutilizarlos después.PyDAPpuede usar una request_cache.CachedSession para descargar y persistir los metadatos necesarios para iniciar un Dataset deXarray. UnaCachedSessionusa un backendSQLitey puede actuar como gestor de base de datos; como unaCachedSessiontambién se puede usar para autenticarse, reemplaza directamente a un objeto requests.Session típicamente usado por PyDAP. Considera el ejemplo siguiente:
from pydap.net import create_session
from pydap.client import consolidate_metadata
URLS = [url1, url2, url3, url4, url5, ...., urlN]
database_name = '</path_to_persistent_directory_of_metadata_for_the_files/NAME_OF_DATABASE>'
my_session = create_session(use_cache=True, cache_kwargs={'cache_name': database_name})
consolidate_metadata(URLS, concat_dim="time", session=my_session)
ds = xr.open_mfdataset(URLS, engine='pydap', parallel=True, concat_dim='time', ...)
El my_session resultante apunta a una base de datos SQLite que puede persistir y estar bajo control de versiones si el directorio /path_to_persistent_directory_of_metadata_for_this_files/, donde existe el archivo NAME_OF_DATABASE.sqlite, es un directorio versionado (por ejemplo, usando github).
consolidate_metadata predescarga todos los DMRs del servidor remoto, junto con cualquier dato necesario de arreglos de dimensión, y los almacena en la base de datos SQLite para reutilizarlos después. Depende de la persona usuaria saber en qué dimensión se deben concatenar los datos; en el ejemplo anterior, es time. Entonces, después de reiniciar el kernel (o eliminar la referencia ds), mientras my_session apunte a la base de datos, todos los metadatos persisten. Crear/abrir el dataset de Xarray no debería tardar más de 2 a 5 segundos.
Además, considera el caso en que el proveedor de datos agrega más archivos remotos a la misma colección a la que pertenecen las URLs iniciales. Ejecutar lo siguiente debería actualizar el dataset con los datos nuevos. Como los archivos originales ya están cacheados, no deberían descargarse datos de las URLs originales.
# new urls
new_URLs = [urlN1, urlN2, urlN3, urlN4, urlN5, ...., urlNN]
# add new url to previous ones
updated_URLs = URLs + new_URLs
# load the session that points to the SQLite database
database_name = '</path_to_persistent_directory_of_metadata_for_this_files/NAME_OF_DATABASE>'
my_session = create_session(use_cache=True, cache_kwargs={'cache_name': database_name})
consolidate_metadata(updated_URLs, concat_dim="time", session=my_session)
Ahora, la base de datos SQLite contiene datos de dimensiones y metadatos actualizados.
Note
Para limpiar los metadatos, basta con hacer: my_session.cache.clear(). Al limpiar los metadatos, especialmente después de reiniciar el Kernel, sugerimos empezar de nuevo desde create_session.
b) Obtener datos numéricos #
Se recomienda firmemente configurar el servidor OPeNDAP para implementar el protocolo DAP4, ya que soporta completamente todos los tipos de datos admitidos por DAP2 y puede enviar respuestas por chunks a través de la web.
Note
En el protocolo DAP2, toda la respuesta se envía en un solo Chunk. Es decir, el protocolo DAP2 no soporta enviar respuestas por chunks. Esto puede provocar errores de Timeout del lado del servidor.
Al transmitir datos por la red (en lugar de dentro de la región de la nube), se recomienda firmemente aprovechar la infraestructura especializada del servidor OPeNDAP para subdividir de forma próxima a los datos. Al trabajar con Xarray, esto implica asegurarse de que el rebanado se pase al servidor. Esto se logra de las siguientes formas:
ds = xr.open_dataset(url, engine='pydap', session=my_session)
ds['varName'].isel(dim1=slice_dim1, dim2=slice_dim2).load()
donde slice_dim1 y slice_dim2 son los rebanados predeterminados por la persona usuaria.
Al trabajar con múltiples archivos, a partir de Xarray <=v2025.10, el rebanado no se pasa al servidor a menos que el dataset se fragmente al crearlo. Esto es:
expected_sizes = {'dim1':expected_size_dim1, 'dim2':expected_size_dim2, 'dim3': expected_size_dim3}
ds = xr.open_mfdataset(urls, engine='pydap', session=my_session, concat_dim='dim1', combine='nested', parallel=True)
ds['varName'].isel(dim1=slice_dim1, dim2=slice_dim2, dim3=slice_dim3).load()
donde dim1 es la dimensión de concatenación, dim2 y dim3 son otras dimensiones del dataset agregado, y expected_size_dim1, expected_size_dim2 y expected_size_dim3 juntos definen el tamaño esperado del subconjunto dentro de cada gránulo. Este tamaño no puede exceder el tamaño original de la dimensión. Para algunos ejemplos, consulta el tutorial de 5 minutos.
Diagnóstico. Es posible que el dataset remoto tenga muchos chunks pequeños, lo que produce un rendimiento muy lento. Esto, junto con la conexión a internet, son problemas de rendimiento fuera del alcance de
pydap. Un diagnóstico útil para saber si el problema está enpydapo en el servidor remoto es usar curl para descargar la respuesta.
curl -L -n "<opendap_url_with_constraint_expression>"
donde -L implica seguir redirecciones, y -n indica a curl que recupere la autenticación desde el archivo ~/.netrc. Esto último solo es necesario cuando se requiere autenticación. Por ejemplo, para descargar una respuesta .dap (DAP4) desde un servidor dap4 (sin autenticación requerida):
curl -L -o output.dap "http://test.opendap.org/opendap/data/nc/coads_climatology.nc.dap?dap4.ce=/TIME"
El siguiente comando descarga solo la variable TIME desde este dataset de prueba. La descarga debería ser muy rápida. Al rebanar un arreglo, pydap hace algo muy similar: descarga una respuesta .dap para una sola variable, en este caso TIME. Pydap no debería tardar mucho más que curl en descargar la respuesta .dap.
Revisa tamaños de variables y evita descargar arreglos completos de datasets ncml. Los datasets
ncmlson una agregación virtual de una colección de archivos NetCDF.ncmles excelente porque proporciona un único endpoint URL para una colección, pero muchas personas usuarias experimentan tiempos largos y errores de descarga al solicitar descargar incluso una sola variable.