PostGis. كيف أجد خطأ في الاستعلام المكاني؟

صورة


طاب مسائك! أنا فيكتور ، مطور في شركة Gems. يعمل فريقنا يوميًا على بيانات مكانية متفاوتة التعقيد والجودة. عند إجراء عملية تقاطع مكاني مع Postgis في Postgresql ، واجهنا الخطأ التالي:



XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001



يبدو الطلب الذي أدى إلى الخطأ كما يلي:



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]]]}'))



حل هذه المشكلة يعيق عمل المستخدمين ، لأنه لا يسمح ببناء تقارير على البيانات ويبطئ عمل تقديم الخدمات. العديد من الإجراءات في النظام الذي نقوم بتطويره ، مثل: إعداد مخطط لقطعة أرض ، وإعداد خطة تخطيط حضري لقطعة أرض ، وغيرها ، استخدام عمليات مكانية مثل هذه.



لنفترض أن المشكلة تكمن في الهندسة غير الصحيحة. غالبًا ما يتم إنشاء هذا الخطأ بواسطة عملية التقاطع إذا كانت الكائنات المضمنة في الاستعلام تحتوي على تقاطعات ذاتية أو نقاط مكررة. يمكن رؤية مثال على هذه الأخطاء الهندسية أدناه. (يتقاطع حد المضلع مع نفسه ويوجد إحداثيان متطابقان في السطر)





لقد أجرينا تحقيقًا خاصًا بنا لمعرفة أسباب الخطأ ونريد إخبارك به.

نحن نستخدم حاليًا Postgis 2.4 و Postgresql 9.6. دعنا نذهب مباشرة إلى التدريب. دعنا نتحقق من الهندسة الثابتة للتأكد من صحتها ونجد أن كل شيء يعمل بشكل صحيح.





يمكننا أن نفترض أن الأمر موجود في الجدول (view) usahalinsk.V_GEO_OOPT الذي نبحث فيه عن التقاطعات. من أجل تأكيد الفرضية ، سوف نتحقق من هذه البيانات أيضًا.





لكننا لا نجد أخطاء هنا أيضًا. بالإضافة إلى ذلك ، لم يتم تضمين البيانات في العينة على الإطلاق. إذا كانت كذلك ، فسيتم حل المهمة عن طريق تصحيح الإدخالات التي تم العثور عليها من خلال وظيفة Postgis st_makeValid.



لكن لا توجد أخطاء في العرض ، ولا يتم تنفيذ الطلب. نقترح النظر في خطته.





ملاحظة: في النموذج الحقيقي ، نستخدم ثلاثة أعمدة للهندسة (للمضلعات والخطوط والنقاط) ، ولكن للإيجاز سنسمي هذا الحقل الجغرافي - فهو يخزن الهندسة ويعرضها في العرض.



تم إنشاء وجهة نظرنا usahalinsk.V_GEO_OOPT كاختيار من الجدول باستخدام البيانات المكانية usahalinsk.d_geometry ويتم إنشاء فهرس مكاني في الحقل باستخدام الهندسة.



هذا يعني أنه عند تنفيذ استعلام ، تتم قراءة الفهرس وفي مكان ما في الجدول ، دون الدخول في تحديدنا ، هناك بيانات مكانية غير صالحة تم تضمينها في الفهرس ، حيث تم بناؤه عبر الطاولة بأكملها.



دعنا نحاول حذف الفهرس:



DROP INDEX usahalinsk.d_geometry_cs1_all_sx;


ودعنا نحاول تلبية طلب المشكلة.





ركض بدون أخطاء. نؤكد أن المشكلة موجودة في الفهرس. يمكنك إرجاع الفهرس ، ولكن بشرط الشكل الهندسي الصحيح:



CREATE INDEX d_geometry_cs1_all_sx
  ON usahalinsk.d_geometry
  USING gist(geoloc)
  where st_isvalid(geoloc)=true;


دعنا نتحقق من التنفيذ ونرى الخطة.





تم تشغيل الطلب بدون أخطاء ، كما يتم استخدام الفهرس الموجود في الخطة. قد يكون عيب هذا الحل هو تباطؤ الإدراج / التحديث ، tk. بالإضافة إلى ذلك ، سيتم فحص الحالة عند إعادة بناء الفهرس.



دعنا نعيد هذا التغيير مرة أخرى وما زلنا نحاول العثور على الكائنات الموجودة في الفهرس التي تسبب فشل الاستعلام الخاص بنا.



DROP INDEX usahalinsk.d_geometry_cs1_all_sx;
 
CREATE INDEX d_geometry_cs1_all_sx
  ON usahalinsk.d_geometry
  USING gist
  (geoloc);


دعني أذكرك بأن لدينا إحداثيات موقع الخطأ:



XX000: GEOSIntersects: TopologyException: side location conflict at 10398.659 3844.9200000000001



ولكن إذا بحثنا في البيانات أو كنتيجة لوظيفة IsValidReason ، والتي ترجع سبب الخطأ ، فلن نجد أي شيء مشابه.



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%';


يمكنك استخدام البرنامج النصي التالي للبحث عن الكائنات التي تؤثر على الاستعلام. سوف نتحقق من كل كائن في الجدول ونتقاطع مع الثابت المطلوب. أثناء التنفيذ ، نكتشف الاستثناءات ونتحقق من محتوياتها. إذا كان الخطأ يحتوي على الإحداثيات التي نحتاجها ، فهذه هي مشكلتنا الهندسية.



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$$;


نتيجة لذلك ، نحصل على ثلاثة مفاتيح هندسية يسهل إصلاحها:



update usahalinsk.d_geometry 
set cs1_geometry_polygone=st_collectionextract(st_makevalid(geoloc),3)
where key in(
1000010001988961,
1000010001989399,
1000010004293508);


سأجيب على السؤال الذي يطرح نفسه: "لماذا يستحيل تصحيح كل الأشكال الهندسية الخاطئة في الجدول حتى لا يتم البحث عن الأسباب بشكل انتقائي؟" ...



الحقيقة هي أن البيانات المكانية تأتي إلى نظامنا من مصادر مختلفة (بما في ذلك من Rosreestr) ولا يمكننا إجراء تصحيح (كقاعدة عامة ، يكون مصحوبًا بتشويه) لجميع البيانات. بعد استلام المفاتيح اللازمة ، نقوم بتحليل البيانات التي تمثلها وما إذا كان من الممكن تصحيحها.



يمكن أن تتحول المهمة التافهة المتمثلة في العثور على سبب الخطأ إلى تحقيق كامل مع نص تصحيح في النهاية.



نسخة أكثر تعقيدًا من المشكلة: ماذا لو تم إجراء التقاطع ليس باستخدام ثابت ، ولكن باستخدام جدول آخر؟ بدلاً من ذلك ، تقاطع كل من الكائنات المشاركة في الجدول الأول مع كل كائن في الثاني. والتقاط الاستثناءات.



كم مرة تواجه مشاكل هندسية وكيف تضمن جودة بياناتك المكانية؟



All Articles