This commit is contained in:
Andras Schmelczer 2026-05-12 22:13:07 +01:00
parent 11711c57e6
commit 81a16f543c
21 changed files with 29072 additions and 1913 deletions

View file

@ -6,7 +6,7 @@ use axum::response::{IntoResponse, Json};
use axum::Extension;
use metrics::histogram;
use rayon::prelude::*;
use rustc_hash::FxHashMap;
use rustc_hash::{FxHashMap, FxHashSet};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use tracing::info;
@ -32,6 +32,7 @@ type ChunkResult = (
FxHashMap<u64, Aggregator>,
FxHashMap<u64, PoiAggregator>,
Vec<FxHashMap<u64, TravelTimeAgg>>,
FxHashSet<u64>,
);
/// Maximum center-to-vertex distance in degrees per H3 resolution.
@ -82,6 +83,7 @@ pub struct HexagonParams {
fn build_feature_maps(
groups: &FxHashMap<u64, Aggregator>,
poi_groups: &FxHashMap<u64, PoiAggregator>,
selectable_cells: &FxHashSet<u64>,
min_keys: &[String],
max_keys: &[String],
avg_keys: &[String],
@ -214,6 +216,36 @@ fn build_feature_maps(
features.push(map);
}
for &cell_id in selectable_cells {
if groups.contains_key(&cell_id) {
continue;
}
let Some(cell) = h3o::CellIndex::try_from(cell_id).ok() else {
continue;
};
let center: h3o::LatLng = cell.into();
let lat = center.lat();
let lng = center.lng();
if lat < bound_south || lat > bound_north || lng < bound_west || lng > bound_east {
continue;
}
let mut map = Map::new();
map.insert("h3".into(), Value::String(cell.to_string()));
map.insert("count".into(), Value::from(0));
if let (Some(lat_num), Some(lon_num)) = (
serde_json::Number::from_f64(lat),
serde_json::Number::from_f64(lng),
) {
map.insert("lat".into(), Value::Number(lat_num));
map.insert("lon".into(), Value::Number(lon_num));
}
features.push(map);
}
features
}
@ -313,6 +345,7 @@ pub async fn get_hexagons(
let mut groups: FxHashMap<u64, Aggregator> = FxHashMap::default();
let mut poi_groups: FxHashMap<u64, PoiAggregator> = FxHashMap::default();
let mut selectable_cells: FxHashSet<u64> = FxHashSet::default();
let mut travel_aggs: Vec<FxHashMap<u64, TravelTimeAgg>> = (0..travel_entries.len())
.map(|_| FxHashMap::default())
.collect();
@ -338,12 +371,22 @@ pub async fn get_hexagons(
..travel_entries.len())
.map(|_| FxHashMap::default())
.collect();
let mut local_selectable_cells: FxHashSet<u64> = FxHashSet::default();
let mut h3_cache: FxHashMap<u64, u64> = FxHashMap::default();
let mut travel_minutes: Vec<Option<i16>> =
Vec::with_capacity(travel_entries.len());
'row: for &row_idx in chunk {
let row = row_idx as usize;
let cell_id = cell_for_row_cached(
row,
precomputed,
h3_res,
need_parent,
&mut h3_cache,
);
local_selectable_cells.insert(cell_id);
if !row_passes_filters(
row,
&parsed_filters,
@ -384,14 +427,6 @@ pub async fn get_hexagons(
}
}
let cell_id = cell_for_row_cached(
row,
precomputed,
h3_res,
need_parent,
&mut h3_cache,
);
let agg = local_groups
.entry(cell_id)
.or_insert_with(|| Aggregator::new(num_features, enum_dist_config));
@ -424,12 +459,19 @@ pub async fn get_hexagons(
}
}
(local_groups, local_poi_groups, local_travel_aggs)
(
local_groups,
local_poi_groups,
local_travel_aggs,
local_selectable_cells,
)
})
.collect();
// Merge thread-local results into the main accumulators
for (local_groups, local_poi_groups, local_travel) in thread_results {
for (local_groups, local_poi_groups, local_travel, local_selectable_cells) in
thread_results
{
for (cell_id, local_agg) in local_groups {
groups
.entry(cell_id)
@ -450,6 +492,7 @@ pub async fn get_hexagons(
.merge(&local_tt);
}
}
selectable_cells.extend(local_selectable_cells);
}
} else {
// Sequential: use for_each_in_bounds to avoid Vec<u32> allocation
@ -460,6 +503,9 @@ pub async fn get_hexagons(
.grid
.for_each_in_bounds(south, west, north, east, |row_idx| {
let row = row_idx as usize;
let cell_id =
cell_for_row_cached(row, precomputed, h3_res, need_parent, &mut h3_cache);
selectable_cells.insert(cell_id);
if !row_passes_filters(
row,
@ -499,9 +545,6 @@ pub async fn get_hexagons(
}
}
let cell_id =
cell_for_row_cached(row, precomputed, h3_res, need_parent, &mut h3_cache);
let aggregation = groups
.entry(cell_id)
.or_insert_with(|| Aggregator::new(num_features, enum_dist_config));
@ -540,6 +583,7 @@ pub async fn get_hexagons(
let mut features = build_feature_maps(
&groups,
&poi_groups,
&selectable_cells,
min_keys,
max_keys,
avg_keys,
@ -564,6 +608,7 @@ pub async fn get_hexagons(
resolution,
rows = row_count,
parallel,
selectable_cells = selectable_cells.len(),
cells_before_filter = groups.len(),
cells_after_filter = features.len(),
truncated,