到 香港開放數據平台 → 點擊【數據集】→ 輸入【地方行政區分界】→ 下面會跳出【地方行政區分界】和【歷史地方行政區分界】→ 點擊【地方行政區分界】
→ 下面列出查詢結果【數據資源】
→ 我們要的就是【地方行政區分界 (英文/繁體中文) (JSON)】
→ 點擊【下載】鈕
香港的行政區有 18 個,所以下載的檔名為【hksar_18_district_boundary.json】。
{"type": "FeatureCollection",
"features": [
...
...
{"properties":{"TOWNSN":"64000002","TOWNID":"6400003","COUNTYNAME":"高雄市","TOWNNAME":"左營區","name":"高雄市/左營區"},
"type":"Feature",
"geometry":{"type": "Polygon",
"coordinates": [[[ 120.274766995608132, 22.706593189102705 ],
...
...
]]
}
},
...
...
CREATE TABLE `town_geo` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`TOWNSN` VARCHAR(20),
`TOWNID` VARCHAR(20),
`COUNTYNAME` VARCHAR(50),
`TOWNNAME` VARCHAR(50),
`name` VARCHAR(100),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
<?php
ini_set('display_errors', 1);
ini_set('memory_limit', '512M'); // 放寬記憶體限制, 才能讀大檔案
// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';
try {
// 1. 建立 PDO 連線
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 2. 讀取並解析 GeoJSON 檔案
$jsonFile = 'twTown1982.geo.json';
if (!file_exists($jsonFile)) {
die("錯誤:找不到檔案 $jsonFile");
}
$jsonContent = file_get_contents($jsonFile);
$data = json_decode($jsonContent, true);
if ($data === null) {
die("錯誤:JSON 解析失敗");
}
// 3. 準備 SQL 插入語句
$sql = "INSERT INTO town_geo (TOWNSN, TOWNID, COUNTYNAME, TOWNNAME, name)
VALUES (:townsn, :townid, :countyname, :townname, :name)";
$stmt = $pdo->prepare($sql);
// 4. 開始交易 (Transaction) 以提升大量寫入的速度
$pdo->beginTransaction();
$count = 0;
foreach ($data['features'] as $feature) {
$props = $feature['properties'];
// 綁定參數並執行
$stmt->execute([
':townsn' => $props['TOWNSN'] ?? null,
':townid' => $props['TOWNID'] ?? null,
':countyname' => $props['COUNTYNAME'] ?? null,
':townname' => $props['TOWNNAME'] ?? null,
':name' => $props['name'] ?? null
]);
$count++;
}
// 5. 提交交易
$pdo->commit();
echo "成功!共匯入 $count 筆資料。";
} catch (PDOException $e) {
// 發生錯誤時回滾
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
echo "一般錯誤:" . $e->getMessage();
}
?>
CREATE TABLE `village_geo` (
`id` INT AUTO_INCREMENT PRIMARY KEY,
`VILLAGESN` VARCHAR(20),
`VILLAGEID` VARCHAR(20),
`COUNTYNAME` VARCHAR(50),
`TOWNNAME` VARCHAR(50),
`VILLAGENAM` VARCHAR(50),
`name` VARCHAR(150),
`created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)
<?php
// 1. 提高記憶體限制(針對較大的村里 GeoJSON 檔案)
ini_set('memory_limit', '512M');
set_time_limit(0); // 取消執行時間限制
// 資料庫連線設定
$host = 'localhost';
$dbname = '資料庫名稱';
$username = '帳號';
$password = '密碼';
try {
// 2. 建立 PDO 連線
$pdo = new PDO("mysql:host=$host;dbname=$dbname;charset=utf8mb4", $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
// 3. 讀取 GeoJSON 檔案
$jsonFile = 'twVillage1982.geo.json';
if (!file_exists($jsonFile)) {
die("錯誤:找不到檔案 $jsonFile");
}
echo "正在讀取檔案...\n";
$jsonContent = file_get_contents($jsonFile);
echo "正在解析 JSON...\n";
$data = json_decode($jsonContent, true);
// 解析完立刻釋放字串記憶體
unset($jsonContent);
if ($data === null) {
die("錯誤:JSON 解析失敗,請檢查檔案格式。");
}
// 4. 準備 SQL 插入語句
$sql = "INSERT INTO village_geo (VILLAGESN, VILLAGEID, COUNTYNAME, TOWNNAME, VILLAGENAM, name)
VALUES (:v_sn, :v_id, :c_name, :t_name, :v_name, :full_name)";
$stmt = $pdo->prepare($sql);
// 5. 開始交易處理 (大量資料寫入必備)
$pdo->beginTransaction();
echo "正在匯入資料...\n";
$count = 0;
foreach ($data['features'] as $feature) {
$props = $feature['properties'];
$stmt->execute([
':v_sn' => $props['VILLAGESN'] ?? null,
':v_id' => $props['VILLAGEID'] ?? null,
':c_name' => $props['COUNTYNAME'] ?? null,
':t_name' => $props['TOWNNAME'] ?? null,
':v_name' => $props['VILLAGENAM'] ?? null,
':full_name' => $props['name'] ?? null
]);
$count++;
}
// 6. 提交交易
$pdo->commit();
echo "匯入完成!成功存入 $count 筆村里資料。";
} catch (PDOException $e) {
if (isset($pdo) && $pdo->inTransaction()) {
$pdo->rollBack();
}
echo "資料庫錯誤:" . $e->getMessage();
} catch (Exception $e) {
echo "一般錯誤:" . $e->getMessage();
}
?>
-- 建立使用者 CREATE USER 'user1'@'localhost' IDENTIFIED BY '密碼'; -- 授予 USER1 查詢資料庫 db1 的 table1 的權限 GRANT SELECT ON db1.table1 TO 'user1'@'localhost'; -- 刷新權限(選擇性命令, 通常會自動生效) FLUSH PRIVILEGES;
# 切換到放置 .sql 檔的目錄下, # 本例中, aa.sql 置於桌面 user$ cd 桌面 # 進入 su 模式 user$ sudo su # 匯入檔案 root# mysql -u root -p 資料庫名 < aa.sql
參考資料 ----
Metabase 預設自帶 世界地圖 & 美國地圖,如果需要台灣地圖幫助我們進行資料分析,則要手動新增台灣圖資。
到 simplemaps 下載台灣的 GeoJSON 的檔案 -- 檔名 tw.json,瞄一下 json 檔的內容,包含了一級行政區,其中屬性 id, name 是我們需要的。
{
"type": "FeatureCollection",
"features": [
{
...
...
"type": "Feature",
"properties": {
"source": "https://simplemaps.com",
"id": "TWKIN",
"name": "Kinmen"
},
...
...
因為在【LinuxMint 22.2 安裝設定 MySQL 8.0 + phpMyadmin】這篇筆記中,我們安裝了 phpMyadmin,所以 LinuxMint 一併安裝了 Apache,其網站根目錄位置為 /var/www/html/,
將 tw.json 放置在 /var/www/html/ 下,然後在 Metabase 設定 tw.json 的 url,在本例為 http://localhost/tw.json
登入 Metabase,點擊【齒輪】圖示
→ 管理員設定
→ 地圖 → 新增一個地圖
要注意的是:通常我們的資料庫中 縣/市 欄位並不是遵循 GeoJSON 的 ISO 名稱定義,所以需要做適當的轉換,例如:另外建一個對照用的 table。
對照資料表:city_geo +--------+--------+-------+ | id | 英文 | 中文 | +--------+--------+-------+ | TWKIN | Kinmen | 金門 | +--------+--------+-------+ | ... | ... | ... | +--------+--------+-------+
點擊右上角的齒輪圖示
→ 管理員設定
# 原本 metabase.jar 是放在 使用者家目錄下的 metabase 目錄內 [user]~$ cd metabase [user]$ sudo su [root]# groupadd -r metabase [root]# useradd -r -s /bin/false -g metabase metabase [root]# mkdir /usr/share/metabase [root]# cp metabase.jar /usr/share/metabase [root]# chown -R metabase:metabase /usr/share/metabase [root]# touch /var/log/metabase.log [root]# chown syslog:adm /var/log/metabase.log [root]# touch /etc/default/metabase [root]# chmod 640 /etc/default/metabase
[root]# cd /etc/systemd/system/ [root]# vim metabase.service # 輸入下述內容 [Unit] Description=Metabase server After=syslog.target After=network.target [Service] WorkingDirectory=/usr/share/metabase/ ExecStart=/usr/bin/java -jar /usr/share/metabase/metabase.jar EnvironmentFile=/etc/default/metabase User=metabase Type=simple StandardOutput=syslog StandardError=syslog SyslogIdentifier=metabase SuccessExitStatus=143 TimeoutStopSec=120 Restart=always [Install] WantedBy=multi-user.target :x 存檔離開
[root]# vim /etc/rsyslog.d/metabase.conf # 輸入下述內容 if $programname == 'metabase' then /var/log/metabase.log & stop :x 存檔離開 # 重啟 rsyslog.service 以使 metabase.conf 生效 [root]# systemctl restart rsyslog.service
[root]# vim /etc/default/metabase MB_PASSWORD_COMPLEXITY=strong MB_PASSWORD_LENGTH=8 # 要求最短的密碼字串長度 MB_JETTY_HOST=0.0.0.0 MB_JETTY_PORT=3000 MB_DB_CONNECTION_URI="jdbc:mysql://localhost:3306/metabase?user=metabase&password=密碼&verifyServerCertificate=false&allowPublicKeyRetrieval=true" MB_EMOJI_IN_LOGS=true # log 要不要有顏文字...這還蠻有趣的...若不要就填 false # any other env vars you want available to Metabase :x 存檔離開
# 先手動啟動 metabase.service [root]# systemctl daemon-reload [root]# systemctl start metabase.service [root]# systemctl status metabase.service # 觀察是否已啟動 # 另外再開瀏覽器, 看看是否能登入 metabase # 確定執行沒問題了, 就改為開機自動啟動 [root]# systemctl enable metabase.service
[user]~$ java -jar metabase.jar
-- 重點在最後面的 "with grant option", phpMyAdmin 圖形界面似乎做不到賦予 grant 權限 GRANT ALL PRIVILEGES ON `metabase`.* TO 'metabase'@'localhost' with grant option;
# 切換到 metabase.jar 所在目錄, 在本例為 [user]~/metabase/ [user]~/metabase$ export MB_DB_TYPE=mysql [user]~/metabase$ export MB_DB_CONNECTION_URI="jdbc:mysql://localhost:3306/metabase?user=metabase&password=密碼&verifyServerCertificate=false&allowPublicKeyRetrieval=true" [user]~/metabase$ java -DMB_DB_TYPE=mysql -DMB_DB_CONNECTION_URI="jdbc:mysql://localhost:3306/metabase?user=metabase&password=密碼&verifyServerCertificate=false&allowPublicKeyRetrieval=true" -jar metabase.jar load-from-h2 metabase.db # 注意檔名
[user]~/metabase$ export MB_DB_TYPE=mysql [user]~/metabase$ export MB_DB_CONNECTION_URI="jdbc:mysql://localhost:3306/metabase?user=metabase帳戶&password=密碼" [user]~/metabase$ java -DMB_DB_CONNECTION_URI="jdbc:mysql://localhost:3306/metabase?user=metabase&password=密碼&verifyServerCertificate=false&allowPublicKeyRetrieval=true" -jar metabase.jar重登入 metabase,可以看到之前製作的儀表板都在。