技術實作

這頁寫給想知道怎麼做的人。所有效能數字都是在自己這台機器上量的。

整條流程

  1. 從政府資料開放平臺下載 zip(三年份合計約 104 MB)
  2. 用 Python 的 zipfile 串流讀取,不解壓縮到磁碟 —— 三年份解開來是 1.5 GB
  3. 去重、剔除假座標
  4. 建成 SQLite:一份 12 公尺細格(帶月份),加上第 7 到 11 級的預聚合表
  5. 成品 106 MB

為什麼不是每個縮放層級各存一份

第一版是那樣做的,12 個層級各存一份,單年資料就 180 MB。 改成「存一份細格,查詢時用整數除法即時併粗」之後,資料量變成三倍(一年變兩年八個月), 資料庫反而縮到 106 MB。低倍率(第 7 到 11 級)才另外預聚合, 因為那個範圍一次要掃的格子太多。

圖磚而不是 bbox

第一版的 API 是吃 bbox 的。問題是 bbox 只要差一個小數點就是一個新網址, 所以地圖平移一點點就會重抓整個畫面,而且瀏覽器和 CDN 都無法快取。實測一次回應 954 KB。

改成固定的圖磚網址之後:

圖磚帶 Cache-Control: max-age=86400。資料一個月只更新兩次,快取一天很安全。

壓縮

GeoJSON 是高度重複的文字,壓縮效果非常好。同一份 1,044,568 bytes 的回應實測:

gzip 級別壓縮後倍率伺服器壓縮瀏覽器解壓
169,13215.1×1.8 ms1.28 ms
458,19417.9×2.6 ms1.25 ms
653,25519.6×4.3 ms1.19 ms
950,96720.5×10.4 ms1.27 ms

解壓縮固定在 1.2 毫秒左右,跟級別無關 —— 那是瀏覽器裡的原生程式碼。 最後選 4 級:比 6 級只大 8%,但伺服器端快一倍。

前端

地圖用 MapLibre GL JS(Mapbox GL 的開源分支,BSD 授權)。 選它的理由是原生支援熱力圖圖層、GPU 渲染、而且不需要 API key 也不需要綁信用卡。

Google Maps 的 HeatmapLayer 在 2025 年 5 月宣告棄用、2026 年 5 月的 3.65 版正式移除, 官方建議改用第三方套件。而且 Google Maps 每次載入要計費,對一個免費工具來說是風險。

底圖用 OpenFreeMap 的向量圖磚,同樣不需要 API key、沒有用量限制。 熱力圖的權重在前端計算,因為圖磚必須是純資料才能被快取, 而每塊圖磚各自標準化會在磚的邊界上留下看得見的色階斷層。

後端

Flask + SQLite,跟站上其他工具跑在同一個容器裡,但完全不碰顯示卡 —— 沒有佇列、沒有配額、可以無限併發。

查詢實測:單一圖磚 8 到 82 毫秒,看縮放層級與範圍而定。

回地圖