Skip to main content

پیاده‌سازی فنی داده‌های مکانی

این سند نحوه پیاده‌سازی استاندارد تعریف‌شده در مستند داده‌های مکانی را توضیح می‌دهد.

در این سند تمرکز روی:

  • Migration
  • Validation
  • Indexing
  • Querying
  • Performance
  • Multi-Database Support

است.


پشتیبانی دیتابیس

Regionalization از قابلیت‌های Spatial دیتابیس‌های زیر پشتیبانی می‌کند:

DatabaseSpatial Support
PostgreSQLPostGIS
MySQL 8+Native Spatial Types
MariaDB 10.6+Native Spatial Types
SQL ServerGeometry / Geography
warning

در 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 ایجاد کنید.

نوع ایندکس به دیتابیس وابسته است:

DatabaseIndex Type
PostgreSQLGiST
MySQLSPATIAL INDEX
MariaDBSPATIAL INDEX
SQL ServerSPATIAL 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
);

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 بدون SRIDGeometry با 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