簡介:本文介紹了如何使用RDS PG或PolarDB(與PG或Oracle版本兼容)的Ganos時(shí)空引擎提供的數(shù)據(jù)庫快捷方式技術(shù),通過100行代碼在線快速顯示數(shù)十億個(gè)海量幾何空間數(shù)據(jù),并實(shí)現(xiàn)無縫的地圖交互。不用擔(dān)心切片存儲(chǔ)和效率問題。

01 引言


如何對(duì)時(shí)空數(shù)據(jù)庫中的億級(jí)矢量空間數(shù)據(jù)進(jìn)行在線可視化一直是業(yè)界難題。因數(shù)據(jù)體量大,傳統(tǒng)方法需要將數(shù)據(jù)庫中數(shù)據(jù)進(jìn)行基于緩存切片的服務(wù)發(fā)布才能可視化,操作流程冗長,且有一大堆需要考慮的問題:


  • 如果對(duì)矢量數(shù)據(jù)進(jìn)行預(yù)切片,數(shù)據(jù)要切多久?切多少級(jí)合適?存儲(chǔ)瓦片的硬盤空間夠用嗎?
  • 如果使用實(shí)時(shí)瓦片,實(shí)時(shí)渲染瓦片的響應(yīng)時(shí)間能保證嗎?
  • 如果使用矢量瓦片,小比例尺的瓦片可能會(huì)有多大體積?傳輸會(huì)不會(huì)成為瓶頸?前端渲染能承受多大的數(shù)據(jù)量?


如果是要快速瀏覽數(shù)據(jù)庫中的大規(guī)模在線數(shù)據(jù),傳統(tǒng)用于“底圖服務(wù)”的離線切片生產(chǎn)流程幾乎無解,不但費(fèi)時(shí)費(fèi)力,又無法在線聯(lián)機(jī)處理。黑科技來了,本文介紹如何使用RDS PG或PolarDB(兼容PG版或Oracle版)的Ganos時(shí)空引擎提供的數(shù)據(jù)庫快顯技術(shù),僅用百行代碼實(shí)現(xiàn)億級(jí)海量幾何空間數(shù)據(jù)的在線快速顯示和流暢地圖交互,且無需關(guān)注切片存儲(chǔ)和效率問題。


02 技術(shù)特性解讀


Ganos的在線快顯處理的核心是將數(shù)據(jù)庫和可視化進(jìn)行了關(guān)聯(lián),提供了一種新的可視化索引技術(shù)——稀疏矢量金字塔(Sparse vector Pyramid,SVP)索引。SVP具備兩個(gè)關(guān)鍵特性:快與省。


其中,快指兩個(gè)階段的快:

  • 金字塔創(chuàng)建快:Ganos利用空間索引對(duì)數(shù)據(jù)在空間上進(jìn)行密集度劃分,根據(jù)密集度建立一種稀疏矢量金字塔索引,相比傳統(tǒng)切圖流程減少了90%的數(shù)據(jù)計(jì)算量。同時(shí),創(chuàng)建金字塔采用了完全并行處理模式,即使1億條地類圖斑數(shù)據(jù)生成金字塔也僅需耗費(fèi)約10分鐘時(shí)間。
  • 數(shù)據(jù)展現(xiàn)快:Ganos采用了視覺可見性剔除算法,根據(jù)Z-order排序,過濾掉大量不影響顯示效果的數(shù)據(jù),從而加快實(shí)時(shí)顯示的效率。Ganos支持直接輸出png格式的柵格瓦片和MVT格式的矢量瓦片,1億地類圖斑數(shù)據(jù)實(shí)時(shí)渲染顯示的響應(yīng)時(shí)間都達(dá)到秒級(jí)。


省也具有兩個(gè)維度:

  • 節(jié)省磁盤空間:1億條地類圖斑數(shù)據(jù)生成金字塔索引僅僅占據(jù)原表5%大小的額外空間。
  • 節(jié)省開發(fā)時(shí)間:僅使用簡單的sql語句,通過調(diào)整語句參數(shù)即可靈活控制顯示效果。


03 使用步驟


