Menemukan tetangga terdekat antara dua tabel dengan lokasi titik di SpatiaLite?

10

Saya sudah mulai bermain dengan SpatiaLite hari ini dan sudah menemukan masalah.

Untuk setiap lokasi titik disimpan dalam tableOne Saya ingin memilih satu, titik terdekat (jarak linear) dari tableTwo.

Sejauh ini saya datang dengan solusi canggung yang memanfaatkan LIHAT:

CREATE VIEW testview AS 
SELECT 
A.id , 
B.myValue, 
Distance(A.Geometry, B.Geometry) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE distance < 10000
ORDER BY A.Id, distance;

Lalu:

SELECT * FROM testview
WHERE distance = (SELECT MIN(distance) FROM testview AS t WHERE t.id = testview.id)

tampaknya melakukan pekerjaan itu.

Dua pertanyaan:

Apakah ada cara untuk melakukan permintaan seperti itu tanpa membuat VIEW?

Apakah ada cara lain untuk mengoptimalkan kueri ini untuk kinerja yang lebih baik? Dalam tabel skenario dunia nyata, One akan memiliki ratusan ribu pasangan catatan, dan tableTwo - 1,3 juta.

Radek
sumber
Saya dapat memberi Anda pendekatan yang beberapa urutan besarnya lebih cepat, tetapi akan mengharuskan Anda untuk menggunakan indeks knngist postgresql 9 bukannya spasial ...
Ragi Yaser Burhum
sebenarnya lebih cepat dari GRASS, ArcGIS, QGIS, SQLServer dan cukup banyak spasial lainnya db / Desktop GIS (belum mencoba fungsi tetangga terdekat Oracle) .Hanya saja beri tahu saya jika ini merupakan pilihan.
Ragi Yaser Burhum
@Ragi: Saya sadar bahwa PostGIS akan menjadi cara yang jauh lebih efisien untuk mengatasi masalah tersebut. Namun tujuan akhir dari latihan ini adalah membuat aplikasi portabel kecil dan dalam hal ini SpatiaLite adalah pemenangnya.
radek
Apa platform pengembangan Anda untuk aplikasi portabel Anda?
Allan Adair
@ Allan: Sedang mengerjakan keduanya: Windows Server 2008 & Ubuntu saat ini.
radek

Jawaban:

5

Saya baru saja menguji SQL ini dan berhasil:

SELECT g1.OGC_FID As id1, g2.OGC_FID As id2, MIN(ST_Distance(g1.GEOMETRY,g2.GEOMETRY)) AS DIST
FROM table_01 As g1, table_02 As g2   
WHERE g1.OGC_FID <> g2.OGC_FID
AND ST_Contains(ST_Expand(g1.geometry,50),g2.geometry)
GROUP BY id1
ORDER BY id1

Seperti yang Anda baca di sini, "Cara naif untuk melakukan kueri tetangga terdekat adalah dengan memesan tabel kandidat berdasarkan jarak dari geometri kueri, dan kemudian mengambil catatan dengan jarak terkecil".

Salam Hormat,

Andrea

aborruso
sumber
Saya mencoba menggunakan kueri ini tetapi saya mendapatkan hasil yang tidak diharapkan - Saya mendapatkan tabel yang dihasilkan tetapi dengan ID untuk baris saya dapat melihat bukan tetangga terdekat. Saya mencoba untuk menemukan garis terdekat dalam lapisan string multiline ke setiap titik di lapisan lain. Saya baru menggunakan spatiaLite. Ada saran? Juga, saya akhirnya ingin menjalankan ini pada 1 juta + poin
kflaw
Saya juga tidak yakin saya mengerti tujuan dari pernyataan ini: WHERE g1.OGC_FID <> g2.OGC_FID
kflaw
Juga, dalam hasil saya, saya mendapatkan jarak nol. Saya telah bermain-main dengan baris ini: AND ST_Contains (ST_Expand (g1.geometry, 50), g2.geometry) serta menghapusnya dan masih tidak mendapatkan nilai jarak, meskipun saya mendapatkan ID
kflaw
6

Jika Anda tidak ingin menghitung jarak antara semua kombinasi titik, Anda bisa menggunakan indeks spasial di salah satu tabel:

SELECT 
  A.id , 
  B.myValue, 
  MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
WHERE A.ROWID IN (
  SELECT ROWID
  FROM SpatialIndex WHERE
    f_table_name = 'A' 
    AND search_frame = BuildCircleMbr(ST_X(B.Geometry), ST_Y(B.Geometry), 10000))
GROUP BY A.id, B.myValue
Samuel
sumber
Saya sudah mencoba menggunakan solusi yang Anda posting karena saya perlu menggunakan indeks spasial, tetapi tidak mengembalikan nilai? untuk baris tersebut f_table_name = 'A', apakah saya harus mengganti 'A' dengan nama tabel sebenarnya (tabel satu)? Saya sudah mencoba kedua cara dan masih tidak mengembalikan apa pun, mengapa ini mungkin
kflaw
Anda benar f_table_name = 'A'seharusnya f_table_name = 'tableOne'. Perhatikan bahwa permintaan ini mengasumsikan spatialite> 4.x ( SpatialIndextabel virtual digunakan). Apakah Anda mencoba menyesuaikan search_frameuntuk kasus penggunaan Anda? Dalam contoh di atas, titik diasumsikan berada pada jarak maksimum 10.000 meter.
Samuel
Saya memang bermain-main dengan nilai frame pencarian, saya berasumsi itu berarti dalam jarak 10.000 meter yang seharusnya cocok untuk saya. Saya sebenarnya tidak tahu versi spatialite mana, saya membuat database melalui qgis dan saya menggunakan gui dalam qgis. Biarkan saya melihat apakah saya bisa mengetahuinya
kflaw
Ini adalah versi 4.1.1 dengan versi sqlite 3.7.17, jadi haruskah itu berfungsi? Saya bertanya-tanya apa yang salah saya akan mengujinya lagi
kflaw
3

Karena versi 4.4.0 SpatiaLite mendukung indeks tabel virtual KNN untuk masalah tetangga terdekat. Berikut adalah kueri yang menemukan baris terdekat di tabel linestring ke setiap titik dalam tabel titik.

SELECT k.* FROM knn k, points p
WHERE f_table_name = 'linestrings' 
AND ref_geometry = p.geometry
AND max_items = 1;
Greg Krakow
sumber
2

Anda dapat menyederhanakan kueri Anda seperti ini.

SELECT 
   A.id , 
   B.myValue, 
   MIN(Distance(A.Geometry, B.Geometry)) AS distance
FROM tableOne AS A, tableTwo AS B
GROUP BY A.id, B.myValue

Untuk solusi yang lebih umum, mungkin ada baiknya mencoba mengubah fungsi PostGIS Nearest Neighbor ini: http://blog.mackerron.com/2011/03/postgis-nearest-neighbour/

underdark
sumber
sayangnya kode menghasilkan:SQL error: "misuse of aggregate: MIN()"
radek
Pada PostGIS ada juga beberapa contoh di situs BostonGIS, tetapi sejauh ini saya tidak berhasil menerjemahkannya ke dalam SpatiaLite: /
radek