簡介:本文介紹了如何使用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