Ganos的快顯引擎使用上非常簡潔,已高度封裝了SQL函數(shù)。需要注意的是,第一次使用快顯引擎之前,需要顯式創(chuàng)建對(duì)應(yīng)的擴(kuò)展模塊,執(zhí)行的語句如下:


CREATE EXTENSION ganos_geometry_pyramid CASCADE;


通過執(zhí)行以上語句,快顯引擎的計(jì)算組件將會(huì)被加載起來。


3.1 建立稀疏矢量金字塔


假設(shè)您已創(chuàng)建了某個(gè)矢量大表并導(dǎo)入了數(shù)據(jù),接著就可以使用Ganos的st_buildpyramid方法創(chuàng)建矢量金字塔。


方法原型如下,更詳細(xì)的參數(shù)描述可以參考官方文檔。


boolean ST_BuildPyramid(cstring table, cstring geom, cstring fid, cstring config)

注:*左右滑動(dòng)閱覽


其中

  • table:矢量數(shù)據(jù)所在的表名。
  • geom:矢量字段名。
  • fid:矢量要素記錄的唯一標(biāo)識(shí),支持Int4/Int8類型。
  • config:json格式的配置參數(shù)字符串。
    • 在本例中,我們指定矢量金字塔的名稱和使用的邏輯瓦片大小(這個(gè)瓦片大小并非真實(shí)存在的瓦片,僅表示一種空間上的邏輯劃分)


實(shí)際調(diào)用如下:


ST_BuildPyramid('points', 'geom', 'gid', '{"name":"points_geom","tilesize":512}')

注:*左右滑動(dòng)閱覽


我們?yōu)楸韕oints的geom字段創(chuàng)建了一個(gè)矢量金字塔,金字塔名我們指定為points_geom,同時(shí)設(shè)定金字塔的邏輯瓦片大小為512。


3. 2 獲取柵格瓦片


柵格瓦片是圖片形式的瓦片(Tile),是使用最廣泛的一種地圖瓦片形式。Ganos的ST_AsPng方法提供了在數(shù)據(jù)庫端將矢量數(shù)據(jù)按需動(dòng)態(tài)渲染為柵格瓦片的功能。該功能提供了最基礎(chǔ)的柵格符號(hào)化能力,更多面向一些不需要復(fù)雜符號(hào)化的輕量級(jí)場景,如數(shù)管系統(tǒng)中。


方法原型如下,更詳細(xì)的參數(shù)描述可以參考官方文檔:


bytes ST_AsPng( cstring name, cstring tile, cstring style)


其中

  • name:金字塔表名。
  • tile:瓦片索引行列號(hào),Z_X_Y的形式。
  • style:渲染樣式。我們可以通過如下參數(shù)調(diào)節(jié)渲染效果:
    • point_size:點(diǎn)大小,單位為像素。
    • line_width:線寬,對(duì)線要素和面要素的外邊框起作用,單位為像素。
    • line_color:線渲染顏色,對(duì)線要素和面要素的外邊框起作用。前6位為16進(jìn)制顏色,后2位為16進(jìn)制透明度。
    • fill_color:填充顏色,對(duì)面要素起作用。
    • background:背景色。一般設(shè)置為FFFFFF00,即純透明。


實(shí)際調(diào)用如下:

ST_AsPng('points_geom', '1_2_1','{"point_size": 5,"line_width": 2,"line_color": "#003399FF","fill_color": "#6699CCCC","background": "#FFFFFF00"}')

注:*左右滑動(dòng)閱覽


我們從矢量金字塔中獲取到索引行列號(hào)為x=2,y=1,z=1的矢量瓦片,并將該矢量瓦片按照我們配置的樣式渲染為柵格瓦片,返回PNG格式的圖片。


3. 3 獲取矢量瓦片


矢量瓦片是新興的地圖瓦片技術(shù),具有在前端配置樣式的靈活特性,使用WebGL渲染,效果也更加美觀,Mapbox等地圖框架可以方便的支持這一格式。使用Ganos的ST_Tile方法可以將矢量金字塔中的數(shù)據(jù)以矢量瓦片的形式提供。


方法原型如下,更詳細(xì)的參數(shù)描述可以參考官方文檔。


bytea ST_Tile(cstring name, cstring key);


