From 69ce4c2c256b172b9fd772881a2d28e4c80dce2a Mon Sep 17 00:00:00 2001 From: Till JS Date: Sat, 11 Apr 2026 17:54:57 +0200 Subject: [PATCH] feat(geocoding): fall back to Pelias /search when /autocomplete is empty MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Pelias /autocomplete deliberately excludes the address layer as a performance optimization, so queries like "Marktstätte Konstanz" (street + locality) return 0 venue matches even though they're clearly in the index. /search covers all layers including addresses and streets. Query /autocomplete first (fast, fuzzy, great for venue names), and if it returns nothing, try /search. Best of both worlds: quick matches for "Konzil Restaurant" plus reliable matches for street addresses. Co-Authored-By: Claude Opus 4.6 (1M context) --- services/mana-geocoding/src/routes/geocode.ts | 30 +++++++++++++++---- 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/services/mana-geocoding/src/routes/geocode.ts b/services/mana-geocoding/src/routes/geocode.ts index bb881e96a..8777f3ced 100644 --- a/services/mana-geocoding/src/routes/geocode.ts +++ b/services/mana-geocoding/src/routes/geocode.ts @@ -77,15 +77,33 @@ export function createGeocodeRoutes(config: Config) { params.set('focus.point.lon', focusLon); } - const response = await fetch(`${config.pelias.apiUrl}/autocomplete?${params}`); - if (!response.ok) { - console.error(`Pelias autocomplete error: ${response.status} ${response.statusText}`); - return c.json({ results: [], error: 'geocoding_unavailable' }, 502); + // Query Pelias /autocomplete first (fast, fuzzy, good for venue names). + // Autocomplete intentionally excludes the address layer as a perf + // optimization, so if it returns nothing we fall back to /search which + // covers streets/addresses too. This gives us the best of both worlds: + // quick venue matches for names like "Konzil Restaurant" AND reliable + // address matches for queries like "Marktstätte Konstanz". + let features: PeliasFeature[] = []; + const autocompleteRes = await fetch(`${config.pelias.apiUrl}/autocomplete?${params}`); + if (autocompleteRes.ok) { + const data = (await autocompleteRes.json()) as PeliasResponse; + features = data.features; } - const data = (await response.json()) as PeliasResponse; - const results = data.features.map(normalizePeliasFeature); + if (features.length === 0) { + const searchRes = await fetch(`${config.pelias.apiUrl}/search?${params}`); + if (searchRes.ok) { + const data = (await searchRes.json()) as PeliasResponse; + features = data.features; + } else if (!autocompleteRes.ok) { + console.error( + `Pelias error: autocomplete=${autocompleteRes.status} search=${searchRes.status}` + ); + return c.json({ results: [], error: 'geocoding_unavailable' }, 502); + } + } + const results = features.map(normalizePeliasFeature); searchCache.set(cacheKey, results); return c.json({ results }); });