پریسا رشیدی نژاد
پریسا رشیدی نژاد
خواندن ۴ دقیقه·۴ سال پیش

تفاوت geometry و geography در Postgres

دستگاه مختصات دکارتی و کروی
دستگاه مختصات دکارتی و کروی

تا حالا شده دیتایی رو بخواین در پایگاه داده ذخیره کنید که شامل مختصات جغرافیایی باشه؟

از بین data type های معتبر که برای ذخیره کردن دیتای جغرافیایی در پایگاه داده ها ایجاد شدن، شاید دونستن فرق بین geography و geometry بتونه کار شما رو کمی راحت تر بکنه.

تفاوت این دو به طور خلاصه، دستگاه مختصاتی هست که برای محاسبات استفاده میکنن. وقتی نوع داده رو geometry تعریف میکنیم محاسبات روی دستگاه مختصات کروی (Spherical coordinate system) و برحسب زاویه انجام میشه. اما وقتی از نوع داده ی geography استفاده میکنیم، محاسبات روی دستگاه دکارتی و بر حسب متره! مواقعی که میخوایم مقایسه ایی انجام بدیم مثل مقایسه مساحت چند ضلعی ها یا فاصله ی چندین نقطه از هم، اگه خروجی مون زاویه باشه کارمون به مراتب سخت تر از وقتی هست که خروجی مون متر باشه.




برای روشن تر شدن موضوع، من میخوام با استفاده از تابع ST_Distance فاصله ی دو نقطه ی مترو شهید بهشتی و شرکت سان که با دایره قرمز مشخص شدن، رو محاسبه کنم.

فاصله ی شرکت سان تا مترو شهید بهشتی
فاصله ی شرکت سان تا مترو شهید بهشتی
  • در حالت اول از نوع داده geometry استفاده میکنم، که گفتیم خروجی رو برحسب زاویه میده:
SELECT ST_Distance( ST_GeometryFromText('POINT(51.427141 35.730271)', 4326), -- مترو شهید بهشتی ST_GeometryFromText('POINT(51.422646 35.732535)', 4326) --شرکت سان ); -- output : 0.00503296344115198
  • در حالت دوم از نوع داده geography استفاده میکنم:
SELECT ST_Distance (ST_GeographyFromText('POINT(51.427141 35.730271)'), -- مترو شهید بهشتی ST_GeographyFromText('POINT(51.422646 35.732535)') --شرکت سان ); -- output: 477.98556905

پیداست که فاصله ی این دو نقطه ۴۷۷ متره! درحالی که در حالت اول از عدد 0.0050329 که خروجی کوئری مون بود این رو متوجه نمی شدیم.


چه طور geometry رو به geography تبدیل کنیم؟

برای اینکار اول باید مقدار EPSG رو با استفاده از تابع ST_Transform برابر ۴۳۲۶ کنیم.

SELECT Geography(ST_Transform(geom,4326)) AS geog FROM table_name;

چه طور geography رو به geometry تبدیل کنیم؟

SELECT geography_field:: geometry AS geometry FROM table_name;

برای فیلد geography چه طور ایندکس جغرافیایی بذاریم؟

CREATE INDEX test_geography_geog_gix ON table_name USING GIST (geog);

چه مواقعی مجبوریم از نوع داده geometry استفاده کنیم؟

اگه از نوع داده geometry استفاده کنیم،به دلیل کروی بودن دستگاه مختصات، ممکنه محاسبات و تحلیل ها پیچیده تر و کندتر انجام بشن. اما وقتی پراکندگی دیتا به وسعت کره ی زمین هست و شامل کشورها و قاره های مختلف میشه مجبوریم حتما از geometry استفاده کنیم.اما اگه دیتامون مختص فقط یک کشور هست استفاده از geography مشکلی رو ایجاد نمیکنه.

بررسی یک مشکل:

اگه فاصله ی دو شهر Tokyo و Los Angeles رو در دستگاه دکارتی یعنی بر اساس geography حساب کنیم(خط صورتی رنگ) ، به نتیجه ی اشتباهی منجر میشه.نتیجه ی درست و واقعی وقتی حاصل میشه در دستگاه مختصات کروی(خط قرمز رنگ) باشیم.

یه مثال از حالتی که نمیتونیم از نوع داده geography استفاده کنیم.
یه مثال از حالتی که نمیتونیم از نوع داده geography استفاده کنیم.
SELECT ST_Distance( ST_GeometryFromText('Point(-118.4079 33.9434)'), -- LAX ST_GeometryFromText('Point(139.733 35.567)')) -- NRT (Tokyo/Narita) AS geometry_distance, ST_Distance( ST_GeographyFromText('Point(-118.4079 33.9434)'), -- LAX ST_GeographyFromText('Point(139.733 35.567)')) -- NRT (Tokyo/Narita) AS geography_distance; --output: geometry_distance : 258.146005837336 (correct answer) geography_distance : 8833954.76996256 (wrong answer)

تصور کنید یه هواپیما بخواد از شهر Tokyo به Los Angeles بره، قطعا مسیر صورتی که در دستگاه دکارتی هست رو انتخاب نمیکنه :)

یکی از محدودیت هایی که استفاده از نوع داده ی geography داره، فانکشن های محدودی هست که این نوع داده رو پشتیبانی میکنن.

  • ST_AsText(geography) returns text
  • ST_GeographyFromText(text) returns geography
  • ST_AsBinary(geography) returns bytea
  • ST_GeogFromWKB(bytea) returns geography
  • ST_AsSVG(geography) returns text
  • ST_AsGML(geography) returns text
  • ST_AsKML(geography) returns text
  • ST_AsGeoJson(geography) returns text
  • ST_Distance(geography, geography) returns double
  • ST_DWithin(geography, geography, float8) returns boolean
  • ST_Area(geography) returns double
  • ST_Length(geography) returns double
  • ST_Covers(geography, geography) returns boolean
  • ST_CoveredBy(geography, geography) returns boolean
  • ST_Intersects(geography, geography) returns boolean
  • ST_Buffer(geography, float8) returns geography 1
  • ST_Intersection(geography, geography) returns geography 1

اگه این مطلب براتون جالب بود و دوست دارین در موردش بیشتر بدونین، پیشنهاد می کنم این لینک رو حتما مطالعه کنید.


نرم افزارپست گرسمهندسی دادهمهندسی نرم افزارنقشه
یه همسر، یه مادر، یه مهندس داده در map.ir
شاید از این پست‌ها خوشتان بیاید