其中

  • name:金字塔名。在本例中為表名_矢量字段名。
  • key:瓦片索引行列號(hào),Z_X_Y的形式。


我們只需要提供標(biāo)準(zhǔn)的TMS行列號(hào)和金字塔表的名稱即可調(diào)用。


實(shí)際調(diào)用如下:


ST_Tile('points_geom', '1_2_1');


我們從矢量金字塔中獲取到索引行列號(hào)為x=2,y=1,z=1的矢量瓦片,返回?cái)?shù)據(jù)為標(biāo)準(zhǔn)的MVT格式。


04 實(shí)戰(zhàn)案例


4.1 測試數(shù)據(jù)


我們準(zhǔn)備兩份矢量數(shù)據(jù)作為測試樣例。


buildings表為面數(shù)據(jù),數(shù)據(jù)總計(jì)1.25億條,展現(xiàn)使用柵格瓦片的在線可視化效果。


gid|geom | ---|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| 1|MULTIPOLYGON 34.916114 0,-88.066704 34.916114 0,-88.066704 34.91602 0,-88.066953 34.91602 0,-88.066953 34.916114 0))) 2|MULTIPOLYGON 34.994797 0,-87.924791 34.99476 0,-87.924817 34.994824 0,-87.924685 34.994861 0,-87.924658 34.994797 0)))

注:*左右滑動(dòng)閱覽


points表為點(diǎn)數(shù)據(jù),數(shù)據(jù)總計(jì)10.7萬條,展現(xiàn)使用矢量瓦片的在線可視化效果。


id|geom | --|------------------------------| 1|POINT 22.1851929)| 2|POINT 22.1829781)|


4.2 全棧架構(gòu)


數(shù)據(jù)庫-快顯全棧架構(gòu)包含數(shù)據(jù)庫服務(wù)器、python服務(wù)端和用戶端三個(gè)部分,全棧架構(gòu)如下圖所示。



4.3 服務(wù)端代碼


為了代碼簡潔,更側(cè)重于邏輯的描述,我們選擇了Python(兼容Py及以上版本)作為后端語言,Web框架使用了基于Python的Flask(使用pip install flask進(jìn)行安裝)框架,數(shù)據(jù)庫連接框架使用了基于Python的Psycopg2(使用pip install psycopg2進(jìn)行安裝)。


值得一提的是,我們實(shí)現(xiàn)了最基礎(chǔ)的功能,當(dāng)Web服務(wù)自身的性能出現(xiàn)瓶頸時(shí),可按不同的平臺(tái)與框架進(jìn)行優(yōu)化,獲得更好的響應(yīng)性能。


我們?cè)诤蠖耸紫冉⒘耸噶拷鹱炙?,其后分別實(shí)現(xiàn)了兩個(gè)接口,矢量瓦片接口使用points表中的數(shù)據(jù),柵格瓦片接口使用buildings表中的數(shù)據(jù),并定義好樣式,供前端直接調(diào)用。為了方便說明,后端代碼同時(shí)提供了矢量柵格兩個(gè)接口,實(shí)際使用時(shí)可以按需選擇。


# -*- coding: utf-8 -*- # @File : Vec import json from psycopg2 import pool from threading import Semaphore from flask import Flask, jsonify, Response, send_from_directory import binascii # 連接參數(shù) connectION = "dbname=postgres user=postgres password=postgres host=YOUR_HOST port=5432" class ReallyThreadedConnectionPool): """ 面向多線程的連接池,提高地圖瓦片類高并發(fā)場景的響應(yīng)。 """ def __init__(self, minconn, maxconn, *args, **kwargs): = Semaphore(maxconn) super().__init__(minconn, maxconn, *args, **kwargs) def getconn(self, *args, **kwargs): .acquire() return super().getconn(*args, **kwargs) def putconn(self, *args, **kwargs): super().putconn(*args, **kwargs) .release() class VectorViewer: def __init__(self, connect, table_name, column_name, fid): = table_name = column_name # 創(chuàng)建一個(gè)連接池 = ReallyThreadedConnectionPool(5, 10, connect) # 約定金字塔表名 = f"{}_{}" = fid = 512 # () def _build_pyramid(self): """創(chuàng)建金字塔""" config = { "name": , "tileSize": } sql = f"select st_BuildPyramid('{}','{}','{}','{j(config)}')" (sql) def poll_query(self, query: str): pg_connection = .getconn() pg_cursor = () (query) record = () () () .putconn(pg_connection) if record is not None: return record[0] class PngViewer(VectorViewer): def get_png(self, x, y, z): # 默認(rèn)參數(shù) config = { "point_size": 5, "line_width": 2, "line_color": "#003399FF", "fill_color": "#6699CCCC", "background": "#FFFFFF00" } # 在使用psycpg2時(shí),將二進(jìn)制數(shù)據(jù)以16進(jìn)制字符串的形式傳回效率更高 sql = f"select encode(st_aspng('{}','{z}_{x}_{y}','{j(config)}'),'hex')" result = (sql) # 只有在使用16進(jìn)制字符串的形式傳回時(shí)才需要將其轉(zhuǎn)換回來 result = bina(result) return result class MvtViewer(VectorViewer): def get_mvt(self, x, y, z): # 在使用psycpg2時(shí),將二進(jìn)制數(shù)據(jù)以16進(jìn)制字符串的形式傳回效率更高 sql = f"select encode(st_tile('{}','{z}_{x}_{y}'),'hex')" result = (sql) # 只有在使用16進(jìn)制字符串的形式傳回時(shí)才需要將其轉(zhuǎn)換回來 result = bina(result) return result app = Flask(__name__) @a('/vector') def vector_demo(): return send_from_directory("./", "Vec;) # 定義表名,字段名稱等 pngViewer = PngViewer(CONNECTION, 'usbf', 'geom', 'gid') @a('/vector/png/<int:z>/<int:x>/<int:y>') def vector_png(z, x, y): png = (x, y, z) return Response( response=png, mimetype="image/png" ) mvtViewer = MvtViewer(CONNECTION, 'points', 'geom', 'gid') @a('/vector/mvt/<int:z>/<int:x>/<int:y>') def vector_mvt(z, x, y): mvt=mv(x, y, z) return Response( response=mvt, mimetype="application; ) if __name__ == "__main__": a(port=5000, threaded=True)

注:*左右滑動(dòng)閱覽


將以上代碼保存為Vec文件,執(zhí)行python Vec命令即可啟動(dòng)服務(wù)。


從代碼不難推斷,無論我們使用何種語言、何種框架,我們只需將矢量或柵格瓦片的SQL語句封裝為接口即可實(shí)現(xiàn)完全相同的功能。相比發(fā)布傳統(tǒng)的地圖服務(wù),借助Ganos的矢量金字塔功能實(shí)現(xiàn)在線可視化是更加輕量好用的選擇:


  • 針對(duì)柵格瓦片,可以在通過改變代碼進(jìn)行樣式控制,靈活性大大增強(qiáng)。
  • 無需引入第三方的其他組件,也不需要進(jìn)行針對(duì)性優(yōu)化,就有令人滿意的響應(yīng)性能。
  • 可以任意選擇使用者熟悉的編程語言與框架,也無需復(fù)雜專業(yè)的參數(shù)配置,對(duì)非地理從業(yè)者更加的友好。


4.4 用戶端代碼


我們選用Mapbox作為前端地圖框架,展示后端提供的矢量瓦片層和柵格瓦片層,并為矢量瓦片層配置了渲染參數(shù)。


為了方便說明,前端代碼同時(shí)添加了矢量、柵格兩個(gè)圖層,實(shí)際使用時(shí)可以按需選擇。


我們?cè)诤蠖舜a的同一文件目錄下新建名為Vec的文件,寫入下列代碼,在后端服務(wù)啟動(dòng)后,就可以通過http://localhost:5000/vector訪問了。


