Al momento de escribir, tengo la tarea de entregar una sesión de teatro demo en la Conferencia de Usuarios Esri 2026 titulada Distribución de Datos Georelacionales Cloud-Native. Si vas a asistir a UC 2026 puedes agregarla a tu agenda. Si no puedes asistir, entonces el libro de la obra es lo que sigue a continuación, sin embargo, para fomentar la asistencia a UC hay un capítulo que falta en el libro que mostraré en vivo, es decir, qué tan rápido puedes obtener datos en tu mapa o escena desde AWS S3 mientras se aplica un modelo de datos para características de lugar de interés y edificios, porque siempre deberías estar pensando en un producto de información y no solo en datos.<\/P>
La trama tiene tres hilos en su historia de velocidad de datos; los ciclos de vida del conjunto de datos los estoy categorizando como:<\/P>
- Reemplazo masivo periódico poco frecuente
- Datos base que no están habilitados por tiempo
<\/UL><\/LI>- Adición y actualización frecuente
- Capa operativa que crece continuamente y tiene etapas de vida y está habilitada por tiempo
<\/UL><\/LI>- Ediciones de inserción, actualización y eliminación con frecuencia media
- Capas operativas que evolucionan y están habilitadas por tiempo
<\/UL><\/LI><\/OL>Mi objetivo es mostrar cómo los datos podrían ofrecerse en cada uno de los escenarios anteriores de velocidad, de manera cloud native, e integrarse en ArcGIS. El hilo común es que el formato cloud native que usaremos es GeoParquet en un almacenamiento de objetos compatible con API S3 pública como AWS. En todos los casos usaremos ArcPy y DuckDB en notebooks o herramientas script para el consumo de datos, con el entendimiento de que un custodio de datos proporcionaría a los consumidores las herramientas necesarias para que ArcGIS consuma los datos. La combinación de S3, GeoParquet y DuckDB proporciona una implementación eficiente y funcional en ArcGIS.<\/STRONG><\/P>Vamos a profundizar.<\/P> <\/P> <\/P>Reemplazo Masivo Periódico<\/H3> <\/P>Mi dato temático es Overture Maps Foundation Division Area, un conjunto de datos a escala global publicado mensualmente. El modelo de datos incluye geometría poligonal con un nombre principal del lugar y un objeto struct con nombres alternativos en muchos idiomas. Los datos fuente al momento de escribir son diez archivos GeoParquet en AWS S3, con un esquema común. No hay particionamiento lógico. El producto de información que quiero es una clase de entidad geodatabase, tabla relacionada con nombres alternativos más un localizador geocodificador que entienda todos los nombres. <\/STRONG>Aquí se muestra cómo lucen los datos espaciales sobre Europa:<\/P>Division Areas<\/span><\/P>Para usar mi producto de información, por ejemplo si quiero encontrar Madrid en España usando el idioma Bihari (el popup muestra los nombres disponibles para Madrid) doy 2e 48 21 4d 30 3f 21 como dirección:<\/P>92e94892194d93093f921 encuentra Madrid<\/span><\/P>Un notebook es apropiado para el producto de información, puedes encontrarlo en la descarga del blog, y realmente su único truco es usar la ruta glob adecuada hacia los datos GeoParquet, mira esta celda:<\/P>sql = f"""create or replace temp view division_area_view as select
id,
names.primary as primary_name,
class,
subtype,
region,
country,
version,
is_land,
is_territorial,
bbox.xmin as xmin,
bbox.ymin as ymin,
bbox.xmax as xmax,
bbox.ymax as ymax,
division_id,
geometry
from read_parquet('s3://overturemaps-us-west-2/release/{release}/theme=divisions/type=division_area/*.parquet',filename=false, hive_partitioning=1)
where {whereExp}
order by country, ST_Area(geometry) desc;"""
view = conn.sql(sql)<\/code><\/pre><P>DuckDB puede usar rutas glob para datos locales o remotos, y hacer consultas remotas con la API S3, y estas consultas se paralelizan a través de todos los archivos en la ruta glob. Nota que la ruta incluye un identificador de versión, esto se toma desde un catálogo STAC en tiempo de ejecución. <STRONG>Este es el tema central de esta publicación - cuándo y cómo usar GeoParquet y DuckDB con datos que cambian a intervalos.<\/STRONG> <STRONG> En este caso no sabemos qué registros cambiaron por lo que no podemos consultarlos fácilmente, así que hacemos una extracción masiva.<\/STRONG><\/P><P>1Qué pasa si sí sabemos qué registros cambiaron?</P><P> </P><H3 id="toc-hId--574234924">Adición y Actualización Frecuente</H3><P> </P><P>Mi ejemplo de dato "ocupado" es <A title="San Francisco 311 Data" href="https://data.sfgov.org/City-Infrastructure/311-Cases/vw6y-z8j6/about_data" target="_blank" rel="noopener nofollow noreferrer">datos 311 para San Francisco</A>. El conjunto se actualiza continuamente con miles de casos abiertos, editados o cerrados cada día, pero no se depura, y data desde 2008. Al momento de escribir la descarga masiva tiene 8 millones de entidades, vistas aquí a escala 1:10000:<\/P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="311 Cases in San Francisco" style="width: 999px;"><img src="https://us.v-cdn.net/6038851/uploads/images/151351i986691A8041EA18B/SanFrancisco.png" role="button" title="SanFrancisco.png" alt="311 Cases in San Francisco" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">311 Cases in San Francisco</span><\/span><\/P><P>Muchos conjuntos "de eventos" como este existen, entonces ¿cómo podría entregarse eficientemente el conjunto nativo cloud? La respuesta depende que los datos tengan campos timestamp para cuando los casos son abiertos, actualizados y cerrados, con el campo <STRONG>updated_datetime</STRONG> sí siendo actualizado ante cualquier cambio de estado. Como el sitio open data San Francisco (y por tanto el sistema registro detrás) tiene una API que soporta consultas entonces esto puede hacerse para cambios basados en updated_datetime. Aquí está el enfoque tomado en las herramientas compartidas en la descarga del blog:<\/P><UL><LI>Hacer una descarga masiva inicial a un archivo GeoParquet base<\/LI><LI>Bajo un horario frecuente<UL><LI>Consultar el(los) archivo(s) GeoParquet existente(s) por el valor máximo updated_datetime<\/LI><LI>Consultar el sistema registro 311 por registros más recientes al máximo<UL><LI>Esta es una consulta rápida<\/LI><\/UL><\/LI><LI>Escribir el resultado consulta a un nuevo archivo GeoParquet adicional<UL><LI>Todos los archivos GeoParquet deben estar en la misma ruta glob<\/LI><\/UL><\/LI><\/UL><\/LI><LI>Bajo demanda, consultar el conjunto archivos GeoParquet para extraer datos relevantes<UL><LI>Esa consulta usa una cláusula SQL <STRONG>sencilla pero poderosa</STRONG>, sigue leyendo...<\/LI><\/UL><\/LI><\/UL><P>Aquí hay una consulta ejemplo donde extraigo a una clase entidad memoria todos los casos 311 hasta la fecha para 2026 dentro un polígono - <STRONG>esto tomó 4 segundos</STRONG>. Hay alrededor 8500 entidades.<\/P><P><span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="Consulta San Francisco" style="width: 999px;"><img src="https://us.v-cdn.net/6038851/uploads/images/151356i86B6BAA957628C34/SanFranciscoQuery.png" role="button" title="SanFranciscoQuery.png" alt="Consulta San Francisco" /><span class="lia-inline-image-caption" onclick="event.preventDefault();">Consulta San Francisco</span></span></p>
<p>La herramienta consulta es una herramienta script, su salsa secreta es la cláusula <A title="QUALIFY Clause" href="https://duckdb.org/docs/current/sql/query_syntax/qualify" target="_blank" rel="noopener nofollow noreferrer">QUALIFY</A>. Los archivos GeoParquet hechos con datos diarios tendrán duplicados debido al ciclo vida del caso (abierto un día, editado otro día, cerrado otro día posterior) entonces <strong>sólo queremos la fila más reciente por valor service_request_id</strong> entre todos los archivos GeoParquet - la cláusula QUALIFY al consultar parquet hace esto por nosotros.<pre class='lia-code-sample language-python'><code> conn.sql(f'''create or replace temp view sf311_view as select
service_request_id,requested_datetime,closed_date,updated_datetime,
status_description,status_notes,agency_responsible,service_name,
service_subtype,service_details,address,street,supervisor_district,
neighborhoods_sffind_boundaries,police_district,source,media_url,
bos_2012,data_as_of,data_loaded_at,ST_AsWKB(GEOM) as wkb
from read_parquet('{pqPath}',filename=false)
where {where}
and ST_Intersects(ST_GeomFromText('{wkt}'), GEOM)
qualify row_number() over (partition by service_request_id order by updated_datetime desc) = 1;''')
Así ahora tenemos una simple manera de entregar datos que cambian rápidamente de forma cloud native con consultas rápidas.<\/P>¿Qué pasa si tenemos datos bastante grandes pero no hay forma de consultar los cambios?<\/P> <\/P>Inserciones, Actualizaciones y Eliminaciones Continuas de Ediciones<\/H3> <\/P>Los datos sujetos a una edición versionada por ramas intensiva son un trabajo de alto valor para GIS, y aunque puedes compartir el estado de los datos dando acceso a sus servicios de características subyacentes, agregar una carga pública de mapeo al servidor no será bien recibido por el administrador. Resulta que puedes compartir el estado de los datos, con soporte para viaje en el tiempo, usando un enfoque cloud-native<\/STRONG>. Lo que permite esto es el modelo de datos solo inserción<\/STRONG> de versionado por ramas<\/STRONG> - el estado de una característica en cualquier momento está determinado por GDB_FROM_DATE en combinación con OBJECTID - la fila con la última GDB_FROM_DATE para cada valor único de OBJECTID es el estado actual de una característica, y si consultas valores anteriores de GDB_FROM_DATE obtienes viaje en el tiempo. El único truco es crear archivos GeoParquet que representen momentos de edición, pero entonces la cláusula QUALIFY vuelve a ser la solución para entregar los datos que deseas.<\/P>Aquí hay dos vistas de datos parcelarios sobre la misma extensión y usando los mismos archivos fuente GeoParquet<\/STRONG>.<\/P>Momentos actuales y anteriores<\/span><\/span><\/P>La vista izquierda es el momento más reciente, la vista derecha es un momento anterior, puedes ver que se ha realizado mucha subdivisión parcelaria. La fuente de datos conserva todo el historial completo, las ediciones resultan en nuevos archivos GeoParquet añadidos a una carpeta o almacenamiento de objetos en la nube. Aquí tengo un archivo GeoParquet base de 1.46GB para el estado original de los datos con un par de pequeños archivos GeoParquet que contienen ediciones durante dos semanas.<\/STRONG><\/P>Archivos GeoParquet que contienen historial completo de datos<\/span><\/span><\/P>Aquí hay un manifiesto del archivo descargable del blog CloudNativeDataDistribution.zip<\/STRONG>:<\/P>- ImportCurrentDivisionAreas.ipynb<\/STRONG> notebookDescarga las características Overture Division Area a tu geodatabase principal del proyecto<\/LI>Crea nombres multilingües para las características en una tabla relacionada<\/LI>Crea o actualiza un localizador usando las características Division Area como datos de referencia<\/LI><\/UL><\/LI>GetBaselineSF311<\/STRONG> herramienta ETL espacialExtrae el conjunto completo 311 para San Francisco a GeoParquet<\/LI>Requiere ArcGIS Data Interoperability<\/LI>Requiere una cuenta y token de aplicación<\/LI><\/UL><\/LI>GetUpdatesSF311<\/STRONG> herramienta ETL espacialExtrae datos del caso 311 más recientes que cualquiera en un archivo GeoParquet existente<\/LI>Crea un nuevo archivo GeoParquet<\/LI>Requiere ArcGIS Data Interoperability<\/LI>Requiere una cuenta y token de aplicación<\/LI><\/UL><\/LI>Generate311Points <\/STRONG>herramienta scriptMuestra cómo usar los archivos GeoParquet para crear una clase de entidad en memoria<\/LI><\/UL><\/LI>ExtractCurrentParcels.ipynb<\/STRONG> notebook
Muestra cómo extraer el estado más reciente de los datos desde archivos GeoParquet en un modelo versionado por ramas<\/LI><\/UL><\/LI>ExtractEarlierParcels.ipynb<\/STRONG> notebookMuestra cómo extraer un estado anterior de los datos desde archivos GeoParquet en un modelo versionado por ramas<\/LI><\/UL><\/LI><\/UL>No incluidos, pero disponibles bajo solicitud, están las herramientas usadas para construir archivos GeoParquet para los datos parcelarios. Recuerda, donde mis herramientas de ejemplo usan almacenamiento local para GeoParquet, en producción usarías un almacenamiento de objetos en la nube, como AWS S3.<\/P>Ahora, aunque espero verte en la Conferencia de Usuarios 2026 en San Diego, si necesitas más motivación aquí tienes un adelanto exclusivo de una demo que lleva los datos temáticos Overture Building a una escena. Mira si puedes encontrar un par de herramientas script easter egg en la descarga del blog 😉<\/span>.<\/P>
Edificios Overture<\/span><\/span><\/P> <\/P>