پیادهسازی فنی دادههای مکانی
این سند نحوه پیادهسازی استاندارد تعریفشده در مستند دادههای مکانی را توضیح میدهد.
در این سند تمرکز روی:
- Migration
- Validation
- Indexing
- Querying
- Performance
- Multi-Database Support
است.
پشتیبانی دیتابیس
Regionalization از قابلیتهای Spatial دیتابیسهای زیر پشتیبانی میکند:
| Database | Spatial Support |
|---|---|
| PostgreSQL | PostGIS |
| MySQL 8+ | Native Spatial Types |
| MariaDB 10.6+ | Native Spatial Types |
| SQL Server | Geometry / Geography |
در PostgreSQL نصب PostGIS الزامی است.
CREATE EXTENSION IF NOT EXISTS postgis;
ساختار پیشنهادی Schema
نقطه
CREATE TABLE places (
id BIGSERIAL PRIMARY KEY,
location geometry(Point, 4326) NOT NULL
);
چندضلعی
CREATE TABLE districts (
id BIGSERIAL PRIMARY KEY,
boundary geometry(MultiPolygon, 4326) NOT NULL
);
چند فیلد مکانی
CREATE TABLE cities (
id BIGSERIAL PRIMARY KEY,
center geometry(Point, 4326),
boundary geometry(MultiPolygon, 4326)
);
ایندکس مکانی
همیشه روی ستونهای مکانی Spatial Index ایجاد کنید.
نوع ایندکس به دیتابیس وابسته است:
| Database | Index Type |
|---|---|
| PostgreSQL | GiST |
| MySQL | SPATIAL INDEX |
| MariaDB | SPATIAL INDEX |
| SQL Server | SPATIAL INDEX |
PostgreSQL
CREATE INDEX idx_city_center
ON cities
USING GIST (center);
MySQL / MariaDB
CREATE SPATIAL INDEX idx_city_center
ON cities(center);
SQL Server
CREATE SPATIAL INDEX idx_city_center
ON cities(center);
قرارداد ورودی
دادههای ورودی میتوانند به یکی از شکلهای زیر باشند:
Latitude / Longitude
{
"latitude": 35.6892,
"longitude": 51.389
}
UTM
{
"x": 535212,
"y": 3958744,
"zone": 39
}
GeoJSON
{
"type": "Point",
"coordinates": [51.389, 35.6892]
}
تمام این ورودیها باید پیش از ذخیرهسازی به Geometry تبدیل شوند.
Validation
Latitude / Longitude
latitude:
- required
- numeric
- between -90 and 90
longitude:
- required
- numeric
- between -180 and 180
UTM
x:
- required
- numeric
y:
- required
- numeric
zone:
- required
- integer
GeoJSON
اعتبارسنجی باید شامل موارد زیر باشد:
- ساختار معتبر JSON
- نوع هندسه معتبر
- مختصات معتبر
- SRID مشخص
تبدیل مختصات
Lat/Lon → Geometry
نمونه PostgreSQL:
ST_SetSRID(
ST_MakePoint(longitude, latitude),
4326
)
UTM → WGS84
نمونه PostgreSQL:
ST_Transform(
ST_SetSRID(
ST_MakePoint(x, y),
32639
),
4326
)
GeoJSON → Geometry
ST_SetSRID(
ST_GeomFromGeoJSON(geojson::text),
4326
)
مهاجرت دادههای قدیمی
از latitude / longitude
UPDATE places
SET location =
ST_SetSRID(
ST_MakePoint(longitude, latitude),
4326
)
WHERE latitude IS NOT NULL
AND longitude IS NOT NULL;
از UTM
UPDATE places
SET location =
ST_Transform(
ST_SetSRID(
ST_MakePoint(x, y),
32639
),
4326
);
از GeoJSON
UPDATE places
SET location =
ST_SetSRID(
ST_GeomFromGeoJSON(geojson_column::text),
4326
);
نمایش GeoJSON در API
GeoJSON نباید منبع اصلی حقیقت باشد.
منبع اصلی همیشه Geometry است.
GeoJSON میتواند:
- در Query تولید شود
- در Accessor تولید شود
- در Generated Column ذخیره شود (در صورت پشتیبانی دیتابیس)
نمونه PostgreSQL:
SELECT ST_AsGeoJSON(location)
FROM places;
Query های متداول
نمونههای این بخش بر پایه PostgreSQL/PostGIS هستند.
Bounding Box
SELECT *
FROM places
WHERE location &&
ST_MakeEnvelope(
51.2,
35.5,
51.6,
35.9,
4326
);
Nearby Search
SELECT *,
ST_Distance(
location::geography,
ST_SetSRID(
ST_MakePoint(51.38,35.69),
4326
)::geography
) AS distance_m
FROM places
WHERE ST_DWithin(
location::geography,
ST_SetSRID(
ST_MakePoint(51.38,35.69),
4326
)::geography,
5000
)
ORDER BY distance_m;
Point In Polygon
SELECT *
FROM districts
WHERE ST_Contains(
boundary,
ST_SetSRID(
ST_MakePoint(51.38,35.69),
4326
)
);
Intersects
SELECT *
FROM districts
WHERE ST_Intersects(
boundary,
:geometry
);
Performance
Spatial Query بدون Spatial Index در عمل قابل استفاده نیست.
قبل از انتشار Production حتماً Query Plan بررسی شود.
PostgreSQL
EXPLAIN ANALYZE
SELECT *
FROM places
WHERE location &&
ST_MakeEnvelope(
51.2,
35.5,
51.6,
35.9,
4326
);
انتظار:
Index Scan
اگر نتیجه:
Seq Scan
باشد، معمولاً یکی از مشکلات زیر وجود دارد:
- Index ساخته نشده است
- Query از Index استفاده نمیکند
- حجم داده برای Planner کافی نیست
آنتیپترنها
| ❌ اشتباه | ✅ درست |
|---|---|
| نگهداری GeoJSON بهعنوان منبع اصلی | Geometry بهعنوان منبع اصلی |
| کوئری روی JSON خام | کوئری روی Geometry |
| فاصله روی Geometry بدون تبدیل به Geography | استفاده از Geography برای فاصله بر حسب متر |
| Geometry بدون SRID | Geometry با SRID مشخص |
| Migration بدون Spatial Index | ایجاد Spatial Index |
| اجرای Contains / Distance / Intersects در PHP | اجرای Spatial Query در دیتابیس |
| نگهداری latitude و longitude بهعنوان منبع اصلی | تبدیل به Geometry و استفاده از یک منبع حقیقت |
چکلیست پروژه جدید
- Spatial Support فعال است
- ستون Geometry ایجاد شده است
- SRID مشخص شده است
- Spatial Index ایجاد شده است
- Validation ورودیها انجام میشود
- Geometry منبع اصلی حقیقت است
- API از Geometry تولید میشود
- Query Plan بررسی شده است
چکلیست مهاجرت پروژه موجود
- ایجاد ستون Geometry
- انتقال دادههای قدیمی
- ساخت Spatial Index
- بازنویسی Queryها
- حذف وابستگی به JSON خام
- تست عملکرد
- تست صحت دادهها
منابع
- دادههای مکانی
- PostgreSQL PostGIS Documentation
- MySQL Spatial Documentation
- MariaDB Spatial Documentation
- SQL Server Spatial Documentation