Una query geospaziale è una ricerca nel database che filtra e ordina i record per posizione – vicino a un punto, entro un raggio o dentro un’area. Alimenta la richiesta di feature che arriva nel secondo mese di quasi ogni prodotto: trova X nelle vicinanze – caffè, autisti, negozi, altri utenti. Ed è il caso più netto di una classe di query che l’indicizzazione B-tree ordinaria non sa servire: la vicinanza è bidimensionale, e una struttura ordinata su una sola dimensione non riesce a vederla.
Punti chiave
| Domanda | Risposta |
|---|---|
| Il tipo di campo | GeoPoint – una coppia latitudine/longitudine che il database capisce |
| Le query | Near (ordinata per distanza), entro un raggio, entro un rettangolo/poligono |
| L’indice | Di tipo 2dsphere: il globo proiettato su celle indicizzabili |
| Senza indice | Distanza calcolata da ogni riga – una scansione completa con trigonometria |
| La feature canonica | ”Trova X nelle vicinanze”, composta con filtri ordinari |
La query nelle vicinanze, scritta e provata
// JavaScript / Node.js — Back4app JS SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
const here = new Parse.GeoPoint({ latitude: 40.7484, longitude: -73.9857 });
const query = new Parse.Query('Cafe');
query.withinKilometers('location', here, 2); // radius filter, nearest-first
query.equalTo('openNow', true); // geo + ordinary filters compose
query.limit(20);
const cafes = await query.find();
cafes.forEach((c) => {
const km = here.kilometersTo(c.get('location'));
console.log(`${c.get('name')} — ${km.toFixed(2)} km away`);
}); // Flutter / Dart — Back4app Flutter SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
final here = ParseGeoPoint(latitude: 40.7484, longitude: -73.9857);
final query = QueryBuilder<ParseObject>(ParseObject('Cafe'))
..whereWithinKilometers('location', here, 2) // radius filter, nearest-first
..whereEqualTo('openNow', true) // geo + ordinary filters compose
..setLimit(20);
final response = await query.query();
for (final result in response.results ?? []) {
final cafe = result as ParseObject;
final loc = cafe.get<ParseGeoPoint>('location');
print('${cafe.get<String>('name')} at '
'${loc?.latitude}, ${loc?.longitude}');
} // iOS / Swift — Back4app Swift SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
let here = try ParseGeoPoint(latitude: 40.7484, longitude: -73.9857)
let query = Cafe.query(
withinKilometers(key: "location", geoPoint: here, distance: 2),
"openNow" == true // geo + ordinary filters compose
).limit(20)
query.find { result in
if case .success(let cafes) = result {
for cafe in cafes {
print("\(cafe.name ?? "?") — \(String(describing: cafe.location))")
}
}
} // Android / Kotlin — Back4app Android SDK
// "Find cafes within 2 km, nearest first" — the canonical geo query
val here = ParseGeoPoint(40.7484, -73.9857)
val query = ParseQuery.getQuery<ParseObject>("Cafe")
query.whereWithinKilometers("location", here, 2.0) // radius, nearest-first
query.whereEqualTo("openNow", true) // geo + filters compose
query.limit = 20
query.findInBackground { cafes, e ->
if (e == null) cafes.forEach { cafe ->
val loc = cafe.getParseGeoPoint("location")
val km = loc?.distanceInKilometersTo(here)
println("${cafe.getString("name")} — ${"%.2f".format(km)} km away")
}
} La stessa fisica in SQL, tramite PostGIS – e l’indice che la rende praticabile:
-- Un indice spaziale sulla colonna geography:
CREATE INDEX cafe_location_gix ON cafe USING GIST (location);
-- "Caffè entro 2 km, i più vicini prima":
SELECT name, ST_Distance(location, ST_MakePoint(-73.9857, 40.7484)::geography) AS meters
FROM cafe
WHERE ST_DWithin(location, ST_MakePoint(-73.9857, 40.7484)::geography, 2000)
ORDER BY location <-> ST_MakePoint(-73.9857, 40.7484)::geography
LIMIT 20;
-- con l'indice: tocca solo le celle che coprono il cerchio di 2 km
-- senza indice: calcola una distanza per ogni riga della tabella
Come l’indice vede il globo
Un indice di tipo 2dsphere rende indicizzabile la vicinanza proiettando la superficie curva su celle gerarchiche il cui ordine preserva l’adiacenza – punti vicini sul globo finiscono in voci di indice vicine. Una query nel raggio si legge allora come qualunque lookup su indice: individuare le poche celle che coprono il cerchio, scandirne i candidati, verificare le distanze esatte su quella breve lista. La geometria sferica – anziché il calcolo su un piano – mantiene i risultati corretti alle scale reali, a cavallo dell’antimeridiano e verso i poli.
La regola di composizione discende dalla meccanica ordinaria delle query: i vincoli geo si combinano liberamente con filtri di uguaglianza, di intervallo e su Pointer (openNow == true nelle schede qui sopra), e i filtri non geo selettivi nelle query più frequenti possono meritare indici propri.
La paginazione merita una nota a parte, perché i risultati ordinati per distanza rompono l’abitudine dell’offset. Saltare la prima pagina di una query near costringe il motore a riclassificare tutto ciò che è stato saltato, e un punto che si è mosso tra una richiesta e l’altra può rimescolare l’ordine sotto gli occhi dell’utente. I pattern più robusti: allargare il raggio progressivamente per il “carica altro”, oppure paginare su una chiave stabile entro un raggio fisso. L’ordinamento dal più vicino è una classifica su dati vivi – i confini di pagina vanno trattati come indicativi, non come righe di un registro contabile.
Query near vs. within vs. su piano
Quale query geo conviene usare?
| Forma della query | Risponde a | Ordinamento | Uso tipico |
|---|---|---|---|
| Near (vicinanza) | Che cosa è più vicino a qui? | Dal più vicino | Elenchi di “caffè nelle vicinanze”, abbinamento di autisti |
| Entro un raggio | Che cosa c’è entro r km da qui? | Nessuno implicito | Idoneità alla consegna, avvisi |
| Entro un rettangolo | Che cosa c’è in questo rettangolo? | Nessuno | Rendering della porzione di mappa |
| Entro un poligono | Che cosa c’è dentro questa forma? | Nessuno | Quartieri, zone, geofence |
| Su piano (2d) | Lo stesso, su un piano proiettato | Variabile | Mappe di gioco, planimetrie – non la Terra |
La distinzione near/within è logica di prodotto, non pedanteria: near è una classifica (va limitata con un limit e un raggio massimo, altrimenti le città dense restituiscono migliaia di righe), within è un predicato (va abbinato alla geometria della porzione di mappa o del recinto). La riga del piano è la nota a piè di pagina onesta – per coordinate che non stanno su una sfera, gli indici sferici sono lo strumento sbagliato.
Casi d’uso tipici
- “Trova X nelle vicinanze”. Caffè, palestre, bancomat, stazioni di ricarica – l’elenco di vicinanza canonico, limitato nel raggio e ordinato dal più vicino.
- Abbinamento e dispatch. Passeggeri e autisti, consegne e corrieri – query near su GeoPoint aggiornati di frequente.
- Porzioni di mappa. Query entro un rettangolo che alimentano i segnaposto mentre l’utente sposta la mappa – economiche, non ordinate, a misura di viewport.
- Geofencing. Controlli entro un poligono per zone di consegna, aree di servizio e logica attivata dalla posizione.
- Feature social locali. Persone nelle vicinanze ed eventi del fine settimana, composti con filtri di privacy e relazioni basate su Pointer.
Conviene usare query geo o precalcolare le regioni? Matrice decisionale
| Interrogare dal vivo con un indice geo quando… | Precalcolare etichette di regione quando… |
|---|---|
| Raggi e forme variano a ogni richiesta | I confini sono fissi (negozi, zone, quartieri) |
| I punti si muovono spesso (autisti, utenti) | L’appartenenza cambia di rado |
| L’ordinamento dal più vicino conta | Si filtra solo per uguaglianza di regione |
| Le forme sono davvero spaziali | Una semplice colonna region risponde a tutto |
| È disponibile un indice spaziale | Si raggruppa, non si misura |
La via d’uscita conta: quando ogni query si riduce a “nella zona A?”, una semplice colonna di testo indicizzata batte il macchinario spaziale – più economica, più semplice e coperta dai B-tree ordinari. L’indicizzazione spaziale si guadagna il posto esattamente quando la geometria è dinamica: centri arbitrari, punti in movimento, distanze reali.
Limiti e trade-off
- Gli indici geo sono specialisti. Servono solo i predicati spaziali; gli altri filtri hanno ancora bisogno di indici propri, e la manutenzione dell’indice costa scritture – la stessa tassa, a tariffa spaziale.
- Le query near senza limiti sono trappole. Ordinare dal più vicino su una città densa senza raggio massimo né limit classifica metà tabella. La ricerca va sempre delimitata.
- I punti in movimento scrivono di continuo. Posizioni degli autisti dal vivo significano aggiornamenti dei GeoPoint ad alta frequenza, ognuno dei quali mantiene l’indice – conviene raggruppare o limitare gli aggiornamenti di posizione dove il prodotto lo consente.
- Un punto per riga è il modello di base. Un negozio con cinque filiali è cinque record; forme più ricche dei punti (percorsi, aree di copertura) spingono verso veri database spaziali.
- La precisione ha un limite inferiore. L’errore sfera/ellissoide è trascurabile, ma il rumore del GPS è di metri nel migliore dei casi – la logica di prodotto (zone, soglie) va progettata per tollerarlo.
Le query geospaziali su Back4app
Back4app è una piattaforma open-source di Backend as a Service (BaaS) che combina database gestito, API REST e GraphQL generate automaticamente, autenticazione, archiviazione di file e funzioni serverless con Cloud Code. GeoPoint è un tipo di colonna nativo dell’archivio gestito basato su MongoDB, e gli operatori di vicinanza, raggio e rettangolo – withinKilometers, near, withinGeoBox – arrivano nelle API generate automaticamente e in ogni SDK, esattamente come li usano le schede di codice qui sopra. Gli indici geo si gestiscono insieme al resto della strategia di indicizzazione nella dashboard, il che trasforma il consueto progetto infrastrutturale “trova X nelle vicinanze” in una decisione di schema e tre righe di query.
Domande frequenti
Che cos'è una query geospaziale?
Una ricerca nel database il cui filtro è spaziale anziché per valore: restituisce i record vicini a un punto, entro un raggio o dentro un rettangolo o un poligono, di solito ordinati dal più vicino. Il database memorizza le coordinate come tipo di prima classe – un GeoPoint di latitudine e longitudine – e un indice spaziale risponde alla domanda senza calcolare la distanza da ogni riga.
Che cos'è un campo GeoPoint?
Un tipo di colonna che contiene una coppia latitudine/longitudine, con latitudine da -90 a 90 e longitudine da -180 a 180. Poiché il database sa che il campo è geografico – non solo due numeri in virgola mobile – può indicizzarlo spazialmente ed esporre operatori di distanza: entro tanti chilometri o miglia da qui, dentro questa bounding box, contenuto in questo poligono, ordinato per vicinanza.
Come funziona un indice geo di tipo 2dsphere?
Proietta la superficie curva della Terra su celle ordinate e indicizzabili – celle grossolane suddivise in celle più fini – così che la vicinanza sul globo diventi adiacenza nell'indice. Una query near ispeziona la manciata di celle che coprono l'area di ricerca invece di ogni riga, e la geometria sferica mantiene corrette le distanze, anche a cavallo dell'antimeridiano e vicino ai poli.
Perché una ricerca nelle vicinanze è lenta senza un indice geo?
Perché senza indice il motore deve calcolare la distanza dal punto dato a ogni riga, poi ordinare il tutto – una scansione completa travestita da trigonometria, ripetuta a ogni richiesta. Un indice geo inverte il lavoro: va dritto alle celle che coprono il raggio di ricerca e tocca solo i candidati plausibili. Il divario si allarga con la dimensione della tabella, esattamente come per qualunque indice mancante, solo con un costo per riga più alto.
Qual è la differenza tra una query near e una query within?
Una query near risponde a "che cosa è più vicino?" – ordina per distanza da un punto e di norma limita i risultati con un limit o un raggio massimo. Una query within risponde a "che cosa c'è dentro?" – filtra per contenimento in un raggio, un rettangolo o un poligono e non implica alcun ordinamento. Gli elenchi di caffè più vicini sono query near; "i negozi in questa porzione di mappa" e i controlli di geofencing sono query within.
Si possono combinare filtri geo con filtri di query ordinari?
Sì, e le feature reali lo fanno quasi sempre: entro 2 km e aperto adesso e con più di quattro stelle. Il vincolo geo si compone con filtri di uguaglianza, di intervallo e su Pointer in un'unica query. Attenzione all'interazione con l'indicizzazione – l'indice spaziale restringe prima per posizione, e i filtri ordinari molto selettivi possono meritare un indice proprio perché la query combinata resti economica.
Quanto sono precise le query nel raggio su grandi distanze?
I calcoli sferici modellano la Terra come una sfera, che si discosta dall'ellissoide reale al massimo di circa un terzo di punto percentuale – metri su distanze urbane, e di norma irrilevante per la logica di prodotto. Ciò che pesa prima è la precisione dei punti memorizzati: le coordinate del GPS di un telefono portano metri di errore all'aperto e di più al chiuso. Per "trovare X nelle vicinanze" entrambi gli effetti sono rumore.