Trabajar con datos geoespaciales

Las analíticas geoespaciales te permiten analizar datos geográficos en BigQuery. Los datos geográficos también se conocen como datos geoespaciales.

Entre los tipos de objetos más habituales al trabajar con datos geoespaciales se incluyen los siguientes:

  • Una geometría representa una superficie de la Tierra. A menudo se describe mediante puntos, líneas, polígonos o una colección de puntos, líneas y polígonos. Una colección de geometrías es una geometría que representa la unión espacial de todas las formas de la colección.
  • Una entidad espacial representa un objeto espacial lógico. Combina una geometría con atributos adicionales específicos de la aplicación.
  • Una colección de elementos espaciales es un conjunto de elementos espaciales.

En BigQuery, el tipo de datos GEOGRAPHY representa un valor de geometría o una colección de geometrías. Para representar elementos espaciales, crea una tabla con una columna GEOGRAPHY para la geometría y columnas adicionales para los atributos. Cada fila de la tabla es una entidad espacial y toda la tabla representa una colección de entidades espaciales.

El tipo de datos GEOGRAPHY describe un conjunto de puntos en la superficie de la Tierra. Un conjunto de puntos es un conjunto de puntos, líneas y polígonos en el esferoide de referencia WGS84 con aristas geodésicas. Puedes usar el tipo de datos GEOGRAPHY llamando a una de las funciones geográficas de GoogleSQL.

Cargar datos geoespaciales

Los puntos de la Tierra se pueden describir con un par de longitud y latitud. Por ejemplo, puedes cargar un archivo CSV que contenga valores de longitud y latitud y, a continuación, usar la función ST_GEOGPOINT para convertirlos en valores GEOGRAPHY.

En el caso de las zonas geográficas más complejas, puede cargar los siguientes formatos de datos geoespaciales en una columna GEOGRAPHY:

  • Texto conocido (WKT)
  • Binario conocido (WKB)
  • GeoJSON
  • GeoParquet

Cargar datos de WKT o WKB

WKT es un formato de texto para describir formas geométricas individuales mediante puntos, líneas, polígonos con agujeros opcionales o una colección de puntos, líneas o polígonos. WKB es la versión binaria del formato WKT. WKB se puede codificar en hexadecimal para formatos que no admiten datos binarios, como JSON.

Por ejemplo, en el siguiente código se define un punto en WKT:

POINT(-121 41)

Para describir una entidad espacial, el formato WKT suele insertarse en un formato de archivo contenedor, como un archivo CSV, o en una tabla de una base de datos. Una fila de un archivo o de una tabla suele corresponder a la entidad espacial. Todo el archivo o toda la tabla corresponde a la colección de elementos. Para cargar datos WKT en BigQuery, proporciona un esquema que especifique una columna GEOGRAPHY para los datos geoespaciales.

Por ejemplo, puede que tengas un archivo CSV con los siguientes datos:

"POLYGON((-124.49 47.35,-124.49 40.73,-116.49 40.73,-116.49 47.35,-124.49 47.35))",poly1
"POLYGON((-85.6 31.66,-85.6 24.29,-78.22 24.29,-78.22 31.66,-85.6 31.66))",poly2
"POINT(1 2)",point1

Para cargar este archivo, ejecuta el comando load de la herramienta de línea de comandos bq:

bq load --source_format=CSV \
  --schema="geography:GEOGRAPHY,name:STRING" \
  mydataset.mytable filename1.csv

Para obtener más información sobre cómo cargar datos en BigQuery, consulta la introducción a la carga de datos.

Para transmitir datos WKT a una tabla de BigQuery que ya tenga una columna GEOGRAPHY, serializa los datos como una cadena en la solicitud a la API.

bq

Ejecuta el comando insert de la herramienta de línea de comandos bq:

echo '{"geo": "LINESTRING (-118.4085 33.9416, -73.7781 40.6413)"}' \
    | bq insert my_dataset.geo_table

Python

Antes de probar este ejemplo, sigue las Pythoninstrucciones de configuración de la guía de inicio rápido de BigQuery con bibliotecas de cliente. Para obtener más información, consulta la documentación de referencia de la API Python de BigQuery.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación para bibliotecas de cliente.

