The smokesignal.events web application

feature: index geo locations

+36
+36
src/search_index.rs
··· 22 22 Some(cid.to_string()) 23 23 } 24 24 25 + /// Extract geo coordinates from a LocationOrRef if it's an InlineGeo variant. 26 + /// Returns None if the location is not a geo type or has invalid coordinates. 27 + fn extract_geo_point(location: &LocationOrRef) -> Option<GeoPoint> { 28 + if let LocationOrRef::InlineGeo(typed_geo) = location { 29 + let geo = &typed_geo.inner; 30 + let lat = geo.latitude.parse::<f64>().ok()?; 31 + let lon = geo.longitude.parse::<f64>().ok()?; 32 + // Validate coordinate ranges 33 + if (-90.0..=90.0).contains(&lat) && (-180.0..=180.0).contains(&lon) { 34 + Some(GeoPoint { lat, lon }) 35 + } else { 36 + None 37 + } 38 + } else { 39 + None 40 + } 41 + } 42 + 25 43 const INDEX_NAME: &str = "smokesignal-events"; 26 44 45 + /// A geographic point for OpenSearch geo_point field. 46 + #[derive(Debug, Serialize, Deserialize, Clone)] 47 + pub struct GeoPoint { 48 + pub lat: f64, 49 + pub lon: f64, 50 + } 51 + 27 52 #[derive(Debug, Serialize, Deserialize)] 28 53 pub struct IndexedEvent { 29 54 pub aturi: String, ··· 34 59 pub tags: Vec<String>, 35 60 #[serde(default)] 36 61 pub location_cids: Vec<String>, 62 + #[serde(default)] 63 + pub locations_geo: Vec<GeoPoint>, 37 64 pub start_time: Option<String>, 38 65 pub end_time: Option<String>, 39 66 pub created_at: String, ··· 280 307 "description": { "type": "text" }, 281 308 "tags": { "type": "keyword" }, 282 309 "location_cids": { "type": "keyword" }, 310 + "locations_geo": { "type": "geo_point" }, 283 311 "start_time": { "type": "date" }, 284 312 "end_time": { "type": "date" }, 285 313 "created_at": { "type": "date" }, ··· 337 365 .filter_map(generate_location_cid) 338 366 .collect(); 339 367 368 + // Extract geo coordinates 369 + let locations_geo: Vec<GeoPoint> = event_record 370 + .locations 371 + .iter() 372 + .filter_map(extract_geo_point) 373 + .collect(); 374 + 340 375 let mut doc = json!({ 341 376 "aturi": event.aturi, 342 377 "did": event.did, ··· 345 380 "description": event_record.description, 346 381 "tags": tags, 347 382 "location_cids": location_cids, 383 + "locations_geo": locations_geo, 348 384 "created_at": json!(event_record.created_at), 349 385 "updated_at": json!(chrono::Utc::now()) 350 386 });