C’est quelques chose que l’on commence à nous demander de plus en plus: avoir des stats sur la consultation des images.
Il y a plein de stats qui peuvent être produites, tellement qu’en faisant certaines stats il y aura toujours une demande autre, et difficile de répondre à tout sans tourner à l’usine à gaz !
Quelques exemples :
- combien d’images ont été consultées sur telle zone géographique, telle commune, département, région
- des stats par compte contributeur : “mes photos sont elles consultées”
- sur quel site affiche-t-on des photos Panoramax
etc !
Une solution que j’ai testé consisterait à extraire depuis les logs des serveurs, les informations essentielles telles que :
- l’id de la photo consultée
- date/heure de consultation
- le type de requête (une image complète, basse-def, imagette ou bien une tuile d’image 360)
- le volume transféré (pour faire des stats sur le trafic généré)
- le site depuis lequel elle a été affichée (extrait du referer HTTP)
En croisant cela avec les métadonnées sur les images on peut compléter par:
- la coordonnée géographique de la photo
- le compte contributeur
- l’instance sur laquelle elle est publiée
En croisant aussi avec les géométrie des communes on peut rajouter:
- le nom et code INSEE de la commune
- le code du département et de la région
Nous publions déjà les métadonnées sur les images sous forme de dumps postgresql et aussi de fichiers au format geoparquet qui peuvent se requêter à distance ou localement si on en fait une copie.
J’ai donc tenté de produire des logs légers, eux aussi au format geoparquet.
J’ai déposé ça sur https://data.cquest.org/temp/panoramax/panostats/
Voici un exemple de stat qu’on peut sortir avec duckdb:
INSTALL spatial; LOAD spatial;
CREATE VIEW panostat AS SELECT * FROM 'https://data.cquest.org/temp/panoramax/panostats/osmfr/osm37.parquet';
Ces deux lignes chargent les extensions spatiales et crée une vue pour se simplifier les requêtes qui sont ici faites sur les logs de l’instance OSM-FR.
SELECT count(*), min(dt), max(dt)
FROM panostat;
┌──────────────┬─────────────────────┬─────────────────────┐
│ count_star() │ min(dt) │ max(dt) │
│ int64 │ timestamp │ timestamp │
├──────────────┼─────────────────────┼─────────────────────┤
│ 4761139 │ 2025-12-25 00:00:10 │ 2026-02-13 23:57:31 │
└──────────────┴─────────────────────┴─────────────────────┘
Un peu moins de 5 millions de requêtes depuis Noël, regardons de qu’il y a comme informations :
DESCRIBE panostat;
┌───────────────────────────┬─────────────┬─────────┬─────────┬─────────┬─────────┐
│ column_name │ column_type │ null │ key │ default │ extra │
│ varchar │ varchar │ varchar │ varchar │ varchar │ varchar │
├───────────────────────────┼─────────────┼─────────┼─────────┼─────────┼─────────┤
│ picid │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ typ │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ referer │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ dt │ TIMESTAMP │ YES │ NULL │ NULL │ NULL │
│ code │ BIGINT │ YES │ NULL │ NULL │ NULL │
│ bytes │ BIGINT │ YES │ NULL │ NULL │ NULL │
│ geometry │ GEOMETRY │ YES │ NULL │ NULL │ NULL │
│ account │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ instance │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ code_insee │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ code_insee_du_departement │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ code_insee_de_la_region │ VARCHAR │ YES │ NULL │ NULL │ NULL │
│ nom_officiel │ VARCHAR │ YES │ NULL │ NULL │ NULL │
├───────────────────────────┴─────────────┴─────────┴─────────┴─────────┴─────────┤
│ 13 rows 6 columns │
└─────────────────────────────────────────────────────────────────────────────────┘
- picid : l’id de la photo
- typ : le type de consultation (fu = pleine résolution, sd = basse-définition, th = imagette, ti = tuile 360°)
- referer : le domaine du referer, c’est à dire le site depuis où elle a été consultée
- dt : date/heure de consultation (UTC)
- code : code HTTP de réponse (200 = OK, 304 = non modifiée, etc)
- bytes : volume en octets
- geometry : position géographique de la photo
- account : pseudo du contributeur
- instance : instance où la photo est publiée
- code_insee : code commune, département et région
- nom_officiel : nom de la commune
Sortons le volume transféré sur les 10 derniers jours :
SELECT date(dt), round(sum(bytes)/2^30,1) as gb
FROM panostat
GROUP BY 1
ORDER BY 1 desc
LIMIT 10;
┌──────────────────┬────────┐
│ CAST(dt AS DATE) │ gb │
│ date │ double │
├──────────────────┼────────┤
│ 2026-02-13 │ 268.7 │
│ 2026-02-12 │ 134.0 │
│ 2026-02-11 │ 15.1 │
│ 2026-02-10 │ 23.2 │
│ 2026-02-09 │ 27.1 │
│ 2026-02-08 │ 89.8 │
│ 2026-02-07 │ 12.4 │
│ 2026-02-06 │ 18.7 │
│ 2026-02-05 │ 390.8 │
│ 2026-02-04 │ 146.0 │
├──────────────────┴────────┤
│ 10 rows 2 columns │
└───────────────────────────┘
Les communes où il y a eu le plus d’images consultées ?
SELECT nom_officiel, code_insee_du_departement, count(*) as nb
FROM panostat
GROUP BY 1,2
ORDER BY nb desc
LIMIT 10;
┌────────────────┬───────────────────────────┬─────────┐
│ nom_officiel │ code_insee_du_departement │ nb │
│ varchar │ varchar │ int64 │
├────────────────┼───────────────────────────┼─────────┤
│ NULL │ NULL │ 1829095 │
│ Paris │ 75 │ 262260 │
│ Lyon │ 69 │ 198212 │
│ Nantes │ 44 │ 120306 │
│ Pont-à-Mousson │ 54 │ 95344 │
│ Grenoble │ 38 │ 90585 │
│ Bléruais │ 35 │ 81554 │
│ Caen │ 14 │ 68746 │
│ Rouen │ 76 │ 56132 │
│ Villeurbanne │ 69 │ 53203 │
├────────────────┴───────────────────────────┴─────────┤
│ 10 rows 3 columns │
└──────────────────────────────────────────────────────┘
Le NULL correspond à des images hors de France.
Les possibilités sont quasi infinies… !
Pour donner une idée de la vitesse, voici un lien vers un shell duckdb qui tourne directement dans votre navigateur (avec wasm) et exécute la dernière requête: DuckDB Shell