فصل 5. الاستعلامات المكانية
علّة وجود قواعد البيانات المكانية هي تنفيذ استعلامات داخل قاعدة البيانات تتطلب عادةً وظائف نظم المعلومات الجغرافية المكتبية. ويتطلب استخدام PostGIS بفعالية معرفة الدوال المكانية المتاحة، وكيفية استخدامها في الاستعلامات، والتأكد من وجود الفهارس المناسبة لتوفير أداء جيد.
5.1. تحديد العلاقات المكانية
تُبيّن العلاقات المكانية كيف يتفاعل شكلان هندسيان أحدهما مع الآخر. وهي قدرة أساسية للاستعلام عن الأشكال الهندسية.
5.1.1. نموذج التقاطعات التسعة الموسّع بالأبعاد
وفقًا لـ مواصفة تطبيق OpenGIS Simple Features لـ SQL، "النهج الأساسي لمقارنة شكلين هندسيين هو إجراء اختبارات زوجية للتقاطعات بين الدواخل والحدود والخوارج للشكلين، وتصنيف العلاقة بينهما بناءً على مُدخلات مصفوفة 'التقاطع' الناتجة."
في نظرية طوبولوجيا مجموعات النقاط، تُصنَّف نقاط الشكل الهندسي المضمَّن في فضاء ثنائي الأبعاد إلى ثلاث مجموعات:
- الحد
-
حد الشكل الهندسي هو مجموعة الأشكال الهندسية ذات البُعد الأدنى التالي. بالنسبة إلى
POINT، التي بُعدها 0، يكون الحد هو المجموعة الفارغة. وحدLINESTRINGهو نقطتا النهاية. وبالنسبة إلىPOLYGON، يكون الحد هو خطوط الحلقات الخارجية والداخلية. - الداخل
-
داخل الشكل الهندسي هو نقاط الشكل التي لا تقع على الحد. بالنسبة إلى
POINT، يكون الداخل هو النقطة نفسها. وداخلLINESTRINGهو مجموعة النقاط الواقعة بين نقطتي النهاية. وبالنسبة إلىPOLYGON، يكون الداخل هو السطح المساحي داخل المضلع. - الخارج
-
خارج الشكل الهندسي هو بقية الفضاء الذي يُضمَّن فيه الشكل؛ أي جميع النقاط التي لا تقع في داخل الشكل أو على حده. وهو سطح ثنائي الأبعاد غير مغلق.
يصف نموذج التقاطعات التسعة الموسّع بالأبعاد (DE-9IM) العلاقة المكانية بين شكلين هندسيين بتحديد أبعاد التقاطعات التسعة بين المجموعات المذكورة أعلاه لكل شكل. ويمكن تمثيل أبعاد التقاطعات رسميًا في مصفوفة تقاطع بحجم 3x3.
بالنسبة إلى شكل هندسي g، يُرمز إلى الداخل والحد والخارج بالرموز I(g) وB(g) وE(g). كما يرمز dim(s) إلى بُعد المجموعة s ضمن المجال {0,1,2,F}:
-
0=> نقطة -
1=> خط -
2=> مساحة -
F=> مجموعة فارغة
باستخدام هذا الترميز، تكون مصفوفة التقاطع لشكلين هندسيين a وb هي:
| الداخل | الحد | الخارج | |
|---|---|---|---|
| الداخل | dim( I(a) ∩ I(b) ) | dim( I(a) ∩ B(b) ) | dim( I(a) ∩ E(b) ) |
| الحد | dim( B(a) ∩ I(b) ) | dim( B(a) ∩ B(b) ) | dim( B(a) ∩ E(b) ) |
| الخارج | dim( E(a) ∩ I(b) ) | dim( E(a) ∩ B(b) ) | dim( E(a) ∩ E(b) ) |
بصريًا، يبدو ذلك لشكلين مضلعيين متداخلين على النحو الآتي:
|
||||||||||||||||||
|
|
بالقراءة من اليسار إلى اليمين ومن الأعلى إلى الأسفل، تُمثَّل مصفوفة التقاطع بالسلسلة النصية '212101212'.
لمزيد من المعلومات، راجع:
5.1.2. العلاقات المكانية المسمّاة
لتسهيل تحديد العلاقات المكانية الشائعة، تُعرّف مواصفة OGC SFS مجموعة من شروط العلاقات المكانية المسمّاة. ويوفرها PostGIS في صورة الدوال ST_Contains وST_Crosses وST_Disjoint وST_Equals وST_Intersects وST_Overlaps وST_Touches وST_Within. كما يُعرّف شروط العلاقات غير القياسية ST_Covers وST_CoveredBy وST_ContainsProperly.
تُستخدم الشروط المكانية عادةً كشروط في عبارات WHERE أو JOIN في SQL. وتستخدم الشروط المكانية المسمّاة الفهرس المكاني تلقائيًا إن وُجد، فلا حاجة إلى استخدام عامل المستطيل المحيط && أيضًا. على سبيل المثال:
SELECT city.name, state.name, city.geom FROM city JOIN state ON ST_Intersects(city.geom, state.geom);
لمزيد من التفاصيل والرسوم التوضيحية، انظر ورشة عمل PostGIS.
5.1.3. العلاقات المكانية العامة
في بعض الحالات لا تكفي العلاقات المكانية المسمّاة لتوفير شرط التصفية المكانية المطلوب.
![]() على سبيل المثال، لنأخذ مجموعة بيانات خطية تمثل شبكة طرق. قد يلزم تحديد جميع مقاطع الطرق التي يعبر بعضها بعضًا، لا في نقطة، بل في خط (ربما للتحقق من قاعدة عمل ما). في هذه الحالة لا توفر ST_Crosses المرشّح المكاني اللازم، لأنها تُعيد للمعالم الخطية يتمثل الحل ذو الخطوتين في حساب التقاطع الفعلي (ST_Intersection) لأزواج خطوط الطرق التي تتقاطع مكانيًا (ST_Intersects) أولًا، ثم التحقق مما إذا كان ST_GeometryType للتقاطع هو ' من الواضح أن حلًا أبسط وأسرع مرغوب فيه. |
![]() مثال ثانٍ هو تحديد مواقع الأرصفة البحرية التي تتقاطع مع حد بحيرة في خط ويكون أحد طرفي الرصيف على الشاطئ. بعبارة أخرى، حيث يقع الرصيف داخل البحيرة دون أن تحتويه كليًا، ويتقاطع مع حدها في خط، ويقع طرف واحد بالضبط من طرفيه داخل البحيرة أو على حدها. يمكن استخدام مجموعة من الشروط المكانية للعثور على المعالم المطلوبة:
|
يمكن تلبية هذه المتطلبات بحساب مصفوفة التقاطع DE-9IM كاملة. ويوفر PostGIS الدالة ST_Relate لذلك:
SELECT ST_Relate( 'LINESTRING (1 1, 5 5)',
'POLYGON ((3 3, 3 7, 7 7, 7 3, 3 3))' );
st_relate
-----------
1010F0212
لاختبار علاقة مكانية معينة، يُستخدم نمط مصفوفة التقاطع. وهو تمثيل المصفوفة مُعزَّزًا بالرمزين الإضافيين {T,*}:
-
T=> بُعد التقاطع غير فارغ؛ أي ينتمي إلى{0,1,2} -
*=> لا يهم
باستخدام أنماط مصفوفة التقاطع، يمكن تقييم علاقات مكانية محددة بطريقة أكثر إيجازًا. ويمكن استخدام الدالتين ST_Relate وST_RelateMatch لاختبار أنماط مصفوفة التقاطع. بالنسبة إلى المثال الأول أعلاه، نمط مصفوفة التقاطع الذي يحدد خطين يتقاطعان في خط هو '1*1***1**':
-- Find road segments that intersect in a line
SELECT a.id
FROM roads a, roads b
WHERE a.id != b.id
AND a.geom && b.geom
AND ST_Relate(a.geom, b.geom, '1*1***1**');
بالنسبة إلى المثال الثاني، نمط مصفوفة التقاطع الذي يحدد خطًا يقع جزئيًا داخل مضلع وجزئيًا خارجه هو '102101FF2':
-- Find wharves partly on a lake's shoreline
SELECT a.lake_id, b.wharf_id
FROM lakes a, wharfs b
WHERE a.geom && b.geom
AND ST_Relate(a.geom, b.geom, '102101FF2');
5.2. استخدام الفهارس المكانية
عند إنشاء استعلامات تستخدم شروطًا مكانية، من المهم لتحقيق أفضل أداء التأكد من استخدام الفهرس المكاني إن وُجد (انظر قسم 4.9, “الفهارس المكانية”). ولتحقيق ذلك، يجب استخدام عامل مكاني أو دالة مُدركة للفهرس في عبارة WHERE أو ON في الاستعلام.
تشمل العوامل المكانية عوامل المستطيل المحيط (وأكثرها استخدامًا &&؛ انظر قسم 7.10.1, “عوامل المستطيل المحيط” للقائمة الكاملة) وعوامل المسافة المستخدمة في استعلامات أقرب جار (وأكثرها شيوعًا <->؛ انظر قسم 7.10.2, “عوامل المسافة” للقائمة الكاملة.)
تضيف الدوال المُدركة للفهرس عامل المستطيل المحيط إلى الشرط المكاني تلقائيًا. وتشمل الدوال المُدركة للفهرس شروط العلاقات المكانية المسمّاة ST_Contains وST_ContainsProperly وST_CoveredBy وST_Covers وST_Crosses وST_Intersects وST_Overlaps وST_Touches وST_Within وST_Within وST_3DIntersects، وشروط المسافة ST_DWithin وST_DFullyWithin وST_3DDFullyWithin وST_3DDWithin .)
دوال مثل ST_Distance لا تستخدم الفهارس لتحسين عملها. على سبيل المثال، سيكون الاستعلام الآتي بطيئًا جدًا على جدول كبير:
SELECT geom FROM geom_table WHERE ST_Distance( geom, 'SRID=312;POINT(100000 200000)' ) < 100
يختار هذا الاستعلام جميع الأشكال الهندسية في geom_table التي تقع ضمن 100 وحدة من النقطة (100000, 200000). وسيكون بطيئًا لأنه يحسب المسافة بين كل نقطة في الجدول والنقطة المحددة، أي تُجرى عملية حساب ST_Distance() واحدة لـكل صف في الجدول.
يمكن تقليل عدد الصفوف المعالَجة بشكل كبير باستخدام الدالة المُدركة للفهرس ST_DWithin:
SELECT geom FROM geom_table WHERE ST_DWithin( geom, 'SRID=312;POINT(100000 200000)', 100 )
يختار هذا الاستعلام الأشكال الهندسية نفسها، لكنه يفعل ذلك بطريقة أكثر كفاءة. ويُتاح ذلك لأن ST_DWithin() تستخدم داخليًا العامل && على مستطيل محيط موسَّع للشكل الهندسي للاستعلام. إذا وُجد فهرس مكاني على geom، فسيدرك مخطِّط الاستعلامات أنه يمكنه استخدام الفهرس لتقليل عدد الصفوف الممسوحة قبل حساب المسافة. يتيح الفهرس المكاني استرجاع السجلات ذات الأشكال الهندسية التي تتداخل مستطيلاتها المحيطة مع الامتداد الموسَّع فقط، والتي قد تقع بالتالي ضمن المسافة المطلوبة. ثم تُحسب المسافة الفعلية للتأكد مما إذا كان السجل سيُدرج في مجموعة النتائج.
لمزيد من المعلومات والأمثلة انظر ورشة عمل PostGIS.
5.3. أمثلة على SQL المكاني
تستخدم الأمثلة في هذا القسم جدولًا للطرق الخطية، وجدولًا لحدود البلديات المضلعة. تعريف الجدول bc_roads هو:
Column | Type | Description ----------+-------------------+------------------- gid | integer | Unique ID name | character varying | Road Name geom | geometry | Location Geometry (Linestring)
تعريف الجدول bc_municipality هو:
Column | Type | Description ---------+-------------------+------------------- gid | integer | Unique ID code | integer | Unique ID name | character varying | City / Town Name geom | geometry | Location Geometry (Polygon)
- 5.3.1. ما الطول الإجمالي لجميع الطرق، معبَّرًا عنه بالكيلومترات؟
- 5.3.2. ما مساحة مدينة Prince George بالهكتارات؟
- 5.3.3. ما أكبر بلدية في المقاطعة من حيث المساحة؟
- 5.3.4. ما طول الطرق الواقعة كليًا داخل كل بلدية؟
- 5.3.5. إنشاء جدول جديد يضم جميع الطرق الواقعة داخل مدينة Prince George.
- 5.3.6. ما طول "Douglas St" في Victoria بالكيلومترات؟
- 5.3.7. ما أكبر مضلع بلدية يحتوي على ثقب؟
|
5.3.1. |
ما الطول الإجمالي لجميع الطرق، معبَّرًا عنه بالكيلومترات؟ |
|
يمكنك الإجابة عن هذا السؤال بقطعة SQL بسيطة جدًا: SELECT sum(ST_Length(geom))/1000 AS km_roads FROM bc_roads; km_roads ------------------ 70842.1243039643 |
|
|
5.3.2. |
ما مساحة مدينة Prince George بالهكتارات؟ |
|
يجمع هذا الاستعلام بين شرط على السمات (على اسم البلدية) وحساب مكاني (لمساحة المضلع): SELECT ST_Area(geom)/10000 AS hectares FROM bc_municipality WHERE name = 'PRINCE GEORGE'; hectares ------------------ 32657.9103824927 |
|
|
5.3.3. |
ما أكبر بلدية في المقاطعة من حيث المساحة؟ |
|
يستخدم هذا الاستعلام قياسًا مكانيًا كقيمة للترتيب. توجد عدة طرق لمعالجة هذه المسألة، لكن أكثرها كفاءة هي الآتية: SELECT name, ST_Area(geom)/10000 AS hectares FROM bc_municipality ORDER BY hectares DESC LIMIT 1; name | hectares ---------------+----------------- TUMBLER RIDGE | 155020.02556131 لاحظ أنه للإجابة عن هذا الاستعلام يجب حساب مساحة كل مضلع. وإذا كنا نفعل ذلك كثيرًا، فمن المنطقي إضافة عمود للمساحة إلى الجدول يمكن فهرسته لتحسين الأداء. وبترتيب النتائج ترتيبًا تنازليًا، ثم استخدام الأمر "LIMIT" في PostgreSQL، يمكننا بسهولة اختيار أكبر قيمة فقط دون استخدام دالة تجميعية مثل MAX(). |
|
|
5.3.4. |
ما طول الطرق الواقعة كليًا داخل كل بلدية؟ |
|
هذا مثال على "الربط المكاني"، الذي يجمع البيانات من جدولين (بعملية ربط) باستخدام تفاعل مكاني ("محتوى في") كشرط للربط (بدلًا من النهج العلائقي المعتاد للربط على مفتاح مشترك): SELECT m.name, sum(ST_Length(r.geom))/1000 as roads_km FROM bc_roads AS r JOIN bc_municipality AS m ON ST_Contains(m.geom, r.geom) GROUP BY m.name ORDER BY roads_km; name | roads_km ----------------------------+------------------ SURREY | 1539.47553551242 VANCOUVER | 1450.33093486576 LANGLEY DISTRICT | 833.793392535662 BURNABY | 773.769091404338 PRINCE GEORGE | 694.37554369147 ... يستغرق هذا الاستعلام بعض الوقت، لأن كل طريق في الجدول يُلخَّص في النتيجة النهائية (نحو 250 ألف طريق في جدول المثال). أما لمجموعات البيانات الأصغر (عدة آلاف من السجلات على عدة مئات) فقد تكون الاستجابة سريعة جدًا. |
|
|
5.3.5. |
إنشاء جدول جديد يضم جميع الطرق الواقعة داخل مدينة Prince George. |
|
هذا مثال على "التراكب" (overlay)، الذي يأخذ جدولين ويُخرج جدولًا جديدًا يتكون من نواتج مقصوصة أو مقطوعة مكانيًا. وخلافًا لـ"الربط المكاني" الموضح أعلاه، يُنشئ هذا الاستعلام أشكالًا هندسية جديدة. التراكب أشبه بربط مكاني فائق القوة، وهو مفيد لأعمال التحليل الأكثر دقة: CREATE TABLE pg_roads as SELECT ST_Intersection(r.geom, m.geom) AS intersection_geom, ST_Length(r.geom) AS rd_orig_length, r.* FROM bc_roads AS r JOIN bc_municipality AS m ON ST_Intersects(r.geom, m.geom) WHERE m.name = 'PRINCE GEORGE'; |
|
|
5.3.6. |
ما طول "Douglas St" في Victoria بالكيلومترات؟ |
SELECT sum(ST_Length(r.geom))/1000 AS kilometers FROM bc_roads r JOIN bc_municipality m ON ST_Intersects(m.geom, r.geom WHERE r.name = 'Douglas St' AND m.name = 'VICTORIA'; kilometers ------------------ 4.89151904172838 |
|
|
5.3.7. |
ما أكبر مضلع بلدية يحتوي على ثقب؟ |
SELECT gid, name, ST_Area(geom) AS area FROM bc_municipality WHERE ST_NRings(geom) > 1 ORDER BY area DESC LIMIT 1; gid | name | area -----+--------------+------------------ 12 | SPALLUMCHEEN | 257374619.430216 |

