paint-brush
CBS Dışı Veritabanlarında CBS Hesaplamaları Nasıl Yapılır?ile@joellopes
1,662 okumalar
1,662 okumalar

CBS Dışı Veritabanlarında CBS Hesaplamaları Nasıl Yapılır?

ile Joel Lopes9m2024/06/15
Read on Terminal Reader

Çok uzun; Okumak

Arka uç depolama alanınız uzamsal sorguları yerel olarak desteklemiyorsa bu makale sizin için özel olarak hazırlanmıştır. Uzamsal verileri işlemek için her zaman başka bir mikro hizmet oluşturabilirsiniz, ancak bu seçenek genellikle ek bir uygulamanın bakımını yapma yükünü içerir. Diğer bir yaklaşım ise S2 ve H3 gibi coğrafi indeksleme kütüphanelerini kullanmaktır. S2, küreyi her biri benzersiz 64 bit tanımlayıcıya sahip hücrelere böler. Daha yüksek seviyeler daha iyi çözünürlüklere ve daha küçük hücre alanlarına karşılık gelir.
featured image - CBS Dışı Veritabanlarında CBS Hesaplamaları Nasıl Yapılır?
Joel Lopes HackerNoon profile picture

Giriiş:

Bazen uygulamanızda kullanıcı konumlarını haritalamak veya coğrafi verileri analiz etmek gibi jeo-uzamsal işlevleri gerçekleştirme ihtiyacıyla karşılaşabilirsiniz. Bu görevler için GDAL, Shapely ve Python için Geopandas gibi çok sayıda dile özgü kitaplık mevcuttur.


Alternatif olarak, jeo-uzamsal işlevsellik veritabanları aracılığıyla uygulanabilir; örneğin, PostGIS uzantısını PostgreSQL gibi ilişkisel bir veritabanıyla kullanabilir veya Azure CosmosDB gibi dağıtılmış bir veritabanındaki uzamsal veri türleri için yerel destekten yararlanabilirsiniz.


Ancak Redis veya Google Spanner gibi arka uç depolama alanınız uzamsal sorguları yerel olarak desteklemiyorsa ve büyük ölçekli coğrafi uzamsal sorguları işlemeniz gerekiyorsa bu makale sizin için özel olarak hazırlanmıştır.

Seçeneklerim Nelerdir?

Uzamsal verileri işlemek için her zaman başka bir mikro hizmet oluşturabilirsiniz, ancak bu seçenek genellikle ek bir uygulamanın bakımını yapma yükünü içerir. Diğer bir yaklaşım ise S2 ve H3 gibi coğrafi indeksleme kütüphanelerini kullanmaktır. Google tarafından geliştirilen S2, Hilbert eğrisini temel alırken, Uber tarafından geliştirilen H3, jeodezik ayrık küresel ızgara sistemini temel alıyor. S2 ve H3 pek çok benzerliğe sahiptir: her ikisi de belirli bir bölgeyi hücrelere böler ve bu hücreleri indekslemek için 64 bitlik tamsayılar kullanır.


Ancak asıl fark hücrelerin şeklindedir; S2 kare şekilli hücreleri kullanırken H3 altıgen şekilli hücreleri kullanır. Bazı uygulamalar için H3 daha iyi performans sunabilir. Ancak genel olarak her iki kütüphane de yeterli olacaktır. Bu yazımızda S2 kullanacağız ancak benzer işlevleri H3 kullanarak da gerçekleştirebilirsiniz.

