
Selamat sore! Saya Victor, seorang pengembang di Gems development. Setiap hari, tim kami bekerja dengan data spasial dengan berbagai kompleksitas dan kualitas. Saat melakukan operasi persimpangan spasial dengan Postgis di Postgresql, kami menemukan kesalahan berikut:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001
Permintaan yang mengarah ke kesalahan terlihat seperti ini:
select q1.key,st_asGeoJson(geoloc)
from usahalinsk.V_GEO_OOPT q1
where ST_Intersects(geoloc,
ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":
[[[11165.15,2087.5],[11112,2066.6],[11127.6,2022.5],
[11122.6,2020.7],
[11122.25,2021.2],[11107.07,2015.7],
[11121,1947],[11123.48,1922.99],[11128.42,1874.4],
[11131.5,1875],[11140.96,1876.81],[11160.73,1880.59],
[11201.04,1888.3],[11194.2,1908],[11221.93,1916.57],
[11223.3,1917],[11165.15,2087.5]]]}'))
Solusi untuk masalah ini memblokir pekerjaan pengguna, karena tidak memungkinkan pembuatan laporan pada data dan memperlambat pekerjaan penyediaan layanan. Banyak tindakan dalam sistem yang sedang kami kembangkan, seperti: menyiapkan tata letak sebidang tanah, menyiapkan rencana tata kota untuk sebidang tanah, dan lainnya, menggunakan operasi tata ruang seperti ini.
Mari kita asumsikan bahwa masalahnya adalah geometri yang salah. Seringkali kesalahan ini dihasilkan oleh operasi interseksi jika objek yang berpartisipasi dalam kueri memiliki titik potong sendiri atau duplikat. Contoh kesalahan geometri tersebut dapat dilihat di bawah ini. (Batas poligon berpotongan sendiri dan ada dua koordinat identik di garis)

Kami telah melakukan penyelidikan kami sendiri untuk menemukan penyebab kesalahan dan ingin memberi tahu Anda tentang hal itu.
Kami saat ini menggunakan Postgis 2.4 dan Postgresql 9.6. Ayo langsung latihan. Mari kita periksa validitas geometri konstan dan temukan bahwa semuanya bekerja dengan benar.

Kita dapat berasumsi bahwa masalahnya ada di tabel (view) usahalinsk.V_GEO_OOPT di mana kita mencari persimpangan. Untuk mengkonfirmasi hipotesis, kami akan memeriksa data ini juga.

Tetapi kami juga tidak menemukan kesalahan di sini. Selain itu, data sama sekali tidak dimasukkan dalam sampel. Jika ya, maka tugas akan diselesaikan dengan mengoreksi entri yang ditemukan melalui fungsi st_makeValid Postgis.
Tetapi tidak ada kesalahan dalam tampilan, dan permintaan tidak dijalankan. Kami menyarankan untuk melihat rencananya.

Catatan: dalam model nyata kami menggunakan tiga kolom untuk geometri (untuk poligon, garis dan titik), tetapi untuk singkatnya kami akan menyebutnya bidang geoloc - ini menyimpan geometri dan menampilkannya dalam tampilan.
Tampilan kami usahalinsk.V_GEO_OOPT dibangun sebagai pilihan dari tabel dengan data spasial usahalinsk.d_geometry dan indeks spasial dibuat di lapangan dengan geometri.
Ini berarti bahwa saat menjalankan kueri, indeks sedang dibaca dan di suatu tempat di tabel, tidak masuk ke dalam pilihan kami, ada data spasial yang tidak valid yang disertakan dalam indeks, karena itu dibangun di seluruh tabel.
Mari coba hapus indeks:
DROP INDEX usahalinsk.d_geometry_cs1_all_sx;
Dan mari kita coba memenuhi permintaan yang bermasalah.

Itu berjalan tanpa kesalahan. Kami mengonfirmasi bahwa masalahnya ada di indeks. Anda dapat mengembalikan indeks, tetapi dengan kondisi geometri yang benar:
CREATE INDEX d_geometry_cs1_all_sx
ON usahalinsk.d_geometry
USING gist(geoloc)
where st_isvalid(geoloc)=true;
Mari kita periksa implementasinya dan lihat rencananya.