from google.cloud import bigquery
import shapely.geometry
import shapely.wkt

bigquery_client = bigquery.Client()

# This example uses a table containing a column named "geo" with the
# GEOGRAPHY data type.
table_id = "my-project.my_dataset.my_table"

# Use the Shapely library to generate WKT of a line from LAX to
# JFK airports. Alternatively, you may define WKT data directly.
my_geography = shapely.geometry.LineString(
    [(-118.4085, 33.9416), (-73.7781, 40.6413)]
)
rows = [
    # Convert data into a WKT string.
    {"geo": shapely.wkt.dumps(my_geography)},
]

#  table already exists and has a column
# named "geo" with data type GEOGRAPHY.
errors = bigquery_client.insert_rows_json(table_id, rows)
if errors:
    raise RuntimeError(f"row insert failed: {errors}")
else:
    print(f"wrote 1 row to {table_id}")

Para obtener más información sobre la transmisión de datos en BigQuery, consulta el artículo Transmitir datos a BigQuery.

También puedes convertir una cadena de texto WKT en un valor GEOGRAPHY con la función ST_GEOGFROMTEXT.

Cargar datos de GeoJSON

GeoJSON es un formato basado en JSON para geometrías y elementos espaciales. Por ejemplo, el siguiente código define un punto en GeoJSON:

{ "type": "Point", "coordinates": [-121,41] }

Los datos de GeoJSON pueden contener cualquiera de los siguientes tipos de objetos:

  • Objetos de geometría. Un objeto de geometría es una forma espacial que se describe como una unión de puntos, líneas y polígonos con agujeros opcionales.
  • Destacar objetos. Un objeto de entidad contiene una geometría más pares nombre/valor adicionales, cuyo significado es específico de la aplicación.
  • Colecciones de funciones. Una colección de entidades es un conjunto de objetos de entidad.

Hay dos formas de cargar datos GeoJSON en BigQuery:

Cargar archivos GeoJSON delimitados por líneas nuevas

Un archivo GeoJSON delimitado por líneas nuevas contiene una lista de objetos de características GeoJSON, uno por línea en el archivo. Un objeto de elemento GeoJSON es un objeto JSON con los siguientes miembros:

  • type. En el caso de los objetos de función, el valor debe ser Feature. BigQuery valida el valor, pero no lo incluye en el esquema de la tabla.

  • geometry. El valor es un objeto Geometry GeoJSON o null. BigQuery convierte este miembro en un valor GEOGRAPHY.

  • properties. El valor es cualquier objeto JSON o null. Si el valor no es null, BigQuery carga cada miembro del objeto JSON como una columna de tabla independiente. Para obtener más información sobre cómo analiza BigQuery los tipos de datos JSON, consulta Detalles de la carga de datos JSON.

  • id. Opcional. Si está presente, el valor es una cadena o un número. BigQuery carga este valor en una columna llamada id.

Si el objeto de entidad contiene otros miembros que no se indican aquí, BigQuery los convierte directamente en columnas de la tabla.

Para cargar un archivo GeoJSON delimitado por saltos de línea, puedes usar el comando bq load de la herramienta de línea de comandos bq, tal como se indica a continuación:

bq load \
 --source_format=NEWLINE_DELIMITED_JSON \
 --json_extension=GEOJSON \
 --autodetect \
 DATASET.TABLE \
 FILE_PATH_OR_URI

Haz los cambios siguientes:

  • DATASET es el nombre de su conjunto de datos.
  • TABLE es el nombre de la tabla de destino.
  • FILE_PATH_OR_URI es una ruta a un archivo local o un URI de Cloud Storage.

En el ejemplo anterior se habilita la detección automática de esquemas. Para tener más control sobre cómo BigQuery convierte los valores del objeto properties, puedes proporcionar un esquema explícito. Para obtener más información, consulta Especificar esquemas. Si proporciona un esquema explícito, no incluya una columna type de nivel superior en la definición del esquema. Define columnas independientes para cada miembro de properties, no una sola columna anidada.

