??在Observable Vector Tile Dissector 一文中笆制,我評估了不同的矢量切片供應(yīng)商提供的切片大小。文中提到的一些限制,其實是完全隨機選擇的选调,依據(jù)的是我豐富的經(jīng)驗積累……但如何才能真正減小切片大械亍俯抖?我將嘗試優(yōu)化自己的矢量切片并逐步解釋臂容。
??以下所有空間數(shù)據(jù)均基于 OpenStreetMap嗅剖,投影為web 墨卡托 (EPSG:3857) 忆蚀,并托管于PostGIS 數(shù)據(jù)庫矾利。
長話短說
??使用一些方法后姑裂,我們可以將給定矢量切片的大小減小到原始大小的 14%。
??這些“無損”的方法是:
- 移除不使用的數(shù)據(jù)
- 減小緩沖區(qū)
- 合并要素
- 壓縮
現(xiàn)狀
??選擇兩個不同縮放級別的切片男旗,讓我們觀察一下它們的大胁案:
切片 | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
大小 | 64 KiB (64984 Bytes) | 352 KiB (359820 Bytes) |
原始數(shù)據(jù) | ||
渲染后 |
??數(shù)據(jù)本身已經(jīng)根據(jù)縮放層級進行了刪減,并且還概化 [1] 了(降低空間復(fù)雜性)低縮放級別的要素察皇。還能搞點啥茴厉?
Identifier
?? 讓我們看看切片里都有啥:
??我們看到許多存儲為數(shù)字的 ID
。z10這個層級大概有幾千個什荣。然而當前配圖并沒有用到 ID
矾缓,因此我們可以從Layer Schema
中刪除對 osm_id/id
的所有引用:
??看看結(jié)果如何:
??數(shù)字類型的屬性少了很多,切片大小也顯著減欣6谩:
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
原始切片 | 64 KiB (64984 Bytes) | 352 KiB (359820 Bytes) |
移除Id 后 |
51 KiB (51966 Bytes) | 278 KiB (283677 Bytes) |
相對大小 | 80% | 79% |
??Nice!僅僅是刪除Id
————這個未使用的屬性而账,大小就減少了約 20%!
??然而在某些情況下掛載ID字段是有意義的因篇,例如需要根據(jù)ID從切片中提取數(shù)據(jù)(比如通過OnClick()事件)看哈這個Azure Maps
:
??Anyway泞辐,咱們再壓榨點空間試試。
Tile Buffer
??最近我寫過一篇關(guān)于切片緩沖區(qū)的文章竞滓。目前我緩沖大小為256咐吼。試著減小到64:
切片 | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
原始數(shù)據(jù) | ||
渲染后 |
??沒有出現(xiàn)visual artefacts,但切片也沒小多少商佑。意料之中锯茄。
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
previous step | 51 KiB (51966 Bytes) | 278 KiB (283677 Bytes) |
64 coordinate unit buffer | 50 KiB (51114 Bytes) | 276 KiB (282250 Bytes) |
relative size | 98% | 99% |
Merge
??看看縮放層級為10時的其他統(tǒng)計數(shù)據(jù):
??可以發(fā)現(xiàn):
??公路和鐵路層占所有要素的 87%。
??這些要素中超過 95% 僅包含 2 個點茶没。
??讓我們隨機選一條道路并檢查一下數(shù)據(jù)庫:
SELECT
ST_NPoints(geometry) as points,
geometry
FROM import.roads_gen10
where (geometry && ST_Transform(ST_MakeEnvelope(11.2500, 47.9899, 11.6016, 48.2247, 4326), 3857)) AND ref = 'St 2345' order by points DESC;
??將這條道路在 postgis 中編碼為矢量切片:
SELECT
length(ST_AsMVT(q, 'roads', 4096, 'geom')) as length
FROM
(
SELECT
ST_AsMVTGeom(
geometry,
ST_Transform(ST_MakeEnvelope(11.2500, 47.9899, 11.6016, 48.2247, 4326), 3857),
4096,
1) AS geom
FROM
import.roads_gen10
WHERE
(geometry && ST_Transform(ST_MakeEnvelope(11.2500, 47.9899, 11.6016, 48.2247, 4326), 3857))
AND ref = 'St 2345' ) AS q;
??看一下結(jié)果:
Name | Value |
---|---|
length | 1639 |
??這么說來肌幽。該切片中一條由 112 個單獨的 LineString 組成的連續(xù)道路,編碼為矢量瓦片后抓半,占用了 1639 字節(jié)空間喂急。而這112條LineString中,大部分(104條)都只有兩個點笛求。
??如果我們 使用ST_LineMerge() 將只有 兩個個 點的 LINESTRING 合并為一個大的 MULTILINESTRING 會發(fā)生什么廊移?
SELECT
length(ST_AsMVT(q, 'roads', 4096, 'geom')) AS length
FROM
(
SELECT
ST_AsMVTGeom(
ST_LineMerge( ST_Collect(geometry) ),
ST_Transform(ST_MakeEnvelope(11.2500, 47.9899, 11.6016, 48.2247, 4326), 3857),
4096,
0) AS geom
FROM
import.roads_gen10
WHERE
(geometry && ST_Transform(ST_MakeEnvelope(11.2500, 47.9899, 11.6016, 48.2247, 4326), 3857))
AND ref = 'St 2345' ) as q;
??results in:
Name | Value |
---|---|
length | 398 |
??So,僅僅是合并 LINESTRINGs 我們就將這條路的大小減少了 75%。背后的原理是探入,每次繪制一條新的 LINESTRING 狡孔,必須先將cursor移動到該LineString的起點,才能開始繪制蜂嗽。如果新Linestring的起點與上一個LineString的終點相同苗膝,則可以省略。也許我會寫另一篇文章來詳細解釋植旧。在此之前荚醒,請參閱 Vector Tile 規(guī)范芋类。
??Anyway,在真實場景中試試:
??干得漂亮界阁!現(xiàn)在我們的切片里的要素又少又大。我們也可以合并其他一些LineStrings,例如waterways圖層胖喳。
??其實面圖層也可以采用這種方法泡躯。我們還可以使用 ST_Union()函數(shù) 將切片內(nèi)的所有建筑物多邊形合并為一個大的MultiPolygon,而且效果不錯丽焊,尤其是在低縮放級別的情況下:
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
上一步驟 | 50 KiB (51114 Bytes) | 276 KiB (282250 Bytes) |
合并要素后 | 31 KiB (31518 Bytes) | 73 KiB (74081 Bytes) |
相對大小 | 62% | 26% |
??要使用此功能较剃,您需要指定一個新的屬性 (geom_query) 并對所有的keys施加group by
:
??請記住,這些合并操作代價不菲技健,有可能會減慢未緩存的訪問写穴。
GZIP
??在減小了數(shù)據(jù)編碼為切片的大小后,我們可以使用壓縮算法進一步減小大小雌贱。所有可用的瀏覽器都支持 GZIP啊送,因此無需擔心兼容性問題。
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
上一步驟 | 31 KiB (31518 Bytes) | 73 KiB (74081 Bytes) |
壓縮后 | 22 KiB (22382 Bytes) | 49 KiB (50061 Bytes) |
相對大小 | 71% | 68% |
??這不僅有助于節(jié)省存儲成本欣孤,還可以縮短最終用戶的加載時間馋没。
Summary
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
Orignal | 64 KiB (64984 Bytes) | 352 KiB (359820 Bytes) |
移除Id 后 |
51 KiB (51966 Bytes) | 278 KiB (283677 Bytes) |
調(diào)整Buffer后 | 50 KiB (51114 Bytes) | 276 KiB (282250 Bytes) |
合并要素后 | 31 KiB (31518 Bytes) | 73 KiB (74081 Bytes) |
相對大小 | 48% | 21% |
gzip壓縮后 | 22 KiB (22382 Bytes) | 49 KiB (50061 Bytes) |
相對大小 | 34% | 14% |
??渲染圖顯示出一些細微差異,主要原始是某些要素的排序發(fā)生了變化:
Tile | 14/8717/5683.mvt | 10/544/355.mvt |
---|---|---|
之前 |
|
|
之后 |
|
|
??通過分析矢量切片及其空間數(shù)據(jù)降传,我們能夠?qū)⑹噶壳衅瑴p小到原始大小的 21%(算上壓縮的話篷朵,14%),同時并沒有降低視覺體驗婆排。這些方法適用于幾乎所有矢量切片服務(wù)器声旺。
??我期待更多關(guān)于如何進一步減小切片大小的想法。
參考
原文鏈接:Optimizing vector tile size(cyclemap.link)