परिचय: कभी-कभी, आपको अपने एप्लिकेशन के भीतर भू-स्थानिक कार्य करने की आवश्यकता पड़ सकती है, जैसे कि उपयोगकर्ता स्थानों को मैप करना या भौगोलिक डेटा का विश्लेषण करना। इन कार्यों के लिए कई भाषा-विशिष्ट लाइब्रेरी उपलब्ध हैं, जैसे कि GDAL, Shapely और Python के लिए Geopandas। वैकल्पिक रूप से, भू-स्थानिक कार्यक्षमता को डेटाबेस के माध्यम से क्रियान्वित किया जा सकता है; उदाहरण के लिए, आप PostgreSQL जैसे रिलेशनल डेटाबेस के साथ PostGIS एक्सटेंशन का उपयोग कर सकते हैं, या Azure CosmosDB जैसे वितरित डेटाबेस में स्थानिक डेटा प्रकारों के लिए मूल समर्थन का लाभ उठा सकते हैं। हालाँकि, यदि आपका बैकएंड स्टोरेज, जैसे कि रेडिस या गूगल स्पैनर, स्थानिक प्रश्नों का मूल रूप से समर्थन नहीं करता है और आपको बड़े पैमाने पर भू-स्थानिक प्रश्नों को संभालने की आवश्यकता है, तो यह लेख आपके लिए तैयार किया गया है। मेरे पास क्या विकल्प हैं? आप स्थानिक डेटा को संभालने के लिए हमेशा एक और माइक्रोसर्विस बना सकते हैं, लेकिन इस विकल्प में अक्सर एक अतिरिक्त एप्लिकेशन को बनाए रखने का ओवरहेड शामिल होता है। एक अन्य दृष्टिकोण S2 और H3 जैसी जियो-इंडेक्सिंग लाइब्रेरी का उपयोग करना है। Google द्वारा विकसित S2, हिल्बर्ट वक्र पर आधारित है, जबकि Uber द्वारा विकसित H3, एक जियोडेसिक असतत वैश्विक ग्रिड प्रणाली पर आधारित है। S2 और H3 में कई समानताएँ हैं: दोनों किसी दिए गए क्षेत्र को कोशिकाओं में विभाजित करते हैं और इन कोशिकाओं को अनुक्रमित करने के लिए 64-बिट पूर्णांक का उपयोग करते हैं। हालाँकि, मुख्य अंतर कोशिकाओं के आकार में है; S2 वर्गाकार कोशिकाओं का उपयोग करता है, जबकि H3 षट्भुज आकार की कोशिकाओं का उपयोग करता है। कुछ अनुप्रयोगों के लिए, H3 बेहतर प्रदर्शन प्रदान कर सकता है। हालाँकि, कुल मिलाकर, दोनों में से कोई भी लाइब्रेरी पर्याप्त होनी चाहिए। इस लेख में, हम S2 का उपयोग करेंगे, लेकिन आप H3 का उपयोग करके समान कार्य कर सकते हैं। गूगल S2 लाइब्रेरी की मूल अवधारणाएँ कोशिकाएँ: S2 गोले को कोशिकाओं में विभाजित करता है, जिनमें से प्रत्येक में एक अद्वितीय 64-बिट पहचानकर्ता होता है। सेल स्तर: पदानुक्रम बड़े क्षेत्रों से लेकर छोटे सटीक क्षेत्रों तक, विवरण के विभिन्न स्तरों की अनुमति देता है। प्रत्येक स्तर एक अलग रिज़ॉल्यूशन का प्रतिनिधित्व करता है: स्तर 0: सबसे बड़ी कोशिकाएँ, जो पृथ्वी की सतह के एक महत्वपूर्ण हिस्से को कवर करती हैं। उच्चतर स्तर: कोशिकाओं को क्रमिक रूप से छोटे-छोटे चतुर्थांशों में विभाजित किया जाता है। उदाहरण के लिए, स्तर 1 की प्रत्येक कोशिका को चार स्तर 2 कोशिकाओं में विभाजित किया जाता है, और इसी तरह आगे भी। रिज़ॉल्यूशन और क्षेत्र: उच्च स्तर बेहतर रिज़ॉल्यूशन और छोटे सेल क्षेत्रों के अनुरूप हैं। यह पदानुक्रम अलग-अलग स्तरों पर सटीक अनुक्रमण और क्वेरी करने की अनुमति देता है। नीचे दी गई तालिका विभिन्न कोशिका स्तरों को उनके संगत क्षेत्रों के साथ दर्शाती है। स्तर न्यूनतम क्षेत्र अधिकतम क्षेत्र औसत क्षेत्र इकाइयां कोशिकाओं की संख्या 00 85011012.19 85011012.19 85011012.19 किमी2 6 01 21252753.05 21252753.05 21252753.05 किमी2 24 02 4919708.23 6026521.16 5313188.26 किमी2 96 03 1055377.48 1646455.50 1328297.07 किमी2 384 04 231564.06 413918.15 332074.27 किमी2 1536 05 53798.67 104297.91 83018.57 किमी2 6के 06 12948.81 26113.30 20754.64 किमी2 24के 07 3175.44 6529.09 5188.66 किमी2 98के 08 786.20 1632.45 1297.17 किमी2 393के 09 195.59 408.12 324.29 किमी2 1573के 10 48.78 102.03 81.07 किमी2 6 11 12.18 25.51 20.27 किमी2 25एम 12 3.04 6.38 5.07 किमी2 100 मीटर १३ 0.76 1.59 1.27 किमी2 402एम 14 0.19 0.40 0.32 किमी2 1610एम 15 47520.30 99638.93 79172.67 एम2 6बी 16 11880.08 24909.73 19793.17 एम2 25बी 17 2970.02 6227.43 4948.29 एम2 103बी 18 742.50 1556.86 1237.07 एम2 412बी 19 185.63 389.21 309.27 एम2 1649बी 20 46.41 97.30 77.32 एम2 7टी 21 11.60 24.33 19.33 एम2 26टी 22 2.90 6.08 4.83 एम2 105टी 23 0.73 1.52 1.21 एम2 422टी 24 0.18 0.38 0.30 एम2 1689टी 25 453.19 950.23 755.05 सेमी 2 7ई15 26 113.30 237.56 188.76 सेमी 2 27ई15 27 28.32 59.39 47.19 सेमी 2 108ई15 28 7.08 14.85 11.80 सेमी 2 432ई15 29 1.77 3.71 2.95 सेमी 2 1729ई15 30 0.44 0.93 0.74 सेमी 2 7ई18 दी गई तालिका से यह स्पष्ट है कि आप S2 का उपयोग करके 0.44 cm^2 तक की मैपिंग परिशुद्धता प्राप्त कर सकते हैं। S2 सेल के प्रत्येक वर्ग के भीतर, एक चाइल्ड सेल मौजूद होता है जो एक ही पैरेंट को साझा करता है, जो एक पदानुक्रमित संरचना को दर्शाता है। सेल का स्तर एक स्थिर मान हो सकता है (सभी कोशिकाओं पर समान स्तर लागू होता है) या गतिशील हो सकता है जहाँ S2 तय करता है कि कौन सा रिज़ॉल्यूशन सबसे अच्छा काम करता है। निकटतम पड़ोसियों की गणना आइए एक उदाहरण से शुरू करते हैं। मान लीजिए कि हम एक ऐसा एप्लिकेशन लिख रहे हैं जो सिएटल क्षेत्र के लिए निकटता सेवा जैसी सुविधाएँ प्रदान करता है। हम दिए गए क्षेत्र में कॉफी की दुकानों की एक सूची लौटाना चाहते हैं। इन कार्यों को करने के लिए, हम इस कार्य को 4 उप-कार्यों में विभाजित करेंगे: सिएटल मानचित्र लोड हो रहा है सिएटल मानचित्र पर S2 कोशिकाओं को देखें डेटाबेस में कुछ कॉफ़ी शॉप के स्थान संग्रहीत करें निकटतम कॉफी शॉप के लिए पूछताछ सिएटल मानचित्र लोड हो रहा है Google मानचित्र लोड करने के लिए, हम gmplot लाइब्रेरी का उपयोग करेंगे। इस लाइब्रेरी को लोड करने के लिए Google मैप्स API कुंजी की आवश्यकता होती है। API कुंजी जनरेट करने के लिए, गए निर्देशों का पालन करें। यहाँ दिए import gmplot import const # plot seattle with zoom level 13 gmap = gmplot.GoogleMapPlotter(47.6061, -122.3328, 13, apikey=const.API_KEY) # Draw the map to an HTML file: gmap.draw('map.html') उपरोक्त कोड एक map.html फ़ाइल उत्पन्न करता है जैसा कि नीचे दिखाया गया है: सिएटल मानचित्र पर S2 कोशिकाओं को देखें अब जब हमारे पास मानचित्र है, तो आइए मानचित्रों के लिए कुछ S2 कोशिकाएं बनाएं: from s2 import * import gmplot # plot seattle with zoom level 13 gmap = gmplot.GoogleMapPlotter(47.6061, -122.3328, 13, apikey=const.API_KEY) areatobeplotted = [ (47.64395531736767,-122.43597221319135), (47.51369277846956,-122.43597221319135), (47.51369277846956,-122.24156866779164), (47.64395531736767,-122.24156866779164), (47.64395531736767,-122.43597221319135) ] region_rect = S2LatLngRect( S2LatLng.FromDegrees(47.51369277846956,-122.43597221319135), S2LatLng.FromDegrees(47.64395531736767, -122.24156866779164)) coverer = S2RegionCoverer() coverer.set_min_level(8) coverer.set_max_level(15) covering = coverer.GetCovering(region_rect) geoms = 0 for cellid in covering: new_cell = S2Cell(cellid) vertices = [] for i in range(0, 4): vertex = new_cell.GetVertex(i) latlng = S2LatLng(vertex) vertices.append((latlng.lat().degrees(), latlng.lng().degrees())) gmap.polygon(*zip(*vertices), face_color='pink', edge_color='cornflowerblue', edge_width=5) geoms+=1 gmap.polygon(*zip(*areatobeplotted), face_color='red', edge_color='green', edge_width=5) print(f"Total Geometries: {geoms}") gmap.draw('/tmp/map.html') Output: Total Geometries: 273 ऊपर दिए गए कोड में, हम सबसे पहले सिएटल क्षेत्र के चारों ओर Google मैप प्लॉटर को केन्द्रित करते हैं। में, हम क्षेत्र कवरर को न्यूनतम स्तर 8 और अधिकतम स्तर 15 के बीच गतिशील स्तर रखने के लिए आरंभ करते हैं। यह S2 को सभी कोशिकाओं को सर्वोत्तम फिट के लिए विशिष्ट सेल आकारों में गतिशील रूप से फ़िट करने की अनुमति देता है। विधि सिएटल क्षेत्र के चारों ओर एक आयत के लिए कवरिंग लौटाती है। S2RegionCoverer GetCovering फिर, हम प्रत्येक सेल पर पुनरावृत्ति करते हैं, कोशिकाओं के लिए शीर्षों की गणना करते हैं और उन्हें मानचित्र पर प्लॉट करते हैं। हम उत्पन्न कोशिकाओं की संख्या को लगभग 273 तक रखते हैं। अंत में, हम इनपुट आयत को लाल रंग में प्लॉट करते हैं। यह कोड सिएटल मानचित्र पर पर S2 कोशिकाओं को प्लॉट करेगा, जैसा कि नीचे दिखाया गया है: /tmp/map.html डेटाबेस में कुछ कॉफ़ी शॉप के स्थान संग्रहीत करें आइए कॉफी शॉप्स का डेटाबेस उनके S2 सेल पहचानकर्ताओं के साथ बनाएं। आप इन सेल को अपनी पसंद के किसी भी डेटाबेस में स्टोर कर सकते हैं। इस ट्यूटोरियल के लिए, हम SQLite डेटा डेटाबेस का उपयोग करेंगे। नीचे दिए गए कोड सैंपल में, हम 3 फ़ील्ड , और के साथ टेबल बनाने के लिए SQLite डेटाबेस से कनेक्ट करते हैं। Id name cell_id CoffeeShops पिछले उदाहरण की तरह, हम कोशिकाओं की गणना करने के लिए उपयोग करते हैं लेकिन इस बार, हम बिंदुओं को प्लॉट करने के लिए एक निश्चित स्तर का उपयोग करते हैं। अंत में, गणना की गई आईडी को एक स्ट्रिंग में परिवर्तित किया जाता है और डेटाबेस में संग्रहीत किया जाता है। S2RegionCoverer import sqlite3 from s2 import S2CellId,S2LatLng,S2RegionCoverer # Connect to SQLite database conn = sqlite3.connect('/tmp/sqlite_cells.db') cursor = conn.cursor() # Create a table to store cell IDs cursor.execute('''CREATE TABLE IF NOT EXISTS CoffeeShops ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, cell_id TEXT )''') coverer = S2RegionCoverer() # Function to generate S2 cell ID for a given latitude and longitude def generate_cell_id(latitude, longitude, level=16): cell=S2CellId(S2LatLng.FromDegrees(latitude, longitude)) return str(cell.parent(level)) # Function to insert cell IDs into the database def insert_cell_ids(name,lat,lng): cell_id = generate_cell_id(lat, lng) cursor.execute("INSERT INTO CoffeeShops (name, cell_id) VALUES (?, ?)", (name, cell_id)) conn.commit() # Insert cell IDs into the database insert_cell_ids("Overcast Coffee", 47.616656277302155, -122.31156460382837) insert_cell_ids("Seattle Sunshine", 47.67366852914391, -122.29051997415843) insert_cell_ids("Sip House", 47.6682364706238, -122.31328618043693) insert_cell_ids("Victoria Coffee",47.624408595334536, -122.3117362652041) # Close connection conn.close() इस बिंदु पर, हमारे पास एक डेटाबेस है जो कॉफी शॉप्स को उनके सेल आईडी के साथ संग्रहीत करता है, जो सेल स्तर के लिए चयनित रिज़ॉल्यूशन द्वारा निर्धारित होता है। निकटतम कॉफी शॉप के लिए पूछताछ अंत में, आइए यूनिवर्सिटी डिस्ट्रिक्ट क्षेत्र में कॉफी की दुकानों के बारे में जानकारी प्राप्त करें। import sqlite3 from s2 import S2RegionCoverer,S2LatLngRect, S2LatLng # Connect to SQLite database conn = sqlite3.connect('/tmp/sqlite_cells.db') cursor = conn.cursor() # Function to query database for cells intersecting with the given polygon def query_intersecting_cells(start_x,start_y,end_x,end_y): # Create S2RegionCoverer region_rect = S2LatLngRect( S2LatLng.FromDegrees(start_x,start_y), S2LatLng.FromDegrees(end_x,end_y)) coverer = S2RegionCoverer() coverer.set_min_level(8) coverer.set_max_level(15) covering = coverer.GetCovering(region_rect) # Query for intersecting cells intersecting_cells = set() for cell_id in covering: cursor.execute("SELECT name FROM CoffeeShops WHERE cell_id >= ? and cell_id<=?", (str(cell_id.range_min()),str(cell_id.range_max()),)) intersecting_cells.update(cursor.fetchall()) return intersecting_cells # Query for intersecting cells intersecting_cells = query_intersecting_cells(47.6527847,-122.3286438,47.6782181, -122.2797203) # Print intersecting cells print("Intersecting cells:") for cell_id in intersecting_cells: print(cell_id[0]) # Close connection conn.close() Output: Intersecting cells: Sip House Seattle Sunshine नीचे कोशिकाओं का एक दृश्य प्रतिनिधित्व है। संक्षिप्तता बनाए रखने के लिए, नीचे दिए गए विज़ुअलाइज़ेशन कोड को नहीं जोड़ा गया है। चूंकि सभी चाइल्ड और पैरेंट सेल एक उपसर्ग साझा करते हैं, इसलिए हम उन दो मानों के बीच सभी सेल प्राप्त करने के लिए न्यूनतम और अधिकतम के बीच सेल श्रेणियों के लिए क्वेरी कर सकते हैं। हमारे उदाहरण में, हम कॉफी शॉप को क्वेरी करने के लिए उसी सिद्धांत का उपयोग करते हैं निष्कर्ष: इस लेख में, हमने दिखाया है कि भू-स्थानिक डेटा को संग्रहीत करने और क्वेरी करने के लिए जियो-इंडेक्सिंग का उपयोग कैसे करें जो भू-स्थानिक क्वेरी का समर्थन नहीं करते हैं। इसे कई उपयोग मामलों में आगे बढ़ाया जा सकता है जैसे कि 2 बिंदुओं के बीच रूटिंग की गणना करना या निकटतम पड़ोसियों को प्राप्त करना। आम तौर पर, जियो-इंडेक्स्ड डेटाबेस क्वेरी के लिए, आपको डेटा पर कुछ अतिरिक्त पोस्ट-प्रोसेसिंग करनी होगी। क्वेरी और पोस्ट-प्रोसेसिंग लॉजिक पर सावधानीपूर्वक विचार करना आवश्यक है ताकि यह सुनिश्चित हो सके कि हम नोड पर अधिक बोझ न डालें। संदर्भ: गूगल मैप प्लॉटर - https://github.com/gmplot/gmplot/wiki/GoogleMapPlotter S2 डेवलपर गाइड - http://s2geometry.io/devguide/ SQLite - https://docs.python.org/3/library/sqlite3.html Azure Cosmos DB भू-स्थानिक - https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/query/geospatial?tabs=javascript जीडीएएल - https://gdal.org/index.html शेपली- https://shapely.readthedocs.io/en/stable/manual.html जिओपांडास - https://geopandas.org पॉसजीस - https://postgis.net/ गूगल स्पैनर - https://cloud.google.com/spanner?hl=en रेडिस - https://redis.io/