Tal como se define en RFC 7946, una estructura de datos GeoJSON completa es un único objeto JSON. Muchos sistemas exportan datos GeoJSON como un único objeto FeatureCollection que contiene todas las geometrías. Para cargar este formato en BigQuery, debe convertir el archivo quitando el objeto FeatureCollection de nivel raíz y dividiendo los objetos de características individuales en líneas independientes. Por ejemplo, el siguiente comando usa la herramienta de línea de comandos jq para dividir un archivo GeoJSON en formato delimitado por líneas nuevas:

cat ~/file1.json | jq -c '.features[]' > converted.json

Crear una tabla externa a partir de un archivo GeoJSON delimitado por saltos de línea

Puedes consultar un archivo GeoJSON delimitado por saltos de línea almacenado en Cloud Storage creando una tabla externa. Para crear la tabla externa, usa la declaración de DDL CREATE EXTERNAL TABLE. En la cláusula OPTIONS, asigna el valor NEWLINE_DELIMITED_JSON a la opción format y el valor GEOJSON a la opción json_extension.

Ejemplo:

CREATE EXTERNAL TABLE mydataset.table1 OPTIONS (
  format="NEWLINE_DELIMITED_JSON",
  json_extension = 'GEOJSON',
  uris = ['gs://mybucket/geofile.json']
);

Cargar datos de geometría GeoJSON

La analítica geoespacial permite cargar objetos de geometría GeoJSON individuales que están insertados como cadenas de texto en otros tipos de archivo. Por ejemplo, puede cargar un archivo CSV en el que una de las columnas contenga un objeto de geometría GeoJSON.

Para cargar este tipo de datos GeoJSON en BigQuery, proporcione un esquema que especifique una columna GEOGRAPHY para los datos GeoJSON. Debes proporcionar el esquema manualmente. De lo contrario, si la detección automática está habilitada, BigQuery cargará los datos como un valor STRING.

La analítica geoespacial no admite la carga de objetos de características ni colecciones de características GeoJSON con este método. Si necesitas cargar objetos de características, te recomendamos que utilices archivos GeoJSON delimitados por líneas nuevas.

Para transmitir datos GeoJSON a una tabla de BigQuery que ya tenga una columna GEOGRAPHY, serializa los datos como una cadena en la solicitud de la API.

bq

Ejecuta el comando insert de la herramienta de línea de comandos bq:

echo '{"geo": "{\"type\": \"LineString\", \"coordinates\": [[-118.4085, 33.9416], [-73.7781, 40.6413]]}"}' \
  | bq insert my_dataset.geo_table

Python

Antes de probar este ejemplo, sigue las Pythoninstrucciones de configuración de la guía de inicio rápido de BigQuery con bibliotecas de cliente. Para obtener más información, consulta la documentación de referencia de la API Python de BigQuery.

Para autenticarte en BigQuery, configura las credenciales predeterminadas de la aplicación. Para obtener más información, consulta el artículo Configurar la autenticación para bibliotecas de cliente.

import geojson
from google.cloud import bigquery

bigquery_client = bigquery.Client()

# This example uses a table containing a column named "geo" with the
# GEOGRAPHY data type.
table_id = "my-project.my_dataset.my_table"

# Use the python-geojson library to generate GeoJSON of a line from LAX to
# JFK airports. Alternatively, you may define GeoJSON data directly, but it
# must be converted to a string before loading it into BigQuery.
my_geography = geojson.LineString([(-118.4085, 33.9416), (-73.7781, 40.6413)])
rows = [
    # Convert GeoJSON data into a string.
    {"geo": geojson.dumps(my_geography)}
]

#  table already exists and has a column
# named "geo" with data type GEOGRAPHY.
errors = bigquery_client.insert_rows_json(table_id, rows)
if errors:
    raise RuntimeError(f"row insert failed: {errors}")
else:
    print(f"wrote 1 row to {table_id}")

También puedes convertir un objeto de geometría GeoJSON en un valor GEOGRAPHY con la función ST_GEOGFROMGEOJSON. Por ejemplo, puedes almacenar las geometrías como valores STRING y, a continuación, ejecutar una consulta que llame a ST_GEOGFROMGEOJSON.

Cargar archivos GeoParquet

GeoParquet es una especificación que añade tipos geoespaciales al formato de archivo Parquet. GeoParquet incluye metadatos que proporcionan una semántica definida a los datos geoespaciales que contiene, lo que evita los problemas de interpretación que se producen con otros formatos de datos geoespaciales.