Permintaan berjalan tanpa kesalahan, dan indeks dalam rencana juga digunakan. Kerugian dari solusi semacam itu mungkin adalah perlambatan penyisipan / pembaruan, tk. Selain itu, kondisi akan diperiksa saat membangun kembali indeks.
Mari kita kembalikan perubahan ini kembali dan masih mencoba menemukan objek apa dalam indeks yang menyebabkan kueri kita gagal.
DROP INDEX usahalinsk.d_geometry_cs1_all_sx;
CREATE INDEX d_geometry_cs1_all_sx
ON usahalinsk.d_geometry
USING gist
(geoloc);
Izinkan saya mengingatkan Anda bahwa kami memiliki koordinat lokasi kesalahan:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001
Tetapi jika kami mencari di data atau sebagai hasil dari fungsi IsValidReason, yang mengembalikan alasan kesalahan, maka kami tidak akan menemukan yang serupa.
select key,ST_IsValidReason(geoloc)
from usahalinsk.d_geometry
where st_isvalid(geoloc)!=true
and ST_AsText(geoloc) like '%3844.9200000000001%';
select key,ST_IsValidReason(geoloc)
from usahalinsk.d_geometry
where st_isvalid(geoloc)!=true
and ST_IsValidReason(geoloc) like '%3844.9200000000001%';
Anda dapat menggunakan skrip berikut untuk menemukan objek yang mempengaruhi kueri. Kami akan memeriksa setiap objek tabel dan memotongnya dengan konstanta yang diinginkan. Selama eksekusi, kami menangkap pengecualian dan memeriksa isinya. Jika kesalahan berisi koordinat yang kita butuhkan, maka ini adalah masalah geometri kita.
do
$$
declare
tKey bigint;
rec record;
error_text text;
--
error_info text:='GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001';
begin
--
for rec in(select key from usahalinsk.d_geometry)
loop
begin
select key into tKey
from (select * from usahalinsk.d_geometry q1
--
where q1.key=rec.key
and ST_Intersects(geoloc,
--
ST_GeomFromGeoJSON('{"type":"Polygon","coordinates":[[[11165.15,2087.5],
[11112,2066.6],[11127.6,2022.5],[11122.6,2020.7],
[11122.25,2021.2],[11107.07,2015.7],[11121,1947], [11123.48,1922.99],[11128.42,1874.4],
[11131.5,1875],[11140.96,1876.81], [11160.73,1880.59],[11201.04,1888.3],
[11194.2,1908],[11221.93,1916.57],[11223.3,1917],
[11165.15,2087.5]]]}'))) geoQ;
exception when others then
--
GET STACKED DIAGNOSTICS error_text = MESSAGE_TEXT;
-- ,
if error_text=error_info then
raise info '%',rec.key;
end if;
end;
end loop;
end$$;
Hasilnya, kami mendapatkan tiga kunci geometri yang mudah diperbaiki:
update usahalinsk.d_geometry
set cs1_geometry_polygone=st_collectionextract(st_makevalid(geoloc),3)
where key in(
1000010001988961,
1000010001989399,
1000010004293508);
Saya akan menjawab pertanyaan yang muncul: "mengapa tidak mungkin untuk mengoreksi semua geometri yang salah dalam tabel, agar tidak mencari alasannya secara selektif?" ...
Faktanya adalah bahwa data spasial masuk ke sistem kami dari berbagai sumber (termasuk dari Rosreestr) dan kami tidak dapat melakukan koreksi (biasanya disertai dengan distorsi) semua data. Setelah menerima kunci yang diperlukan, kami menganalisis data apa yang mereka wakili dan apakah mungkin untuk memperbaikinya.
Tugas sepele untuk menemukan penyebab kesalahan dapat berubah menjadi penyelidikan menyeluruh dengan skrip koreksi di bagian akhir.
Versi masalah yang lebih kompleks: bagaimana jika perpotongan dilakukan bukan dengan konstanta, tetapi dengan tabel lain? Alternatifnya, potong setiap objek yang berpartisipasi di tabel pertama dengan setiap objek di tabel kedua. Dan menangkap pengecualian.
Seberapa sering Anda mengalami masalah geometri dan bagaimana Anda memastikan kualitas data spasial Anda?