Data Engineering
Evaluation de sentier de rendonnée
Cette requête PostgreSQL analyse des sentiers de randonnée en évaluant leurs caractéristiques géographiques (élévation, points de vue, météo). Elle découpe les sentiers en segments d'un kilomètre et calcule un score scénique pour chaque sentier.
WITH trail_segments AS ( -- Break trails into 1km segments for detailed analysis SELECT t.trail_id, t.trail_name, ST_LineSubstring( t.geometry, generate_series(0, ceil(ST_Length(t.geometry::geography)/1000)::integer)::float/ceil(ST_Length(t.geometry::geography)/1000), LEAST(((generate_series(0, ceil(ST_Length(t.geometry::geography)/1000)::integer) + 1)::float/ceil(ST_Length(t.geometry::geography)/1000)), 1) ) AS segment_geom FROM trails t ), elevation_stats AS ( -- Calculate elevation statistics for each segment SELECT ts.trail_id, ts.segment_geom, ST_Summarystats(ST_Clip(dem.rast, ts.segment_geom)) AS elev_stats FROM trail_segments ts CROSS JOIN LATERAL ( SELECT rast FROM elevation_dem WHERE ST_Intersects(rast, ts.segment_geom) ) dem ), scenic_points AS ( -- Find scenic viewpoints along trails SELECT ts.trail_id, ts.trail_name, COUNT(v.viewpoint_id) AS viewpoint_count, array_agg(DISTINCT v.viewpoint_type) AS viewpoint_types, ST_CollectionExtract( ST_Collect(ST_Buffer(v.geom, 100)::geometry), 3 ) AS viewshed_area FROM trail_segments ts JOIN viewpoints v ON ST_DWithin(ts.segment_geom::geography, v.geom::geography, 200) GROUP BY ts.trail_id, ts.trail_name ), weather_exposure AS ( -- Analyze weather exposure risk using terrain and historical data SELECT ts.trail_id, sum(CASE WHEN ST_Value(w.wind_rast, ST_Centroid(ts.segment_geom)) > 30 AND e.elev_stats->>'max' > 2000 THEN 1 ELSE 0 END) AS high_wind_exposure_segments, avg(ST_Value(w.precipitation_rast, ST_Centroid(ts.segment_geom))) AS avg_annual_precipitation FROM trail_segments ts JOIN elevation_stats e ON ts.trail_id = e.trail_id CROSS JOIN LATERAL ( SELECT rast AS wind_rast, rast AS precipitation_rast FROM weather_data WHERE ST_Intersects(rast, ts.segment_geom) ) w GROUP BY ts.trail_id ) -- Final query combining all analyses SELECT t.trail_name, t.difficulty_level, ST_Length(t.geometry::geography)/1000 AS length_km, sp.viewpoint_count, sp.viewpoint_types, ST_Area(sp.viewshed_area::geography)/1000000 AS viewshed_area_km2, we.high_wind_exposure_segments, we.avg_annual_precipitation, CASE WHEN we.high_wind_exposure_segments > 3 THEN 'High wind risk' WHEN we.avg_annual_precipitation > 1500 THEN 'High precipitation risk' ELSE 'Normal conditions' END AS weather_risk_category, -- Calculate a "scenic rating" based on various factors ( (sp.viewpoint_count * 2) + (ST_Area(sp.viewshed_area::geography)/1000000) + (CASE WHEN e.elev_stats->>'max' > 2500 THEN 5 ELSE 0 END) )::numeric(10,2) AS scenic_rating FROM trails t JOIN scenic_points sp ON t.trail_id = sp.trail_id JOIN weather_exposure we ON t.trail_id = we.trail_id JOIN elevation_stats e ON t.trail_id = e.trail_id WHERE -- Filter for trails that meet certain criteria ST_Length(t.geometry::geography) > 5000 -- Longer than 5km AND EXISTS ( SELECT 1 FROM parking_areas p WHERE ST_DWithin( ST_StartPoint(t.geometry)::geography, p.geom::geography, 1000 ) ) ORDER BY scenic_rating DESC, length_km;
Matching et comparaison d'entitées graphique
Le script compare les zones géographiques de deux ensembles de polygones en calculant la différence entre la somme des surfaces de ces polygones, en fonction de types spécifiques, et les insère dans une table de comparaison.
WITH route_sections AS ( -- Break urban routes into 500m sections SELECT r.route_id, r.route_name, ST_LineSubstring( r.geom, generate_series(0, ceil(ST_Length(r.geom::geography)/500)::integer)::float/ceil(ST_Length(r.geom::geography)/500), LEAST(((generate_series(0, ceil(ST_Length(r.geom::geography)/500)::integer) + 1)::float/ceil(ST_Length(r.geom::geography)/500)), 1) ) AS section_geom FROM urban_routes r ), traffic_density AS ( -- Calculate traffic patterns for each section SELECT rs.route_id, rs.section_geom, ST_Summarystats(ST_Clip(traffic.rast, rs.section_geom)) AS traffic_stats FROM route_sections rs CROSS JOIN LATERAL ( SELECT rast FROM traffic_density_map WHERE ST_Intersects(rast, rs.section_geom) ) traffic ), poi_clusters AS ( -- Find points of interest along routes SELECT rs.route_id, rs.route_name, COUNT(p.poi_id) AS poi_count, array_agg(DISTINCT p.poi_category) AS poi_types, ST_CollectionExtract( ST_Collect(ST_Buffer(p.geom, 50)::geometry), 3 ) AS service_area FROM route_sections rs JOIN points_of_interest p ON ST_DWithin(rs.section_geom::geography, p.geom::geography, 100) GROUP BY rs.route_id, rs.route_name ), population_density AS ( -- Analyze population density along routes SELECT rs.route_id, sum(CASE WHEN ST_Value(pd.density_rast, ST_Centroid(rs.section_geom)) > 5000 AND t.traffic_stats->>'max' > 1000 THEN 1 ELSE 0 END) AS high_density_sections, avg(ST_Value(pd.density_rast, ST_Centroid(rs.section_geom))) AS avg_population_density FROM route_sections rs JOIN traffic_density t ON rs.route_id = t.route_id CROSS JOIN LATERAL ( SELECT rast AS density_rast FROM population_data WHERE ST_Intersects(rast, rs.section_geom) ) pd GROUP BY rs.route_id ) SELECT r.route_name, r.transport_type, ST_Length(r.geom::geography)/1000 AS length_km, pc.poi_count, pc.poi_types, ST_Area(pc.service_area::geography)/1000000 AS service_area_km2, pd.high_density_sections, pd.avg_population_density, CASE WHEN pd.high_density_sections > 5 THEN 'High congestion risk' WHEN pd.avg_population_density > 8000 THEN 'High usage area' ELSE 'Normal capacity' END AS density_category, ( (pc.poi_count * 1.5) + (ST_Area(pc.service_area::geography)/1000000) + (CASE WHEN t.traffic_stats->>'max' > 1500 THEN 3 ELSE 0 END) )::numeric(10,2) AS route_importance_score FROM urban_routes r JOIN poi_clusters pc ON r.route_id = pc.route_id JOIN population_density pd ON r.route_id = pd.route_id JOIN traffic_density t ON r.route_id = t.route_id WHERE ST_Length(r.geom::geography) > 2000 -- Longer than 2km AND EXISTS ( SELECT 1 FROM transport_hubs h WHERE ST_DWithin( ST_StartPoint(r.geom)::geography, h.geom::geography, 500 ) ) ORDER BY route_importance_score DESC, length_km;