Google S2 Kütüphanesinin Temel Kavramları

  • Hücreler: S2, küreyi her biri benzersiz bir 64 bit tanımlayıcıya sahip hücrelere böler.


  • Hücre Düzeyleri: Hiyerarşi, büyük bölgelerden küçük hassas alanlara kadar farklı ayrıntı düzeylerine izin verir. Her seviye farklı bir çözünürlüğü temsil eder:


    • Seviye 0: Dünya yüzeyinin önemli bir bölümünü kaplayan en büyük hücreler.


    • Daha Yüksek Seviyeler: Hücreler giderek daha küçük çeyreklere bölünür. Örneğin, Düzey 1 hücrelerinin her biri dört Düzey 2 hücreye bölünür ve bu böyle devam eder.


    • Çözünürlük ve Alan: Daha yüksek seviyeler, daha iyi çözünürlüklere ve daha küçük hücre alanlarına karşılık gelir. Bu hiyerarşi, farklı ayrıntı düzeylerinde hassas indekslemeye ve sorgulamaya olanak tanır.


Aşağıdaki tablo, karşılık gelen alanlarla birlikte çeşitli hücre seviyelerini göstermektedir.

seviye

minimum alan

maksimum alan

ortalama alan

birimler

Hücre sayısı

00

85011012.19

85011012.19

85011012.19

km2

6

01

21252753.05

21252753.05

21252753.05

km2

24

02

4919708.23

6026521.16

5313188.26

km2

96

03

1055377.48

1646455.50

1328297.07

km2

384

04

231564.06

413918.15

332074.27

km2

1536

05

53798.67

104297.91

83018.57

km2

6K

06

12948.81

26113.30

20754.64

km2

24K

07

3175.44

6529.09

5188.66

km2

98 bin

08

786.20

1632,45

1297.17

km2

393 bin

09

195.59

408.12

324.29

km2

1573K

10

48.78

102.03

81.07

km2

6 milyon

11

12.18

25.51

20.27

km2

25 milyon

12

3.04

6.38

5.07

km2

100 milyon

13

0,76

1.59

1.27

km2

402 milyon

14

0.19

0.40

0,32

km2

1610M

15

47520.30

99638.93

79172.67

m2

6B

16

11880.08

24909.73

19793.17

m2

25B

17

2970.02

6227.43

4948.29

m2

103B

18

742.50

1556,86

1237.07

m2

412B

19

185.63

389.21

309.27

m2

1649B

20

46.41

97.30

77.32

m2

7T

21

11.60

24.33

19.33

m2

26T

22

2.90

6.08

4.83

m2

105 ton

23

0,73

1.52

1.21

m2

422T

24

0,18

0,38

0.30

m2

1689T

25

453.19

950.23

755.05

cm2

7e15

26

113.30

237.56

188.76

cm2

27e15

27

28.32

59.39

47.19

cm2

108e15

28

7.08

14.85

11.80

cm2

432e15

29

1.77

3.71

2.95

cm2

1729e15

30

0,44

0,93

0,74

cm2

7e18



Sağlanan tablodan, S2 kullanarak 0,44 cm^2'ye kadar haritalama hassasiyeti elde edebileceğiniz açıktır. Bir S2 hücresinin her karesinde, aynı ebeveyni paylaşan bir alt hücre bulunur, bu da hiyerarşik bir yapıya işaret eder. Hücrenin düzeyi statik bir değer olabilir (tüm hücrelere uygulanan aynı düzey) veya S2'nin hangi çözünürlüğün en iyi şekilde çalıştığına karar vereceği dinamik olabilir.

En Yakın Komşuların Hesaplanması

Bir örnekle başlayalım. Seattle bölgesi için yakınlık hizmeti benzeri özellikler sağlayan bir uygulama yazdığımızı düşünün. Verilen civardaki kafelerin bir listesini döndürmek istiyoruz. Bu işlemleri gerçekleştirmek için bu görevi 4 alt göreve ayıracağız:


  • Seattle haritası yükleniyor
  • S2 hücrelerini Seattle haritasında görselleştirin
  • Birkaç kahve dükkanı konumunu veritabanında saklayın
  • En yakın kahve dükkanlarını sorgula

Seattle Haritası Yükleniyor

Bir Google haritasını yüklemek için gmplot kütüphanesini kullanırız. Bu kitaplığın yüklenmesi için bir Google Haritalar API anahtarı gerekiyor. API anahtarını oluşturmak için buradaki talimatları izleyin.

 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')


