Skip to content

Instantly share code, notes, and snippets.

@esgn
Last active September 20, 2026 16:03
Show Gist options
  • Select an option

  • Save esgn/625bb8aa722523bf39bc44a79c984fa1 to your computer and use it in GitHub Desktop.

Select an option

Save esgn/625bb8aa722523bf39bc44a79c984fa1 to your computer and use it in GitHub Desktop.
duckdb + geoparquet

Test geoparquet BDTOPO avec DuckDB

Maintenant que le bug sur les headers manquant est corrigé, je reteste à nouveau.
Je teste avec DuckDB v1.5.5 (Variegata) sous Ubuntu 24.04.5 LTS

Version des données

Deux versions sont disponibles sur https://data.geopf.fr/chunk/telechargement/ : 15/03/2026 et 15/06/2026

La page de documentation incitant les utilisateurs à tester référence le jeu de donnée du 15/03/2026.
Je n'ai pas trouvé de documentation pour la version du 15/06/2026. J'ai pu rater quelque chose.

⚠️ Il manque tout le thème administratif dans l'édition de juin ⚠️

Soit les fichiers suivants :

arrondissement.parquet
arrondissement_municipal.parquet
canton.parquet
collectivite_territoriale.parquet
commune.parquet
commune_associee_ou_deleguee.parquet
condominium.parquet
departement.parquet
epci.parquet
region.parquet

Comparaison des fichiers avec DuckDB

INSTALL httpfs; LOAD httpfs;

-- Éviter un téléchargement intégral si la lecture partielle échoue.
SET auto_fallback_to_full_download = false;

-- pour éviter de se trimbaler les URLs
SET VARIABLE mars = 'https://data.geopf.fr/chunk/telechargement/download/BDTOPO_PQT/BDTOPO_3-5_TOUSTHEMES_GEOPARQUET_WGS84G_FRA_2026-03-15/batiment.parquet';
SET VARIABLE juin = 'https://data.geopf.fr/chunk/telechargement/download/BDTOPO_PQT/BDTOPO_TOUSTHEMES_3-5_GEOPARQUET_WGS84G_FRA_2026-06-15/batiment.parquet';

-- On créé des vues locales
CREATE OR REPLACE TEMP VIEW batiment_mars AS SELECT * FROM read_parquet(getvariable('mars'));
CREATE OR REPLACE TEMP VIEW batiment_juin AS SELECT * FROM read_parquet(getvariable('juin'));

En faisant un DESCRIBE sur les deux vues, on note que le champ geometrie est défini différement dans les deux cas.

 DESCRIBE SELECT geometrie FROM batiment_mars;
┌──────────────────────────────────────────────────────┐
│                    batiment_mars                     │
│                                                      │
│ geometrie struct(x double, y double, z double)[][][] │
└──────────────────────────────────────────────────────┘
DESCRIBE SELECT geometrie FROM batiment_juin;
┌─────────────────────────────────┐
│          batiment_juin          │
│                                 │
│ geometrie geometry('ogc:crs84') │
└─────────────────────────────────┘

En fouillant un peu plus loin

ITH metadata AS (
             SELECT 'mars' AS edition, decode(value)::JSON AS geo
             FROM parquet_kv_metadata(getvariable('mars'))
             WHERE decode(key) = 'geo'
         
             UNION ALL
         
             SELECT 'juin', decode(value)::JSON
             FROM parquet_kv_metadata(getvariable('juin'))
             WHERE decode(key) = 'geo'
         )
         SELECT
             edition,
             geo ->> '$.version' AS version_geoparquet,
             geo ->> '$.columns.geometrie.encoding' AS encodage,
             geo -> '$.columns.geometrie.geometry_types' AS types_geometriques,
             geo -> '$.columns.geometrie.crs' AS crs
         FROM metadata;
┌─────────┬────────────────────┬──────────────┬────────────────────┬──────┐
│ edition │ version_geoparquet │   encodage   │ types_geometriques │ crs  │
│ varchar │      varchar       │   varchar    │        json        │ json │
├─────────┼────────────────────┼──────────────┼────────────────────┼──────┤
│ mars    │ 1.1.0              │ multipolygon │ ["MultiPolygon Z"] │ NULL │
│ juin    │ 1.1.0              │ WKB          │ ["MultiPolygon Z"] │ NULL │
└─────────┴────────────────────┴──────────────┴────────────────────┴──────┘

Avec un crs qui vaut null on s'attend à des coordonnées en OGC:CRS84 c'est à dire du longitude/latitude (c'est ce que définit la spec geoparquet 1.1).
Une autre requête permet de savoir que les deux fichiers ont été créé avec GDAL 3.11.3, using parquet-cpp-arrow version 21.0.0

Lecture de la colonne géométrique des fichiers

Pour la version de mars il faut convertir la structure de liste de la géométrie en utilisant duck_geoarrow

INSTALL duck_geoarrow FROM community;
LOAD duck_geoarrow;
SELECT ST_AsText(
    ST_GeomFromGeoArrow('multipolygon', geometrie)
)
FROM batiment_mars
LIMIT 1;

Tandis que la version de juin permet une interrogation directe via spatial

INSTALL spatial;
LOAD spatial;

SELECT ST_AsText(geometrie)
FROM batiment_juin
LIMIT 1;

Interrogation spatiale directe des fichiers

Avec la version de mars

INSTALL spatial; LOAD spatial; INSTALL httpfs; LOAD httpfs;
INSTALL duck_geoarrow FROM community;
LOAD duck_geoarrow;
-- Ne lit que les groupes de lignes couvrant l'emprise, pas les 8 Gio du fichier.
-- Utilisation de la colonne geometrie_bbox pour accélérer la sélection
SELECT *
FROM read_parquet('https://data.geopf.fr/chunk/telechargement/download/BDTOPO_PQT/BDTOPO_3-5_TOUSTHEMES_GEOPARQUET_WGS84G_FRA_2026-03-15/batiment.parquet')
WHERE geometrie_bbox.xmin <= 3.4
  AND geometrie_bbox.xmax >= 3.2
  AND geometrie_bbox.ymin <= 47.4
  AND geometrie_bbox.ymax >= 47.3
  AND ST_Intersects(
      ST_GeomFromGeoArrow('multipolygon', geometrie),
      ST_MakeEnvelope(3.2, 47.3, 3.4, 47.4)
  );

Avec la version de juin

INSTALL spatial; LOAD spatial; INSTALL httpfs; LOAD httpfs;
-- Ne lit que les groupes de lignes couvrant l'emprise, pas les 8 Gio du fichier.
-- Utilisation de la colonne geometrie_bbox pour accélérer la sélection
SELECT *
FROM read_parquet('https://data.geopf.fr/chunk/telechargement/download/BDTOPO_PQT/BDTOPO_TOUSTHEMES_3-5_GEOPARQUET_WGS84G_FRA_2026-06-15/batiment.parquet')
WHERE geometrie_bbox.xmin <= 3.4
  AND geometrie_bbox.xmax >= 3.2
  AND geometrie_bbox.ymin <= 47.4
  AND geometrie_bbox.ymax >= 47.3
  AND ST_Intersects(
      geometrie,
      ST_MakeEnvelope(3.2, 47.3, 3.4, 47.4)
  );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment