Problema prossimo più vicino in Postgis 2.0 usando l'indice GIST (<-> funzione)


25

Sto cercando di utilizzare Postgis 2.0 nuova funzione <-> (Geometry Distance Centroid) per calcolare, per ogni riga della mia tabella (cosn1), la distanza dal poligono più vicino della stessa classe.

Stavo cercando di usare il seguente codice:

WITH index_query AS (
  SELECT g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, g1.the_geom <-> g2.the_geom) 
SELECT DISTINCT ON (ref_gid) ref_gid, ENN 
    FROM index_query
ORDER BY ref_gid, ENN;

Ma poi realizzo l'avvertimento:

Nota: L'indice entra in funzione solo se una delle geometrie è una costante (non in una sottoquery / cte). es. 'SRID = 3005; POINT (1011102 450541)' :: geometria anziché a.geom

Ciò significa che l'indice non verrà utilizzato affatto e la query impiegherà quasi lo stesso tempo di prima dell'uso:

SELECT DISTINCT ON(g1.gid)  g1.gid As ref_gid, ST_Distance(g1.the_geom,g2.the_geom) As ENN    
    FROM "cosn1" As g1, "cosn1" As g2   
    WHERE g1.gid <> g2.gid AND g1.class = g2.class
    ORDER BY g1.gid, ST_Distance(g1.the_geom,g2.the_geom)

Qualcuno può indicarmi una soluzione alternativa che mi consente di migliorare le prestazioni della mia query?

Grazie mille.


Non avendo ancora ricevuto risposta, potresti chiederlo nella mailing list di PostGIS.
GIS-Jonathan,

L'ho già fatto, ma anche senza alcuna risposta.
Alexandre Neto,

3
Puoi usare g1.gid> g2.gid nella clausola where, che ridurrà il numero di calcoli di distanza che devi fare. Sfortunatamente, fino a quando l'operatore <-> lavora senza costanti, non vedremo molti miglioramenti della velocità in questo tipo di query.
John Powell,

John, devo mantenere tutte le gid, anche quelle che si ripetono perché devo aggiornare l'EEN per ognuno dei poligoni nella mia tabella "cosn1". Ma quello che hai detto mi ha dato un'idea. Potrei fare come dici tu usando g1.gid> g2.gis per ridurre i calcoli della distanza, ma mantenendo g1.gid e g2.gid nel risultato. Successivamente, potrei unirne due sottoquery (una con g1.gis come gid e l'altra con g2.gid). Grazie
Alexandre Neto,

Ho scoperto che una possibile soluzione per aggirare il problema costante sarebbe utilizzare <-> all'interno di una funzione SQL, usando the_geom come parametro. Ho fatto alcuni test, e in alcuni casi è molto più veloce (). Ma nel mio caso, poiché le distanze sono all'interno della stessa tabella, molti calcoli di distanza vengono ripetuti durante il processo, rendendolo più lento rispetto all'utilizzo della query diretta.
Alexandre Neto,

Risposte:


2

Ronzio facendo alcuni test sulla mia macchina sembrava che questo operatore <-> non funzionasse correttamente. Non sono sicuro che si tratti di un bug ma ha segnalato una distanza zero su geometrie non sovrapposte. Intrigante no?

E le ottimizzazioni delle query SQL tradizionali giuste? Poiché quei risultati imprevisti con l'operatore <-> lo sostituisco con st_centroid. Risultati molto migliori in termini di velocità.

La semantica della speranza con st_overlaps rimane uguale. Almeno questo è stato capito dalla documentazione su <->

Dai documenti su Postigs <->

Per altri tipi di geometria viene restituita la distanza tra i centroidi del riquadro di delimitazione in virgola mobile.

Sui miei dati di test con poligoni di ~ 5,5 k sono aumentati da ~ 1000 secondi a ~ 5 secondi senza indicizzazione spaziale.

Comunque perché usare DISTINCT ON per fare il raggruppamento? Vedo alcune persone che lo usano, ma non esiste il gruppo per eliminare i duplicati?

La tua query con ottimizzazioni SQL standard senza l'errore st_centroid introdotto

select g1.gid, min( st_distance( g1.the_geom, g2.the_geom ) ) AS enn
FROM 
  "cosn1" AS g1, "cosn1" AS g2
WHERE
  g1.gid <> g2.gid
  AND g1.class = g2.class
  AND g1.the_geom && g2.the_geom
GROUP BY
  g1.gid

Buone vacanze di Natale!


Siamo spiacenti ma la tua risposta non risolve il problema. In effetti è molto più veloce, ma i risultati non sono accurati, poiché il risultato finale viene calcolato utilizzando i centroidi dei poligoni, anziché la loro geometria reale. Il <-> mira a ottimizzare la ricerca dei candidati al vicino più vicino, ma alla fine dovrebbe utilizzare le geometrie reali per calcolare la distanza dai migliori candidati. Ho anche provato a utilizzare MIN \ GROUP BY invece di DISTINCT ON \ ORDER BY, e sembra essere più lento.
Alexandre Neto,

Ma il manuale di Postgis per l'operatore <-> afferma che usa il centroide per le geometrie non punti. Quindi la mia soluzione ti darebbe risultati simili. Dovrebbe darti gli stessi risultati della tua query principale. Verificare che anche i risultati con l'operatore <-> siano corretti. Mi ha riportato geometrie di lunghezza zero sui miei dati di test, quindi i risultati potrebbero essere infranti e questa soluzione ha dato dati più accurati. Se sei in grado di pubblicare alcuni record di esempio che mostrano errori in alcuni siti di pastie, potremmo scoprire difetti sulla soluzione.
cavila,

Se controlli la mia domanda, l'operatore <-> verrebbe utilizzato solo per ordinare i candidati, il risultato finale viene calcolato usando le geometrie effettive. Ad ogni modo, come ho detto prima, l'aumento delle prestazioni <-> funziona solo con punti fissi. Questa era la mia domanda originale.
Alexandre Neto,

Quindi, sei d'accordo sul fatto che la query principale non equivale alla query inferiore? Dato che l'ordine cambierà perché l'operatore <-> ORDINERÀ da st_centroid e st_distance ti darà un valore diverso? Ordine diverso può portare una query diversa come prima riga per passare la clausola DISTINCT ON? La query valida sarebbe quella inferiore che necessita di un miglioramento della velocità?
cavila,

Sì, la prima query ha lo scopo di migliorare la velocità su quella in basso. E sì, potrebbe dare un risultato un po 'diverso, poiché g1.geom <-> g2.geom usa i centroidi e ciò significa che la prima riga potrebbe non essere la più vicina. Per farlo funzionare credo che dovrei mettere un limite all'ordine con la clausola diciamo limite 10 quindi estrarre i valori reali della distanza. Potrebbe anche usare il <#>, che utilizza i rettangoli anziché i centroidi.
Alexandre Neto,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.