Yukarıdaki kod aşağıda gösterildiği gibi bir harita.html dosyası oluşturur:


S2 Hücrelerini Seattle Haritasında Görselleştirin

Artık haritamız olduğuna göre haritalar için bazı S2 hücreleri çizelim:

 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


Yukarıdaki kodda, öncelikle Google Harita çizicisini Seattle bölgesi etrafında ortalıyoruz. S2RegionCoverer , bölge kapsayıcıyı minimum seviye 8 ile maksimum seviye 15 arasında dinamik seviyelere sahip olacak şekilde başlatırız. Bu, S2'nin en iyi uyum için tüm hücreleri dinamik olarak belirli hücre boyutlarına sığdırmasına olanak tanır. GetCovering yöntemi, Seattle alanının etrafındaki bir dikdörtgenin kaplamasını döndürür.


Daha sonra, her bir hücre üzerinde yinelemeler yaparak hücrelerin köşelerini hesaplıyoruz ve bunları harita üzerinde işaretliyoruz. Oluşturulan hücre sayısını 273 civarında tutuyoruz. Son olarak giriş dikdörtgenini kırmızı renkle çiziyoruz. Bu kod, S2 hücrelerini Seattle haritası üzerinde /tmp/map.html adresinde aşağıda gösterildiği gibi çizecektir:


Birkaç Kahve Dükkanı Konumunu Veritabanında Saklayın

S2 hücre tanımlayıcılarıyla birlikte kahve dükkanlarının bir veritabanını oluşturalım. Bu hücreleri istediğiniz herhangi bir veritabanında saklayabilirsiniz. Bu eğitim için bir SQLite veri veritabanı kullanacağız. Aşağıdaki kod örneğinde Id , name ve cell_id olmak üzere 3 alanlı CoffeeShops tablosu oluşturmak için SQLite veritabanına bağlanıyoruz.


Önceki örneğe benzer şekilde hücreleri hesaplamak için S2RegionCoverer kullanıyoruz ancak bu sefer noktaları çizmek için sabit bir seviye kullanıyoruz. Son olarak hesaplanan kimlik bir dizeye dönüştürülür ve veritabanında saklanır.


 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()


Bu noktada kahvehanelerin hücre seviyesi için seçilen çözünürlüğe göre belirlenen hücre kimlikleriyle birlikte saklandığı bir veritabanına sahibiz.

En Yakın Kahve Dükkanlarını Sorgulayın

Son olarak Üniversite Bölgesi bölgesindeki kafeleri sorgulayalım.


 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

Aşağıda hücrelerin görsel bir temsili bulunmaktadır. Kısalığı korumak için aşağıdaki görselleştirme kodu eklenmemiştir.



Tüm alt ve üst hücreler bir öneki paylaştığından, bu iki değer arasındaki tüm hücreleri elde etmek için minimum ve maksimum arasındaki hücre aralıklarını sorgulayabiliriz. Örneğimizde kahve dükkanını sorgulamak için aynı prensibi kullanıyoruz

Çözüm:

Bu makalede, jeo-uzaysal sorgulamayı desteklemeyen veritabanlarında coğrafi-uzaysal verileri depolamak ve sorgulamak için coğrafi-indekslemenin nasıl kullanılacağını gösterdik. Bu, 2 nokta arasındaki yönlendirmenin hesaplanması veya en yakın komşuların alınması gibi birden fazla kullanım durumunu kapsayacak şekilde genişletilebilir.


Tipik olarak, coğrafi indeksli veritabanı sorgulaması için veriler üzerinde bazı ek işlem sonrası işlemler gerçekleştirmeniz gerekir. Düğümü bunaltmadığımızdan emin olmak için sorgulama ve işlem sonrası mantığının dikkatli bir şekilde değerlendirilmesi gerekir.

Referanslar: