This commit is contained in:
Andras Schmelczer 2026-05-28 21:48:35 +01:00
parent 39ef5c6646
commit c995f12f8b
78 changed files with 4830 additions and 1619 deletions

View file

@ -40,7 +40,13 @@ pub struct ActualListingsResponse {
pub truncated: bool,
}
const KEEP_UNKNOWN_LISTING_FILTER_FEATURES: &[&str] = &["Total floor area (sqm)"];
const KEEP_UNKNOWN_LISTING_FILTER_FEATURES: &[&str] = &[
"Total floor area (sqm)",
"Leasehold/Freehold",
"Number of bedrooms & living rooms",
"Property type",
];
const LISTING_BOUNDS_EPSILON_DEGREES: f64 = 0.00001;
pub async fn get_actual_listings(
State(shared): State<Arc<SharedState>>,
@ -98,14 +104,29 @@ pub async fn get_actual_listings(
};
let row_indices = actual_listings.grid.query(south, west, north, east);
let total_in_bounds = row_indices.len();
// Build (row, sort_key) pairs so we can sort by index without
// materializing the full ActualListing for every matching row.
let mut matching_rows: Vec<usize> = row_indices
let total_grid_candidates = row_indices.len();
let candidate_rows: Vec<usize> = row_indices
.iter()
.filter_map(|&row_idx| {
let row = row_idx as usize;
row_is_within_bounds(
actual_listings.lat[row],
actual_listings.lon[row],
south,
west,
north,
east,
)
.then_some(row)
})
.collect();
let total_in_bounds = candidate_rows.len();
// Build (row, sort_key) pairs so we can sort by index without
// materializing the full ActualListing for every matching row.
let mut matching_rows: Vec<usize> = candidate_rows
.into_iter()
.filter(|&row| {
if has_listing_filters
&& !row_passes_listing_filters(
row,
@ -116,7 +137,7 @@ pub async fn get_actual_listings(
&keep_unknown_listing_filter_idxs,
)
{
return None;
return false;
}
if has_poi_filters
&& !row_passes_listing_poi_filters(
@ -126,7 +147,7 @@ pub async fn get_actual_listings(
poi_num_features,
)
{
return None;
return false;
}
if has_travel_filters
&& !row_passes_travel_filters(
@ -135,9 +156,9 @@ pub async fn get_actual_listings(
&travel_data,
)
{
return None;
return false;
}
Some(row)
true
})
.collect();
@ -162,6 +183,7 @@ pub async fn get_actual_listings(
results = listings.len(),
total = total_matching,
total_in_bounds,
total_grid_candidates,
offset,
listing_filtered = has_listing_filters,
poi_filtered = has_poi_filters,
@ -214,10 +236,23 @@ fn row_passes_listing_filters(
}
}) && enum_filters.iter().all(|filter| {
let raw = feature_data[base + filter.feat_idx];
raw != NAN_U16 && filter.allowed.contains(&raw)
if raw == NAN_U16 {
keep_unknown_filter_idxs.contains(&filter.feat_idx)
} else {
filter.allowed.contains(&raw)
}
})
}
fn row_is_within_bounds(lat: f32, lon: f32, south: f64, west: f64, north: f64, east: f64) -> bool {
let lat = lat as f64;
let lon = lon as f64;
lat >= south - LISTING_BOUNDS_EPSILON_DEGREES
&& lat <= north + LISTING_BOUNDS_EPSILON_DEGREES
&& lon >= west - LISTING_BOUNDS_EPSILON_DEGREES
&& lon <= east + LISTING_BOUNDS_EPSILON_DEGREES
}
fn row_passes_listing_poi_filters(
row: usize,
filters: &[ParsedPoiFilter],
@ -245,6 +280,20 @@ fn row_passes_listing_poi_filters(
mod tests {
use super::*;
#[test]
fn listing_bounds_check_keeps_only_exact_viewport_rows() {
assert!(row_is_within_bounds(51.5, -0.1, 51.4, -0.2, 51.6, 0.0));
// Bounds are inclusive so edge points are retained.
assert!(row_is_within_bounds(51.4, -0.2, 51.4, -0.2, 51.6, 0.0));
assert!(row_is_within_bounds(51.6, 0.0, 51.4, -0.2, 51.6, 0.0));
assert!(!row_is_within_bounds(51.399, -0.1, 51.4, -0.2, 51.6, 0.0));
assert!(!row_is_within_bounds(51.601, -0.1, 51.4, -0.2, 51.6, 0.0));
assert!(!row_is_within_bounds(51.5, -0.201, 51.4, -0.2, 51.6, 0.0));
assert!(!row_is_within_bounds(51.5, 0.001, 51.4, -0.2, 51.6, 0.0));
}
#[test]
fn listing_floor_area_filter_keeps_unknown_values() {
let floor_area_filter = ParsedFilter {
@ -290,6 +339,48 @@ mod tests {
));
}
#[test]
fn listing_enum_filter_keeps_allowlisted_unknown_values() {
let enum_filter = ParsedEnumFilter {
feat_idx: 0,
allowed: [1u16].into_iter().collect(),
};
let keep_unknown_filter_idxs: FxHashSet<usize> = [0usize].into_iter().collect();
assert!(row_passes_listing_filters(
0,
&[],
&[enum_filter],
&[NAN_U16],
1,
&keep_unknown_filter_idxs
));
assert!(!row_passes_listing_filters(
0,
&[],
&[ParsedEnumFilter {
feat_idx: 0,
allowed: [1u16].into_iter().collect(),
}],
&[2],
1,
&keep_unknown_filter_idxs
));
assert!(row_passes_listing_filters(
0,
&[],
&[ParsedEnumFilter {
feat_idx: 0,
allowed: [1u16].into_iter().collect(),
}],
&[1],
1,
&keep_unknown_filter_idxs
));
}
#[test]
fn listing_poi_filter_uses_listing_metric_matrix() {
let filter = ParsedPoiFilter {