Al cargar archivos Parquet, BigQuery comprueba los metadatos de GeoParquet. Si existen metadatos de GeoParquet, BigQuery carga todas las columnas que describe en una columna GEOGRAPHY correspondiente de forma predeterminada. Para obtener más información sobre cómo cargar archivos Parquet, consulta Cargar datos de Parquet.

Crear una tabla externa a partir de datos GeoParquet

Las tablas externas que hacen referencia a archivos GeoParquet asignan las columnas pertinentes al tipo GEOGRAPHY.

Las estadísticas disponibles en el archivo GeoParquet (bbox, covering) no se usan para acelerar las consultas en una tabla externa.

Sistemas de coordenadas y bordes

En las analíticas geoespaciales, los puntos son posiciones en la superficie de un esferoide WGS84, expresadas como longitud y latitud geodésica. Una arista es una geodésica esférica entre dos puntos finales. Es decir, las aristas son la ruta más corta en la superficie de una esfera.

El formato WKT no proporciona un sistema de coordenadas. Al cargar datos WKT, el análisis geoespacial asume que los datos usan coordenadas WGS84 con bordes esféricos. Asegúrate de que los datos de origen coincidan con ese sistema de coordenadas, a menos que las zonas geográficas sean lo suficientemente pequeñas como para que se puedan ignorar las diferencias entre los bordes esféricos y los planos.

GeoJSON usa explícitamente coordenadas WGS84 con aristas planas. Al cargar datos GeoJSON, la analítica geoespacial convierte los bordes planos en bordes esféricos. La analítica geoespacial añade puntos adicionales a la línea según sea necesario para que la secuencia de aristas convertida se mantenga a una distancia máxima de 10 metros de la línea original. Este proceso se conoce como teselación o densificación no uniforme. No puedes controlar directamente el proceso de teselación.

Para cargar geografías con bordes esféricos, usa WKT. Para cargar geografías con bordes planos, a menudo denominadas geometrías, lo más sencillo es usar GeoJSON. Sin embargo, si los datos de geometría ya están en formato WKT, otra opción es cargarlos como tipo STRING y, a continuación, usar la función ST_GEOGFROMTEXT para convertirlos en valores GEOGRAPHY. Define el parámetro planar como TRUE para interpretar los datos como planares.

Los archivos GeoParquet incluyen metadatos sobre el sistema de coordenadas y los bordes que se han usado para crear los datos. Al leer archivos GeoParquet con aristas planas, las analíticas geoespaciales convierten las aristas planas en aristas esféricas. Los archivos GeoParquet con sistemas de coordenadas distintos de WGS84 se rechazan.

Al elegir un formato de intercambio, asegúrese de conocer el sistema de coordenadas que utilizan sus datos de origen. La mayoría de los sistemas admiten explícitamente el análisis de geografía (en lugar de geometría) a partir de WKT o bien asumen aristas planas.

Las coordenadas deben ser primero la longitud y, después, la latitud. Si la geografía tiene segmentos o bordes largos, deben teselarse, ya que la analítica geoespacial los interpreta como geodésicas esféricas, que pueden no corresponderse con el sistema de coordenadas del que proceden los datos.

Orientación del polígono

En una esfera, cada polígono tiene un polígono complementario. Por ejemplo, un polígono que describa los continentes de la Tierra tendría un polígono complementario que describa los océanos de la Tierra. Como los dos polígonos se describen con los mismos anillos de límite, se necesitan reglas para resolver la ambigüedad sobre cuál de los dos polígonos se describe con una cadena WKT determinada.

Cuando cargas cadenas WKT y WKB desde archivos o mediante la ingestión de streaming, la analítica geoespacial asume que los polígonos de la entrada están orientados de la siguiente manera: si recorres el límite del polígono en el orden de los vértices de entrada, el interior del polígono está a la izquierda. Las analíticas geoespaciales usan la misma regla al exportar objetos geográficos a cadenas WKT y WKB.

