Bonne aprÚs-midi! Je suis Victor, développeur chez Gems development. Chaque jour, notre équipe travaille avec des données spatiales de complexité et de qualité variables. Lors de l'exécution d'une opération d'intersection spatiale avec Postgis dans Postgresql, nous avons rencontré l'erreur suivante:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001
La requĂȘte menant Ă l'erreur ressemble Ă ceci:
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]]]}'))
La solution à ce problÚme bloque le travail des utilisateurs, car elle ne permet pas de créer des rapports sur les données et ralentit le travail de fourniture de services. De nombreuses actions dans le systÚme que nous développons, telles que: la préparation d'un tracé pour un terrain, la préparation d'un plan d'urbanisme pour un terrain, et d'autres, utilisent des opérations spatiales comme celle-ci.
Supposons que le problĂšme soit une gĂ©omĂ©trie incorrecte. Cette erreur est souvent gĂ©nĂ©rĂ©e par l'opĂ©ration d'intersection si les objets impliquĂ©s dans la requĂȘte ont des auto-intersections ou des points en double. Un exemple de ces erreurs de gĂ©omĂ©trie peut ĂȘtre vu ci-dessous. (La bordure du polygone se coupe et il y a deux coordonnĂ©es identiques dans la ligne)
Nous avons menĂ© notre propre enquĂȘte pour trouver les causes de l'erreur et nous voulons vous en informer.
Nous utilisons actuellement Postgis 2.4 et Postgresql 9.6. Allons directement à la pratique. Vérifions la validité de la géométrie constante et constatons que tout fonctionne correctement.
Nous pouvons supposer que la matiÚre est dans la table (vue) usahalinsk.V_GEO_OOPT dans laquelle nous recherchons des intersections. Afin de confirmer l'hypothÚse, nous vérifierons également ces données.
Mais nous ne trouvons pas non plus d'erreurs ici. De plus, les données n'étaient pas du tout incluses dans l'échantillon. Si tel était le cas, la tùche serait résolue en corrigeant les entrées trouvées via la fonction Postgis st_makeValid.
Mais il n'y a pas d'erreurs dans la vue et la requĂȘte n'est pas exĂ©cutĂ©e. Nous suggĂ©rons de regarder son plan.
Remarque: dans le modÚle réel, nous utilisons trois colonnes pour la géométrie (pour les polygones, les lignes et les points), mais par souci de concision, nous l'appellerons le champ géoloc - il stocke la géométrie et l'affiche dans la vue.
Notre vue usahalinsk.V_GEO_OOPT est construite comme une sélection de la table avec des données spatiales usahalinsk.d_geometry et un index spatial est créé sur le champ avec la géométrie.
Cela signifie que lors de l'exĂ©cution d'une requĂȘte, l'index est en cours de lecture et quelque part dans la table, sans entrer dans notre sĂ©lection, il y a des donnĂ©es spatiales non valides qui ont Ă©tĂ© incluses dans l'index, car il est construit sur toute la table.
Essayons de supprimer l'index:
DROP INDEX usahalinsk.d_geometry_cs1_all_sx;
Et essayons de répondre à la demande de problÚme.
Il a fonctionné sans erreurs. Nous confirmons que le problÚme est dans l'index. Vous pouvez renvoyer l'index, mais avec la condition de la géométrie correcte:
CREATE INDEX d_geometry_cs1_all_sx
ON usahalinsk.d_geometry
USING gist(geoloc)
where st_isvalid(geoloc)=true;
VĂ©rifions la mise en Ćuvre et voyons le plan.
La demande s'est exĂ©cutĂ©e sans erreur et l'index du plan est Ă©galement utilisĂ©. L'inconvĂ©nient d'une telle solution peut ĂȘtre le ralentissement de l'insertion / mise Ă jour, tk. de plus, la condition sera vĂ©rifiĂ©e lors de la reconstruction de l'index.
Renvoyons cette modification et essayons toujours de trouver les objets de l'index qui provoquent l'Ă©chec de notre requĂȘte.
DROP INDEX usahalinsk.d_geometry_cs1_all_sx;
CREATE INDEX d_geometry_cs1_all_sx
ON usahalinsk.d_geometry
USING gist
(geoloc);
Permettez-moi de vous rappeler que nous avons les coordonnées de l'emplacement de l'erreur:
XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001
mais si nous recherchons dans les données ou à la suite de la fonction IsValidReason, qui renvoie la raison de l'erreur, nous ne trouverons rien de similaire.
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%';
Vous pouvez utiliser le script suivant pour rechercher des objets qui affectent la requĂȘte. Nous vĂ©rifierons chaque objet du tableau et l'intersecterons avec la constante souhaitĂ©e. Lors de l'exĂ©cution, nous dĂ©tectons les exceptions et vĂ©rifions leur contenu. Si l'erreur contient les coordonnĂ©es dont nous avons besoin, alors c'est notre problĂšme de gĂ©omĂ©trie.
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$$;
En conséquence, nous obtenons trois clés de géométrie faciles à corriger:
update usahalinsk.d_geometry
set cs1_geometry_polygone=st_collectionextract(st_makevalid(geoloc),3)
where key in(
1000010001988961,
1000010001989399,
1000010004293508);
Je répondrai à la question qui se pose: "pourquoi est-il impossible de corriger toute géométrie erronée dans le tableau, pour ne pas rechercher sélectivement les raisons?" ...
Le fait est que les donnĂ©es spatiales arrivent Ă notre systĂšme Ă partir de diverses sources (y compris de Rosreestr) et nous ne pouvons pas effectuer de correction (en rĂšgle gĂ©nĂ©rale, cela s'accompagne d'une distorsion) de toutes les donnĂ©es. AprĂšs avoir reçu les clĂ©s nĂ©cessaires, nous analysons quelles donnĂ©es elles reprĂ©sentent et si elles peuvent ĂȘtre corrigĂ©es.
La tĂąche triviale de trouver la cause de l'erreur peut se transformer en une enquĂȘte complĂšte avec un script de correction Ă la fin.
Une version plus complexe du problÚme: que se passe-t-il si l'intersection est effectuée non pas avec une constante, mais avec une autre table? Vous pouvez également croiser chacun des objets participants du premier tableau avec chaque objet du second. Et attrapez les exceptions.
à quelle fréquence rencontrez-vous des problÚmes de géométrie et comment vous assurez-vous de la qualité de vos données spatiales?