Masalah tetangga terdekat di Postgis 2.0 menggunakan Indeks GIST (fungsi <->)

25

Saya mencoba menggunakan fungsi baru Postgis 2.0 <-> (Geometry Distance Centroid) untuk menghitung, untuk setiap baris tabel saya (cosn1), jarak ke poligon terdekat dari kelas yang sama.

Saya mencoba menggunakan kode berikut:

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;

Tapi kemudian saya menyadari peringatan itu:

Catatan: Indeks hanya menghasilkan jika salah satu geometri adalah konstanta (bukan dalam subquery / cte). mis. 'SRID = 3005; POINT (1011102 450541)' :: geometry alih-alih a.geom

Berarti Indeks tidak akan digunakan sama sekali, dan kueri akan memakan waktu yang hampir sama seperti sebelum menggunakan:

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)

Adakah yang bisa menunjukkan solusi yang memungkinkan saya meningkatkan kinerja kueri?

Terima kasih banyak.

Alexandre Neto
sumber
Belum ada tanggapan, Anda mungkin ingin menanyakan ini di milis PostGIS.
GIS-Jonathan
Saya sudah melakukannya, tetapi juga tanpa tanggapan.
Alexandre Neto
3
Anda dapat menggunakan g1.gid> g2.gid di klausa where, yang akan mengurangi jumlah perhitungan jarak yang harus Anda lakukan. Sayangnya, sampai operator <-> bekerja tanpa konstanta, kami tidak akan melihat banyak peningkatan kecepatan dalam kueri semacam ini.
John Powell
John, saya harus menyimpan semua gids, bahkan yang diulang karena saya perlu memperbarui EEN untuk masing-masing poligon di tabel "cosn1" saya. Tapi apa yang Anda katakan memberi saya ide. Saya bisa melakukan seperti yang Anda katakan menggunakan g1.gid> g2.gis untuk mengurangi perhitungan jarak, tetapi menjaga g1.gid dan g2.gid di hasilnya. Setelah itu, saya bisa menggabungkan dua subqueries (satu dengan g1.gis sebagai gid, dan lainnya dengan g2.gid). Terima kasih
Alexandre Neto
Saya menemukan bahwa solusi yang mungkin untuk menyelesaikan masalah konstan adalah dengan menggunakan <-> di dalam Fungsi SQL, menggunakan the_geom sebagai parameter. Saya telah membuat beberapa tes, dan dalam beberapa kasus ini jauh lebih cepat (). Tetapi dalam kasus saya, karena jarak berada di dalam tabel yang sama, banyak perhitungan jarak diulang selama proses, membuatnya lebih lambat daripada menggunakan kueri langsung.
Alexandre Neto

Jawaban:

2

Hum melakukan beberapa tes pada mesin saya terdengar seperti operator ini <-> tidak berfungsi dengan baik. Saya tidak yakin itu adalah bug tetapi melaporkan jarak nol pada geometri yang tidak tumpang tindih. Menarik bukan?

Nah bagaimana dengan optimasi query SQL tradisional yang adil? Karena hasil yang tidak terduga dengan operator <-> saya menggantinya dengan st_centroid. Mendapat hasil yang jauh lebih baik dalam kecepatan.

Semantik harapan dengan st_overlaps tetap sama. Setidaknya ini yang saya mengerti dari dokumentasi tentang <->

Dari docs on Postigs <->

Untuk tipe geometri lainnya, jarak antara centroid kotak pembatas titik apung dikembalikan.

Pada data pengujian saya dengan poligon ~ 5.5k, kecepatan dari ~ 1000 detik hingga ~ 5 detik tanpa pengindeksan spasial.

Pokoknya mengapa menggunakan DISTINCT ON untuk melakukan pengelompokan? Saya melihat beberapa orang menggunakannya tetapi tidak ada grup untuk menghilangkan duplikat?

Permintaan Anda dengan optimasi SQL standar tanpa kesalahan st_centroid diperkenalkan

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

Selamat liburan natal!

cavila
sumber
Maaf tetapi jawaban Anda tidak menyelesaikan masalah. Sebenarnya jauh lebih cepat, tetapi hasilnya tidak akurat, karena hasil akhir dihitung menggunakan centroid poligon, bukan geometri nyata mereka. <-> bertujuan untuk mengoptimalkan pencarian kandidat ke tetangga terdekat tetapi pada akhirnya harus menggunakan geometri nyata untuk menghitung jarak ke kandidat terbaik. Saya juga mencoba menggunakan MIN \ GROUP BY alih-alih DISTINCT ON \ ORDER BY, dan tampaknya lebih lambat.
Alexandre Neto
Tetapi manual postgis untuk operator <-> menyatakan bahwa ia menggunakan centroid untuk geometri non-titik. Jadi solusi saya akan memberi Anda hasil yang serupa. Ini akan memberi Anda hasil yang sama dengan permintaan teratas Anda. Harap periksa bahwa hasil dengan operator <-> juga benar. Ini melaporkan saya nol panjang geometri pada data pengujian saya sehingga hasilnya bisa rusak dan solusi ini memberikan data yang lebih akurat. Jika Anda dapat memposting beberapa catatan sampel yang menunjukkan kesalahan di beberapa situs pastie, kami dapat menemukan kekurangan pada solusi.
cavila
Jika Anda memeriksa kueri saya, operator <-> hanya akan digunakan untuk memesan kandidat, hasil akhir dihitung menggunakan geometri aktual. Bagaimanapun, seperti yang saya katakan sebelumnya, peningkatan kinerja <-> hanya bekerja dengan poin tetap. Itu pertanyaan awal saya.
Alexandre Neto
Jadi, apakah Anda setuju bahwa kueri teratas tidak setara dengan kueri bawah? Karena pesanan akan berubah karena operator <-> akan MEMESAN OLEH st_centroid dan st_distance akan memberi Anda nilai yang berbeda? Urutan yang berbeda dapat menghasilkan kueri yang berbeda saat baris pertama untuk meneruskan klausa DISTINCT ON? Kueri yang valid akan menjadi yang paling bawah yang membutuhkan peningkatan kecepatan?
cavila
Ya, permintaan pertama adalah niat untuk meningkatkan kecepatan di bagian bawah. Dan ya, itu mungkin memberikan hasil yang sedikit berbeda, karena g1.geom <-> g2.geom menggunakan centroid, dan itu berarti bahwa baris pertama mungkin bukan yang lebih dekat. Untuk membuatnya bekerja, saya yakin saya harus membatasi order dengan klausa mengatakan limit 10 lalu mengekstraksi nilai sebenarnya dari jarak. Bahkan bisa menggunakan <#> sebagai gantinya, yang menggunakan kotak pembatas alih-alih centroid.
Alexandre Neto