Si usa la función ST_GEOGFROMTEXT para convertir una cadena WKT en un valor GEOGRAPHY, el parámetro oriented especifica cómo determina la función el polígono:

  • FALSE: interpreta la entrada como el polígono con el área más pequeña. Este es el comportamiento predeterminado.

  • TRUE: usa la regla de orientación de la mano izquierda descrita anteriormente. Esta opción te permite cargar polígonos con un área mayor que un hemisferio.

Como las cadenas GeoJSON se definen en un mapa plano, la orientación se puede determinar sin ambigüedad, aunque la entrada no siga la regla de orientación definida en la especificación del formato GeoJSON, RFC 7946.

Gestión de datos espaciales con formato incorrecto

Cuando cargas datos espaciales de otras herramientas en BigQuery, es posible que se produzcan errores de conversión debido a que los datos WKT o GeoJSON no son válidos. Por ejemplo, un error como Edge K has duplicate vertex with edge N indica que el polígono tiene vértices duplicados (además del primero y el último).

Para evitar problemas de formato, puede usar una función que genere una salida conforme a los estándares. Por ejemplo, cuando exportas datos de PostGIS, puedes usar la función ST_MakeValid de PostGIS para estandarizar la salida. También puede importar los datos como texto y, a continuación, convertirlos llamando a ST_GEOGFROMTEXT o ST_GEOGFROMGEOJSON con el parámetro make_valid. Si make_valid es TRUE, estas funciones intentan reparar los polígonos no válidos.

Para buscar o ignorar los datos con formato incorrecto, usa el prefijo de función SAFE para mostrar los datos problemáticos. Por ejemplo, la siguiente consulta usa el prefijo SAFE para recuperar datos espaciales con un formato incorrecto.

SELECT
  geojson AS bad_geojson
FROM
  mytable
WHERE
  geojson IS NOT NULL
  AND SAFE.ST_GEOGFROMGEOJSON(geojson) IS NULL

Restricciones

La analítica geoespacial no admite las siguientes funciones en formatos geoespaciales:

  • Geometrías tridimensionales. Esto incluye el sufijo "Z" en el formato WKT y la coordenada de altitud en el formato GeoJSON.
  • Sistemas de referencia lineales. Esto incluye el sufijo "M" en formato WKT.
  • Objetos geométricos WKT que no sean primitivas geométricas ni geometrías multiparte. En concreto, la analítica geoespacial solo admite los tipos Point, MultiPoint, LineString, MultiLineString, Polygon, MultiPolygon y GeometryCollection.

Consulta las restricciones específicas de los formatos de entrada GeoJSON y WKT en los artículos ST_GEOGFROMGEOJSON y ST_GEOGFROMTEXT.

Integrar datos ráster geoespaciales con Google Earth Engine

Las estadísticas geoespaciales suelen presentarse como datos basados en cuadrículas o rasterizados. Los datos ráster organizan datos continuos a nivel regional, como imágenes de satélite, previsiones meteorológicas y cobertura del suelo, en una cuadrícula de píxeles. Aunque BigQuery se especializa principalmente en datos vectoriales tabulares, que representan elementos con límites y puntos, puedes integrar datos ráster en tus análisis de BigQuery mediante la función ST_REGIONSTATS. Esta función usa Earth Engine, la plataforma de análisis de rásteres de Google, para realizar cálculos y agregaciones en datos de rásteres y mejorar el análisis geoespacial. Para obtener más información, consulta Trabajar con datos ráster.

Para obtener información sobre cómo exportar datos de Earth Engine a BigQuery, consulta el artículo Exportar a BigQuery. Para obtener más información sobre las integraciones entre Earth Engine y BigQuery, consulta el artículo Integración con BigQuery de la documentación de Earth Engine.

Transformar datos geoespaciales

Si tu tabla contiene columnas independientes para la longitud y la latitud, puedes transformar los valores en geografías mediante las funciones de geografía de GoogleSQL, como ST_GEOGPOINT. Por ejemplo, si tiene dos columnas DOUBLE para la longitud y la latitud, puede crear una columna de geografía con la siguiente consulta:

SELECT
  *,
  ST_GEOGPOINT(longitude, latitude) AS g
FROM
  mytable

BigQuery puede convertir cadenas WKT y GeoJSON en tipos de geografía. Si tus datos están en otro formato, como Shapefiles, usa una herramienta externa para convertir los datos a un formato de archivo de entrada compatible, como un archivo CSV, con GEOGRAPHYcolumnas codificadas como cadenas WKT o GeoJSON.

