feat: sync source-backed OSM facility entrances
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
<div dir="rtl" align="right">
|
||||
|
||||
# أبواب ومداخل المنشآت: المصدر والتغطية والتشغيل
|
||||
|
||||
**آخر تحديث:** 29 أيلول 2026
|
||||
**المصدر المطبق:** عقد مداخل وبوابات OpenStreetMap ذات الإحداثيات والوسوم الأصلية.
|
||||
|
||||
## الحالة الحالية على الخادم
|
||||
|
||||
استوردت المزامنة **1,439 نقطة مدخل/بوابة مصدرية** وربطتها بـ **389 منشأة مسماة** عبر حدود مضلعات OSM، في الدول الإحدى عشرة. كل نقطة في جدول الخدمة تقابل عقدة OSM فعلية، وتحفظ معرّف العقدة والوسوم الأصلية ورابط المصدر وآخر وقت رصد. لا يحسب البرنامج إحداثيات حول مركز المنشأة.
|
||||
|
||||
| الدولة | نقاط الأبواب/المداخل | منها رئيسي معلّم صراحةً |
|
||||
|---|---:|---:|
|
||||
| الإمارات | 309 | 42 |
|
||||
| البحرين | 41 | 2 |
|
||||
| مصر | 644 | 16 |
|
||||
| العراق | 65 | 7 |
|
||||
| الأردن | 24 | 3 |
|
||||
| الكويت | 44 | 5 |
|
||||
| عُمان | 41 | 2 |
|
||||
| قطر | 66 | 2 |
|
||||
| السعودية | 175 | 5 |
|
||||
| سوريا | 21 | 1 |
|
||||
| اليمن | 9 | 0 |
|
||||
| **المجموع** | **1,439** | **85** |
|
||||
|
||||
تشمل المنشآت المضلعات المسماة الموسومة كمستشفى أو عيادة أو مول أو مكتب حكومي أو مبنى حكومي أو دار بلدية أو محكمة. المستشفيات هنا ليست مصنفة حكومية/خاصة إلا إذا كانت بيانات OSM نفسها تثبت ذلك. تغطية اليمن وسوريا والأردن قليلة مقارنة ببقية الدول؛ هذه الأعداد تقيس ما وجدته بيانات OSM في نسخة الخريطة على الخادم، ولا تعني اكتمال الواقع.
|
||||
|
||||
## كيف تُحدد أنواع الأبواب؟
|
||||
|
||||
- `entrance=main` وحدها تضع `is_main_gate=true` و`gate_type=main`. تؤخذ أيضًا علامة `routing:entrance` كدليل على نقطة وصول مخصصة للملاحة، مع حفظها كما هي.
|
||||
- `entrance=secondary/service/emergency/parking` تبقى بهذه الصفة عند وجودها صراحةً في المصدر.
|
||||
- `barrier=gate` أو `entrance=yes` بلا تصنيف صريح يعرض كـ«بوابة» أو «مدخل»، ولا يُسمى رئيسيًا.
|
||||
- تستبعد النقاط الخاصة أو الممنوعة (`access=private/no`) من واجهة المداخل العامة.
|
||||
- لا تُربط العقدة بمنشأة إلا إذا وقعت هندستها داخل مضلع منشأة OSM مسماة ومؤهلة، ولم تتطابق مع أكثر من منشأة مختلفة. لا يستخدم السكربت أقرب مركز أو إزاحة تقديرية.
|
||||
|
||||
تشرح مواصفات OSM معنى [وسم `entrance`](https://wiki.openstreetmap.org/wiki/Key:entrance)، بما فيه `main` و`secondary` و`service`، ومعنى [وسم `barrier=gate`](https://wiki.openstreetmap.org/wiki/Tag:barrier%3Dgate)، ووسم [`routing:entrance`](https://wiki.openstreetmap.org/wiki/Key:routing:entrance) الذي يحدد نقطة وصول مفضلة للملاحة. تبقى الوسوم كما وردت في `source_tags` ليتسنى للعميل معرفة الدليل الأصلي.
|
||||
|
||||
## إتاحة البيانات عبر API
|
||||
|
||||
يظهر حقل `gates` في نتيجة البحث، كما تتوفر واجهة مخصصة:
|
||||
|
||||
```http
|
||||
GET /api/geocoding/places/{placeId}/gates
|
||||
x-api-key: <مفتاح العميل>
|
||||
```
|
||||
|
||||
تعيد الواجهة معرّف المكان، والإحداثيات، والاسم العربي/الإنجليزي، ونوع المدخل، وإمكانية الوصول عند توفرها، وحقل `is_main_gate`، ومصدر البيانات، ومعرّف عقدة OSM، والوسوم الأصلية، ورابط العقدة، ووقت آخر رصد. تتضمن الاستجابة إسناد `© OpenStreetMap contributors`.
|
||||
|
||||
## التشغيل والتحديث
|
||||
|
||||
- مهمة تحديث بيانات الخريطة على الخادم تعمل كل عشرة أيام وتشغّل `infrastructure/scripts/update-data.sh`.
|
||||
- بعد تحديث PBF وبناء أسماء الأماكن للدول الإحدى عشرة، يشغّل التحديث `scripts/sync_osm_place_gates.py` على ملف `master_map.osm.pbf` نفسه؛ ثم يمسح ذاكرة البحث.
|
||||
- يستخرج السكربت وسوم الأبواب من PBF الخام لأن استيراد `osm2pgsql` الحالي لا يحتفظ بحقل `entrance` في أعمدة PostGIS القياسية.
|
||||
- يستبدل السكربت صفوف OSM المصدرية عند كل مزامنة، ويحفظ الصفوف القديمة مجهولة المصدر في `place_gates_unverified_archive_20260929` خارج جدول الخدمة. يحتوي الأرشيف على **57,381** صفًا سابقًا. لا تُحذف نسخة الأرشيف من هذا التشغيل.
|
||||
- أزيل استدعاء مولّد الإحداثيات التقديرية من مزامنة الأماكن نصف الشهرية، وحُوّل `scripts/populate_place_gates.py` إلى مدخل توافق يتطلب ملف PBF ويستدعي المزامنة المصدرية.
|
||||
|
||||
## حدود التغطية ومصادر أخرى
|
||||
|
||||
المصدر المستخدم في المزامنة هو OSM. معالم Overture المسماة تساعد على البحث، لكن هذا المسار لا يقرأ منها نقاط أبواب. إذا أضاف مصدر مستقبلي نقاط أبواب مستقلة وموثقة، ينبغي حفظ مصدره ومعرّفه ووسومه بالطريقة نفسها، مع إبقاء بيانات المصدر منفصلة وقابلة للتتبع.
|
||||
|
||||
لا تتوافر حاليًا دلالة كافية لتصنيف معظم البوابات كبوابة إسعاف أو مواقف أو بوابة احتياطية. لذلك لا يعرض النظام هذه التسميات إلا عندما تكون ممثلة صراحةً في وسوم المصدر. رفع التغطية يتطلب تحسين بيانات OSM ميدانيًا أو استخدام مصدر رسمي موثق، ثم سيظهر في المزامنة التالية.
|
||||
|
||||
</div>
|
||||
@@ -54,7 +54,7 @@ MaplibreMap(
|
||||
- **ميزات النظام الداخلية المدعومة هنا:**
|
||||
1. **التطبيع العربي:** يعالج (إ/ا/أ/ة/ه).
|
||||
2. **الاستعلامات النسبية:** يفهم (قرب المستشفى، بجانب البنك).
|
||||
3. **بوابات المجمعات (POI Gates):** للمولات الكبرى، يرجع المحرك إحداثيات (البوابة الرئيسية، بوابة الطوارئ) ضمن مصفوفة `gates`.
|
||||
3. **مداخل المنشآت (POI Gates):** قد يرجع المحرك نقاط مداخل OSM الموثقة للمنشأة ضمن مصفوفة `gates`. لا تُنشأ نقاط تقديرية، ولا توصف البوابة بأنها رئيسية إلا إذا كانت موسومة صراحةً في المصدر.
|
||||
4. **هل تقصد (Did you mean):** إذا كتب المستخدم مصطلحاً خاطئاً بالكامل ("السمساني") وعاد بـ 0 نتائج، يقوم المحرك ببحث `KNN` لإرجاع اقترح للتصحيح.
|
||||
|
||||
**الاستخدام في Flutter:**
|
||||
@@ -62,7 +62,7 @@ MaplibreMap(
|
||||
```dart
|
||||
controller.animateCamera(CameraUpdate.newLatLng(LatLng(lat, lng)));
|
||||
```
|
||||
وإذا كان الرد يحتوي على `gates`، يمكن إظهار نافذة منبثقة للسائق: *"أي بوابة تقصد؟"*.
|
||||
وإذا كان الرد يحتوي على `gates`، يمكن إظهار نافذة منبثقة للسائق لاختيار أحد المداخل الموثقة: *"أي مدخل تقصد؟"*. عند غيابها لا يعرض التطبيق اختيار بوابة غير موثقة.
|
||||
|
||||
---
|
||||
|
||||
@@ -117,8 +117,10 @@ await controller.addLineLayer(
|
||||
2. **البحث:**
|
||||
يكتب الراكب في صندوق البحث ⬅️ يتم مناداة `/autocomplete` لعرض الاقتراحات فوراً.
|
||||
3. **الاختيار:**
|
||||
يختار الراكب (مثلاً: سيتي مول) ⬅️ يتم مناداة `/search` ⬅️ الخادم يرجع البوابات المتاحة للمول ⬅️ الراكب يختار "البوابة الرئيسية".
|
||||
يختار الراكب (مثلاً: سيتي مول) ⬅️ يتم مناداة `/search` ⬅️ الخادم يرجع المداخل الموثقة المتاحة إن وجدت؛ وقد لا تتوفر نقاط أبواب للمنشأة.
|
||||
4. **طلب الرحلة:**
|
||||
التطبيق يرسل موقع الراكب وموقع البوابة إلى `/api/maps/route` ⬅️ الخادم يحسب المسار، يطبق خوارزمية الازدحام المروري، ويرجع خط سير (Polyline) ⬅️ الفلاتر يفك تشفير الخط ويرسمه على الخريطة باللون الأزرق.
|
||||
عند اختيار مدخل موثق، يرسل التطبيق موقع الراكب وإحداثيات ذلك المدخل إلى `/api/maps/route` ⬅️ الخادم يحسب المسار ويرجع خط سير (Polyline) ⬅️ تطبيق Flutter يفك تشفير الخط ويرسمه على الخريطة.
|
||||
|
||||
لحقول البوابات، المصدر، التغطية والجدولة راجع [توثيق أبواب ومداخل المنشآت](PLACE_GATES_COVERAGE_AR.md).
|
||||
|
||||
بذلك نكون قد غطينا البنية المعمارية الكاملة بأدق تفاصيلها من السيرفر وحتى واجهة التطبيق! 🚀
|
||||
|
||||
+15
-15
@@ -21,8 +21,8 @@
|
||||
4. **الاستعلامات النسبية (Relative Queries):**
|
||||
فهم طبيعة الوصف في الشارع الأردني والعربي. عندما يبحث المستخدم عن `"قرب مستشفى التخصصي"`, يقوم النظام بفلترة كلمة "قرب"، ويبحث عن المستشفى، ويعيد إحداثياته الدقيقة تحت اسم "قرب مستشفى التخصصي".
|
||||
|
||||
5. **بوابات المجمعات (POI Gates Clustering):**
|
||||
لا توجيه إلى مراكز المباني بعد اليوم! الأماكن الكبرى مثل المولات تعود بقائمة من البوابات الفعلية (مثال: البوابة الرئيسية، بوابة كارفور) لتوجيه السائق بدقة متناهية.
|
||||
5. **مداخل المنشآت (POI Gates):**
|
||||
قد تعود نتيجة المنشأة بمداخل موثقة من عقد OpenStreetMap الفعلية. لا ينشئ النظام بوابات افتراضية؛ وتكون `is_main_gate=true` فقط عندما يوسم المصدر المدخل صراحةً بـ `entrance=main`. راجع [توثيق التغطية والمصدر](PLACE_GATES_COVERAGE_AR.md).
|
||||
|
||||
6. **هل تقصد؟ (Safety Net & Spell Checker):**
|
||||
محرك تعويض الأخطاء (Fallback). إذا أدخل المستخدم مصطلحاً مستحيلاً وأسفر عن 0 نتائج، يتدخل استعلام `KNN` لاقتراح أقرب مصطلح منطقي أو تصحيحه تلقائياً.
|
||||
@@ -60,22 +60,22 @@
|
||||
"distance_km": "3.50",
|
||||
"full_address": "شارع الملك عبدالله، عمان",
|
||||
"totalScore": 0.95,
|
||||
"gates": [
|
||||
{
|
||||
"name_ar": "البوابة الرئيسية",
|
||||
"name_en": "Main Gate",
|
||||
"latitude": 31.9806,
|
||||
"longitude": 35.8380,
|
||||
"is_main_gate": true
|
||||
}
|
||||
]
|
||||
"gates": []
|
||||
}
|
||||
],
|
||||
"did_you_mean": null
|
||||
}
|
||||
```
|
||||
|
||||
### 2. الإكمال التلقائي (Autocomplete)
|
||||
قد تحتوي النتيجة على `gates` إذا وجدت نقاط أبواب/مداخل موثقة ومطابقة للمنشأة؛ وقد تكون المصفوفة فارغة. لا يدل غيابها على عدم وجود مدخل في الواقع، بل على عدم توفر نقطة مصدر مطابقة.
|
||||
|
||||
### 2. مداخل منشأة محددة
|
||||
|
||||
**الرابط:** `GET /api/geocoding/places/{placeId}/gates`
|
||||
|
||||
يتطلب مفتاح API. يعيد المداخل المسجلة للمعلم، مع الإحداثيات ونوع المدخل ووسوم المصدر ومعرّف عقدة OSM ورابطها وإسناد `© OpenStreetMap contributors`.
|
||||
|
||||
### 3. الإكمال التلقائي (Autocomplete)
|
||||
مخصص لتقديم اقتراحات سريعة جداً أثناء طباعة المستخدم في مربع البحث.
|
||||
|
||||
**الرابط:** `GET /api/geocoding/autocomplete`
|
||||
@@ -107,8 +107,8 @@
|
||||
عبارة عن `Materialized View` في PostgreSQL يجمع بيانات (الأردن، سوريا، مصر، و OpenStreetMap) في جدول واحد سريع جداً.
|
||||
- **pg_trgm:**
|
||||
تقنية في قاعدة البيانات تستخدم (Trigrams) لتحطيم الكلمات إلى مقاطع من 3 أحرف ومقارنتها بدقة رهيبة للتغلب على الأخطاء الإملائية.
|
||||
- **تحديثات شعبية الأماكن (Future Sero Trips Sync):**
|
||||
المحرك مجهز لاستقبال بيانات رحلات السائقين وتحديث نقاط `popularity_score` واستنتاج بوابات المجمعات تلقائياً.
|
||||
- **مداخل المنشآت:**
|
||||
تُحدّث من نقاط OSM الفعلية عند تشغيل مزامنة الخريطة كل عشرة أيام. تحفظ معرّفات المصدر والوسوم الأصلية، ولا تستنتج إحداثيات أو تصنيفات غير موجودة في المصدر. انظر [توثيق التغطية والتشغيل](PLACE_GATES_COVERAGE_AR.md).
|
||||
|
||||
---
|
||||
**المستند محدث بتاريخ:** يوليو 2026
|
||||
**المستند محدث بتاريخ:** سبتمبر 2026
|
||||
|
||||
Reference in New Issue
Block a user