<!DOCTYPE html> <html> <head> <meta charset="UTF-8" /> <title></title> <link href="; rel="stylesheet" /> </head> <script src=";></script> <script src=";></script> <body> <div id="map" style="height: 100vh" /> <script> const sources = { osm: { type: "raster", tiles: ["{z}/{x}/{y}.png"], tileSize: 256, }, }; const layers = [ { id: "base_map", type: "raster", source: "osm", layout: { visibility: "visible" }, }, ]; const map = new ma({ container: "map", style: { version: 8, layers, sources }, }); map.on("load", async () => { map.resize(); // 添加?xùn)鸥裢咂瑪?shù)據(jù)源 map.addSource("png_source", { type: "raster", minzoom: 1, tiles: [`${window.loca}/png/{z}/{x}/{y}`], tileSize: 512, }); // 添加?xùn)鸥裢咂瑘D層 map.addLayer({ id: "png_layer", type: "raster", layout: { visibility: "visible" }, source: "png_source", }); // 添加矢量瓦片數(shù)據(jù)源 map.addSource("mvt_source", { type: "vector", minzoom: 1, tiles: [`${window.loca}/mvt/{z}/{x}/{y}`], tileSize: 512, }); // 添加矢量瓦片圖層,并為矢量瓦片添加樣式 map.addLayer({ id: "mvt_layer", paint: { "circle-radius": 4, "circle-color": "#6699CC", "circle-stroke-width": 2, "circle-opacity": 0.8, "circle-stroke-color": "#ffffff", "circle-stroke-opacity": 0.9, }, type: "circle", source: "mvt_source", "source-layer": "points_geom", }); }); </script> </body> </html>

注:*左右滑動(dòng)閱覽


4.5 矢量瓦片的動(dòng)態(tài)效果



可以在前端調(diào)節(jié)不同效果。調(diào)整為新的圖層參數(shù)后效果如下:


{ "circle-radius": 4, "circle-color": "#000000", "circle-stroke-width": 2, "circle-opacity": 0.3, "circle-stroke-color": "#003399", "circle-stroke-opacity": 0.9, }



4.6 柵格瓦片的動(dòng)態(tài)效果



05 與PGADmin集成


PG數(shù)據(jù)庫管理工具PGAdmin原生支持矢量數(shù)據(jù)的可視化,但因缺乏快顯技術(shù),僅能單對(duì)象顯示或有限結(jié)果集顯示,無法對(duì)大規(guī)模矢量數(shù)據(jù)進(jìn)行暢快淋漓的全局瀏覽。我們將Ganos的矢量快顯功能與PGAdmin集成,數(shù)據(jù)入庫即可在線瀏覽全局,快速評(píng)估數(shù)據(jù)概況,大大增強(qiáng)了數(shù)據(jù)管理的使用體驗(yàn)。



06 總結(jié)

本文從稀疏矢量金字塔的原理與優(yōu)勢入手,介紹了如何利用Ganos實(shí)現(xiàn)在線可視化服務(wù)的各種功能,并最終通過百行代碼實(shí)現(xiàn)了一個(gè)可以應(yīng)對(duì)億級(jí)數(shù)據(jù)的地圖可視化服務(wù)。讀者可以進(jìn)一步在可視化基礎(chǔ)上,利用PG/PolarDB Ganos的服務(wù)器端快速查詢和分析能力進(jìn)行對(duì)象屬性查詢、空間圈選、空間分析等更復(fù)雜功能。這就是Ganos所帶來的大規(guī)模空間圖形顯示加速黑科技——稀疏矢量金字塔索引帶來的變革。

作者:李鶴

本文為阿里云原創(chuàng)內(nèi)容,未經(jīng)允許不得轉(zhuǎn)載

1.《【100vh】基于Ganos百行代碼實(shí)現(xiàn)億級(jí)矢量空間數(shù)據(jù)在線可視化》援引自互聯(lián)網(wǎng),旨在傳遞更多網(wǎng)絡(luò)信息知識(shí),僅代表作者本人觀點(diǎn),與本網(wǎng)站無關(guān),侵刪請(qǐng)聯(lián)系頁腳下方聯(lián)系方式。

2.《【100vh】基于Ganos百行代碼實(shí)現(xiàn)億級(jí)矢量空間數(shù)據(jù)在線可視化》僅供讀者參考,本網(wǎng)站未對(duì)該內(nèi)容進(jìn)行證實(shí),對(duì)其原創(chuàng)性、真實(shí)性、完整性、及時(shí)性不作任何保證。

3.文章轉(zhuǎn)載時(shí)請(qǐng)保留本站內(nèi)容來源地址,http://f99ss.com/guonei/1958466.html