Particiones y clústeres de datos geoespaciales

Puedes crear particiones y agrupar en clústeres tablas que contengan GEOGRAPHY columnas. Puede usar una columna GEOGRAPHY como columna de agrupamiento en clústeres, pero no como columna de partición.GEOGRAPHY

Si almacenas datos GEOGRAPHY en una tabla y tus consultas filtran datos mediante un predicado espacial, asegúrate de que la tabla esté agrupada en clústeres por la columna GEOGRAPHY. Esto suele mejorar el rendimiento de las consultas y puede reducir los costes. Un predicado espacial llama a una función geográfica booleana y tiene una columna GEOGRAPHY como uno de los argumentos. En el siguiente ejemplo se muestra un predicado espacial que usa la función ST_DWITHIN:

WHERE ST_DWITHIN(geo, ST_GeogPoint(longitude, latitude), 100)

Usar JOINs con datos espaciales

Las uniones espaciales son uniones de dos tablas con una función geográfica de predicado en la cláusula WHERE. Por ejemplo:

-- how many stations within 1 mile range of each zip code?
SELECT
    zip_code AS zip,
    ANY_VALUE(zip_code_geom) AS polygon,
    COUNT(*) AS bike_stations
FROM
    `bigquery-public-data.new_york.citibike_stations` AS bike_stations,
    `bigquery-public-data.geo_us_boundaries.zip_codes` AS zip_codes
WHERE ST_DWITHIN(
         zip_codes.zip_code_geom,
         ST_GEOGPOINT(bike_stations.longitude, bike_stations.latitude),
         1609.34)
GROUP BY zip
ORDER BY bike_stations DESC

Las uniones espaciales funcionan mejor cuando los datos geográficos se conservan. En el ejemplo anterior se crean los valores de geografía en la consulta. Es más eficiente almacenar los valores de geografía en una tabla de BigQuery.

Por ejemplo, la siguiente consulta obtiene pares de longitud y latitud, y los convierte en puntos geográficos. Cuando ejecutas esta consulta, especificas una nueva tabla de destino para almacenar los resultados de la consulta:

SELECT
  *,
  ST_GEOGPOINT(pLongitude, pLatitude) AS p
FROM
  mytable

BigQuery implementa JOINs espaciales optimizados para los operadores INNER JOIN y CROSS JOIN con las siguientes funciones de predicado de GoogleSQL:

Las combinaciones espaciales no están optimizadas:

  • Si se une LEFT, RIGHT o FULL OUTER
  • En los casos que implican anti-joins
  • Cuando se niega el predicado espacial

Un JOIN que usa el predicado ST_DWITHIN solo se optimiza cuando el parámetro de distancia es una expresión constante.

Exportar datos espaciales

Cuando exportas datos espaciales de BigQuery, los valores de la columna GEOGRAPHY siempre se formatean como cadenas WKT. Para exportar datos en formato GeoJSON, usa la función ST_ASGEOJSON.

Si las herramientas que usas para analizar los datos exportados no reconocen el tipo de datos GEOGRAPHY, puedes convertir los valores de la columna en cadenas mediante una función geográfica, como ST_ASTEXT o ST_ASGEOJSON. La analítica geoespacial añade puntos adicionales a la línea cuando es necesario para que la secuencia de aristas convertida se mantenga a una distancia máxima de 10 metros de la línea geodésica original.

Por ejemplo, la siguiente consulta usa ST_ASGEOJSON para convertir valores de GeoJSON en cadenas.

SELECT
  ST_ASGEOJSON(ST_MAKELINE(ST_GEOGPOINT(1,1), ST_GEOGPOINT(3,2)))

Los datos resultantes serían similares a los siguientes:

{ "type": "LineString", "coordinates": [ [1, 1], [1.99977145571783, 1.50022838764041], [2.49981908082299, 1.75018082434274], [3, 2] ] }

La línea GeoJSON tiene dos puntos adicionales. Las analíticas geoespaciales añaden estos puntos para que la línea GeoJSON siga el mismo recorrido en el suelo que la línea original.

Siguientes pasos