GIS 4 — Định dạng dữ liệu & Nạp/Chuyển đổi không gian

13 thg 7, 2026 3 lượt xem
#etl
#gis
#gdal
#geojson
#shapefile

GIS 4 — Định dạng dữ liệu & Nạp/Chuyển đổi không gian

bài PostGIStruy vấn không gian, ta luôn giả định dữ liệu đã nằm sẵn trong bảng với cột geometry SRID 4326 và GIST index. Bài này trả lời câu hỏi thực tế đứng trước đó: dữ liệu không gian đến từ đâu, ở định dạng gì, và làm sao đưa nó vào PostGIS cho đúng? Đây là phần ETL không gian — thường tốn 80% công sức của một dự án GIS, dù ít được nói tới.

Điểm mấu chốt cần nắm ngay: dữ liệu không gian không đến dưới dạng "bảng SQL". Nó đến dưới dạng file với đủ loại định dạng (Shapefile, GeoJSON, GeoPackage...), mỗi file mang theo một hệ toạ độ (CRS) có thể khác hệ bạn đang dùng. Nạp dữ liệu không gian = đọc đúng định dạng + chuẩn hoá CRS về một chuẩn thống nhất (thường EPSG:4326) + ghi vào bảng có GIST index. Bỏ qua bước CRS là nguồn lỗi số một.

Lưu ý sandbox: PostGIS KHÔNG được cài trên sandbox Knowledge Base (chỉ có PostgreSQL read-only chuẩn), và các công cụ dòng lệnh như ogr2ogr/shp2pgsql cũng không có. Vì vậy mọi lệnh GDAL/SQL không gian trong bài là MINH HOẠ — cú pháp thật, dùng được trên hệ thống có PostGIS, nhưng không đánh dấu -- ▶ Chạy được. Chỉ một câu SQL non-spatial gộp theo city ở cuối là chạy thật, làm phép loại suy cho ý "gom dữ liệu theo địa bàn".

Bức tranh tổng: định dạng vector vs raster

Dữ liệu không gian chia làm hai họ lớn:

  • Vector — hình học rời rạc: điểm (chi nhánh, ATM, khách), đường (sông, đường phố), vùng (ranh giới quận). Đây là 95% dữ liệu một ngân hàng dùng.
  • Raster — lưới ô pixel có toạ độ: ảnh vệ tinh, bản đồ độ cao, bản đồ mật độ dân số. Ít gặp hơn trong ngân hàng nhưng hữu ích cho phân tích vùng phủ.

Định dạng vector

Shapefile (.shp / .shx / .dbf) — kinh điển của ESRI

Định dạng vector phổ biến nhất và cũng cũ nhất (ESRI, đầu thập niên 1990). Dữ liệu nhà nước, GADM, nhiều nguồn mở vẫn phát hành dạng này. Đặc điểm quan trọng: một "shapefile" thực ra là nhiều file phải đi kèm nhau:

  • .shp — hình học (geometry).
  • .shx — chỉ mục hình học.
  • .dbf — bảng thuộc tính (dBASE, các cột như tên quận, mã).
  • .prj — mô tả CRS (rất quan trọng, nhưng hay bị thiếu).
  • .cpg — bảng mã ký tự cho .dbf.

Các hạn chế khiến Shapefile bị coi là lỗi thời:

  • Tên cột tối đa 10 ký tựdistrict_code bị cắt còn district_c, mất nghĩa.
  • Giới hạn kích thước 2 GB cho mỗi thành phần file.
  • Phải mang nhiều file cùng lúc; thiếu .prj là mất CRS, thiếu .dbf là mất thuộc tính.
  • .dbf chỉ hỗ trợ kiểu dữ liệu hạn chế, encoding tiếng Việt hay lỗi nếu thiếu .cpg.

Dù vậy, Shapefile vẫn là "mẫu số chung" — biết nạp nó là kỹ năng bắt buộc.

GeoJSON — chuẩn web dựa trên JSON

GeoJSON là định dạng sinh ra cho web: nó là JSON hợp lệ, con người đọc được, mọi thư viện JavaScript (Leaflet, Mapbox, d3-geo) hiểu thẳng, và API REST trả về tự nhiên. Một FeatureCollection gồm nhiều Feature, mỗi feature có geometry (toạ độ) và properties (thuộc tính):

{
  "type": "FeatureCollection",
  "features": [
    {
      "type": "Feature",
      "geometry": { "type": "Point", "coordinates": [105.80, 21.03] },
      "properties": { "name": "CN Cầu Giấy", "type": "branch" }
    }
  ]
}

Quy ước then chốt: GeoJSON luôn dùng thứ tự [longitude, latitude] (X trước, Y sau) và luôn ở CRS WGS84 / EPSG:4326 theo đặc tả RFC 7946. Đây là lý do 4326 là SRID mặc định thực dụng cho toàn bộ series. Điểm yếu: file text nên cồng kềnh với dữ liệu lớn, và không có chỉ mục — không hợp làm định dạng lưu trữ hàng triệu feature. GeoJSON là ngôn ngữ trao đổi giữa CSDL và trình duyệt; cách phục vụ nó ra bản đồ web là chủ đề của GIS 5 — Trực quan hoá.

GeoPackage (.gpkg) — định dạng hiện đại, một file

GeoPackage là chuẩn OGC mở, bản chất là một CSDL SQLite đóng gói dữ liệu không gian. Nó khắc phục gần hết nhược điểm Shapefile:

  • Một file duy nhất .gpkg — không còn bộ 4-5 file rời.
  • Không giới hạn tên cột 10 ký tự, không giới hạn 2 GB thực tế.
  • Chứa nhiều lớp (điểm, đường, vùng, cả raster) trong cùng một file, kèm chỉ mục không gian.
  • Mang CRS đầy đủ bên trong, encoding UTF-8 chuẩn.

Khi được chọn định dạng để trao đổi file dữ liệu vector cỡ vừa/lớn, GeoPackage là lựa chọn mặc định tốt hơn Shapefile.

KML/KMZ — Google Earth

KML (Keyhole Markup Language, dạng XML) và bản nén KMZ là định dạng của Google Earth / Google Maps. Thường gặp khi ai đó "vẽ tay" ranh giới hoặc điểm trên Google Earth rồi xuất ra. Hữu ích để nhận từ nghiệp vụ, nhưng không phải định dạng lưu trữ/phân tích chính; thường bước đầu là chuyển KML → PostGIS.

WKT / WKB — biểu diễn hình học bên trong CSDL

Khác với các định dạng file trên, WKT (Well-Known Text) và WKB (Well-Known Binary) là cách biểu diễn một hình học dưới dạng chuỗi/nhị phân — chuẩn OGC mà PostGIS dùng để nhập/xuất geometry:

  • WKT — text người đọc được: POINT(105.80 21.03), POLYGON((...)), LINESTRING(...). Dùng khi viết tay geometry trong SQL hoặc debug.
  • WKB — nhị phân, gọn và nhanh hơn; là dạng PostGIS lưu/truyền thực tế.
-- MINH HOẠ (PostGIS) — dựng geometry từ WKT
SELECT ST_GeomFromText('POINT(105.80 21.03)', 4326) AS diem;
SELECT ST_AsText(geom) AS wkt FROM branches LIMIT 1;   -- xuất ra WKT

WKT/WKB không phải "file định dạng" mà là cầu nối giữa hình học và mọi thứ khác — cột trong bảng, chuỗi trong CSV, giá trị trong API.

TopoJSON — GeoJSON tối ưu topology

TopoJSON là mở rộng của GeoJSON lưu topology (chia sẻ đường biên chung giữa các vùng liền kề thay vì lặp lại). Kết quả: file nhỏ hơn nhiều (thường 80%) và biên giữa hai quận khít nhau tuyệt đối, không hở. Rất hợp cho bản đồ ranh giới hành chính trên web. Đổi lại nó phải "giải nén" về GeoJSON trước khi vẽ.

Định dạng raster (ngắn)

GeoTIFF là định dạng raster phổ biến nhất: một ảnh TIFF gắn thêm metadata địa lý (CRS + toạ độ góc + độ phân giải pixel) để mỗi pixel biết mình ở đâu trên Trái Đất. Dùng cho ảnh vệ tinh, mô hình độ cao (DEM), bản đồ mật độ. PostGIS có kiểu raster và extension postgis_raster để lưu/truy vấn, nhưng với ngân hàng, raster thường chỉ là lớp nền tham chiếu — phần lớn phân tích vẫn là vector.

CRS & chuyển hệ toạ độ khi nạp

Đây là bước quan trọng nhất và hay bị bỏ sót nhất khi nạp dữ liệu. Mỗi nguồn dữ liệu mang một CRS (Coordinate Reference System) — quy ước diễn giải các con số toạ độ. Ký hiệu chuẩn là mã EPSG:

  • EPSG:4326 — WGS84, kinh/vĩ độ (độ). Chuẩn của GPS, GeoJSON, hầu hết dữ liệu web.
  • EPSG:3857 — Web Mercator (mét), hệ chiếu của Google/OSM tile.
  • EPSG:32648 — UTM zone 48N (mét), hợp cho đo khoảng cách/diện tích ở miền Bắc VN.
  • VN-2000 — hệ toạ độ quốc gia Việt Nam (các mã EPSG theo múi, ví dụ 3405), dữ liệu nhà nước hay dùng.

Vấn đề: nếu file nguồn ở VN-2000 mà bạn cứ nạp thẳng vào cột SRID 4326 mà không reproject, các con số vẫn vào bảng nhưng điểm rơi sai chỗ hoàn toàn — Hà Nội có thể nhảy ra giữa biển. Quy tắc vàng khi nạp: luôn biết CRS nguồn, và luôn reproject về một CRS đích thống nhất (khuyến nghị 4326 cho lưu chung, đúng như GIS 3 đã dùng). Việc chuyển giữa các hệ gọi là reproject, làm bằng công cụ (ogr2ogr -t_srs) hoặc trong CSDL (ST_Transform).

Công cụ nạp & chuyển đổi

GDAL/OGR — ogr2ogr, con dao đa năng

GDAL/OGR là thư viện mã nguồn mở đứng sau gần như mọi phần mềm GIS. Lệnh ogr2ogr của nó chuyển đổi giữa mọi cặp định dạng vector (Shapefile ↔ GeoJSON ↔ GeoPackage ↔ PostGIS ↔ KML...), đồng thời reproject CRS ngay trong lúc chuyển. Đây là công cụ ETL không gian số một.

Ví dụ 1 — Shapefile → PostGIS, đồng thời reproject về 4326:

# MINH HOẠ (GDAL, không chạy trên sandbox)
ogr2ogr -f "PostgreSQL" \
  PG:"host=db user=analyst dbname=gis password=..." \
  districts_vn2000.shp \
  -nln districts \                # tên bảng đích
  -t_srs EPSG:4326 \              # reproject sang 4326
  -lco GEOMETRY_NAME=geom \       # đặt tên cột hình học
  -lco FID=id \
  -nlt PROMOTE_TO_MULTI           # ép về MultiPolygon cho đồng nhất

Ví dụ 2 — GeoJSON → PostGIS:

# MINH HOẠ (GDAL)
ogr2ogr -f "PostgreSQL" \
  PG:"host=db user=analyst dbname=gis" \
  branches.geojson \
  -nln branches \
  -t_srs EPSG:4326 \
  -lco GEOMETRY_NAME=geom

Ví dụ 3 — chuyển file sang file (Shapefile → GeoPackage), không đụng CSDL:

# MINH HOẠ (GDAL) — hiện đại hoá định dạng
ogr2ogr -f "GPKG" districts.gpkg districts.shp -t_srs EPSG:4326

Cú pháp ogr2ogr <đích> <nguồn> (đích đứng trước) hơi phản trực giác — nhớ kỹ để khỏi ghi đè nhầm.

shp2pgsql — nạp Shapefile chuyên biệt cho PostGIS

shp2pgsql đi kèm PostGIS, chỉ làm một việc: chuyển Shapefile thành script SQL INSERT, rồi psql chạy script đó. Cổ điển nhưng vẫn rất hay dùng vì gắn liền hệ sinh thái PostGIS:

# MINH HOẠ — sinh SQL rồi nạp thẳng qua psql
shp2pgsql -s 3405:4326 -I -g geom districts.shp public.districts \
  | psql -h db -U analyst -d gis
#   -s 3405:4326  = nguồn VN-2000(3405) → đích 4326 (reproject)
#   -I            = tạo GIST index luôn
#   -g geom       = tên cột hình học

So với ogr2ogr, shp2pgsql chỉ nhận Shapefile nhưng bù lại cờ -I tạo GIST index sẵn và tích hợp mượt với psql.

QGIS — nạp trực quan

QGIS (bàn làm việc desktop giới thiệu ở GIS 1) cho phép kéo-thả file vào, xem trước trên bản đồ, kiểm tra CRS/thuộc tính bằng mắt, rồi xuất thẳng vào PostGIS qua menu (DB Manager). Ưu điểm: thấy dữ liệu trước khi nạp, phát hiện ngay CRS sai hay hình méo. Hợp cho công việc thủ công, một lần; với pipeline tự động lặp lại thì ogr2ogr trong script vẫn là chuẩn.

ST_AsGeoJSON — xuất từ PostGIS ra web

Chiều ngược lại: khi dữ liệu đã nằm trong PostGIS và cần phục vụ cho bản đồ web, ST_AsGeoJSON biến geometry thành GeoJSON để API trả về:

-- MINH HOẠ (PostGIS) — xuất branches thành 1 FeatureCollection GeoJSON
SELECT json_build_object(
  'type', 'FeatureCollection',
  'features', json_agg(
    json_build_object(
      'type', 'Feature',
      'geometry', ST_AsGeoJSON(geom)::json,
      'properties', json_build_object('name', name)
    )
  )
) AS geojson
FROM branches;

Đây chính là cầu nối PostGIS → trình duyệt, chi tiết ở GIS 5.

Pipeline dữ liệu không gian trong ngân hàng

Ghép mọi mảnh trên lại, một pipeline nạp dữ liệu không gian điển hình cho ngân hàng gom nhiều nguồn khác nhau về một PostGIS thống nhất:

Ba nhóm nguồn chính:

  1. Ranh giới hành chính (quận/huyện/xã) — tải từ GADM hoặc OpenStreetMap, thường ở Shapefile/GeoPackage, CRS có thể là 4326 hoặc VN-2000.
  2. Danh sách điểm nội bộ — chi nhánh, PGD, ATM: bảng nội bộ đã có cột lat/lon, chỉ cần dựng ST_MakePoint(lon, lat) thành Point 4326.
  3. Vị trí khách hàng — thường chỉ có địa chỉ dạng chữ, phải geocode (địa chỉ → toạ độ) mới thành điểm.

Mọi nguồn đi qua cùng một bước chuẩn hoá CRS về 4326, rồi nạp vào PostGIS với GIST index, sau đó phục vụ phân tích (GIS 3) và bản đồ (GIS 5).

Geocoding & reverse geocoding

Geocoding là chuyển địa chỉ dạng chữ → toạ độ: "144 Xuân Thuỷ, Cầu Giấy, Hà Nội"(105.782, 21.036). Đây là bước sinh dữ liệu điểm cho khách hàng, vốn ban đầu chỉ có địa chỉ text. Công cụ thường dùng: dịch vụ như Nominatim (OSM), Google Geocoding API, hoặc geocoder nội bộ. Reverse geocoding làm chiều ngược lại — toạ độ → địa chỉ/địa danh gần nhất, ví dụ từ GPS của giao dịch app suy ra "khách đang ở quận nào".

Geocoding là nguồn sai số lớn: địa chỉ Việt Nam viết không chuẩn ("ngõ", "tổ", "khu phố"), trùng tên đường, thiếu số nhà → geocoder trả điểm lệch hoặc rơi về tâm phường (fallback). Vì vậy kết quả geocode nên kèm mức độ tin cậy (rooftop / street / district-centroid) để phân tích sau biết lọc.

Chất lượng dữ liệu không gian

Dữ liệu không gian có những lỗi chất lượng đặc thù mà kiểm tra dữ liệu thường bỏ sót:

  • Toạ độ sai / đảo trục. Đảo lat/lon (nhập (21.03, 105.80) thay vì (105.80, 21.03)) đưa điểm Hà Nội ra tận châu Phi. Kiểm nhanh: điểm VN phải có lon ∈ [102, 110], lat ∈ [8, 24].
  • Toạ độ (0, 0) hoặc NULL — "Null Island", thường là giá trị mặc định khi geocode thất bại; phải lọc, không được tính là điểm thật.
  • CRS lẫn lộn. Trộn dữ liệu ở nhiều CRS mà quên reproject là lỗi âm thầm nhất — không báo lỗi, chỉ ra kết quả sai. Luôn kiểm ST_SRID(geom) đồng nhất sau khi nạp.
  • Hình học không hợp lệ — polygon tự cắt, vòng không khép: ST_IsValid(geom) phát hiện, ST_MakeValid(geom) sửa.
  • Trùng lặp / lệch phiên bản ranh giới — hai bộ ranh giới quận từ hai năm khác nhau không khớp biên.

Đây thực chất là một lát cắt không gian của bài toán chất lượng dữ liệu chung; nguyên tắc và quy trình kiểm soát nằm ở data quality — GIS chỉ thêm các luật kiểm đặc thù toạ độ/CRS/hình học ở trên.

Loại suy trên sandbox: gom theo địa bàn

Sandbox không có PostGIS lẫn ogr2ogr, nên không thể nạp dữ liệu không gian thật. Nhưng bản chất bước cuối của pipeline — "gom dữ liệu theo địa bàn để phục vụ" — với dữ liệu đã chuẩn hoá thì chỉ là một GROUP BY. Đây là phiên bản non-spatial chạy thật trên schema sandbox (customers có cột city), làm phép loại suy cho ý "sau khi nạp, dữ liệu sẵn sàng cho tổng hợp theo vùng":

-- ▶ Chạy được
SELECT city,
       COUNT(*) AS so_khach
FROM customers
GROUP BY city
ORDER BY so_khach DESC;

Khác biệt cốt lõi: ở đây citychuỗi đã chuẩn hoá sẵn nên chỉ cần gom theo cột. Trong pipeline GIS thật, "địa bàn" chưa có sẵn — nó được suy ra từ toạ độ sau khi geocode và spatial join (GIS 3). Toàn bộ công đoạn định dạng + nạp + chuẩn hoá CRS ở bài này chính là thứ biến một cột city viết tay thành một cột toạ độ chính xác, mở khoá mọi phép đo không gian.

Use case thực tế

Bối cảnh NCB — dựng lớp dữ liệu không gian nền tảng cho toàn bộ phân tích địa bàn.

Đội Data cần một lần dựng "nền không gian" để các bài phân tích sau (GIS 3, GIS 6) tái dùng. Nguồn dữ liệu ba loại, ba định dạng, ba CRS khác nhau:

  1. Ranh giới 63 tỉnh + quận/huyện tải từ GADM ở Shapefile, CRS VN-2000. Nạp bằng ogr2ogr ... -t_srs EPSG:4326 -nlt PROMOTE_TO_MULTI, đồng thời sửa tên cột bị cắt 10 ký tự và encoding tiếng Việt (.cpg UTF-8).
  2. ~400 chi nhánh/PGD + ~2.000 ATM từ bảng core nội bộ đã có lat/lon. Chỉ cần INSERT ... ST_SetSRID(ST_MakePoint(lon, lat), 4326) — không qua file.
  3. ~1,2 triệu địa chỉ khách dạng text, đưa qua geocoder Nominatim nội bộ. Kết quả kèm cờ tin cậy; ~8% rơi về tâm phường và ~1% thất bại (Null Island) bị lọc/đánh dấu để rà thủ công.

Sau khi cả ba nguồn về cùng EPSG:4326 và đánh GIST index, đội chạy bộ kiểm chất lượng: ST_IsValid trên ranh giới (sửa vài polygon tự cắt bằng ST_MakeValid), kiểm bounding box VN để bắt toạ độ đảo trục, và đối chiếu ST_SRID đồng nhất. Cuối cùng, một API dùng ST_AsGeoJSON phục vụ bản đồ nội bộ.

Kết quả: một lớp nền không gian sạch, cùng CRS, có index — nạp một lần, dùng cho mọi phân tích và bản đồ về sau, thay vì mỗi đội tự tải file và tự reproject theo cách khác nhau (nguồn gốc của "CRS lẫn lộn"). Chuẩn hoá đầu vào ở khâu nạp chính là cách rẻ nhất để chặn lỗi không gian trước khi chúng lan vào phân tích.

Ghi nhớ

  • Dữ liệu không gian đến dưới dạng file với nhiều định dạng, mỗi file mang một CRS — nạp = đọc đúng định dạng + reproject về CRS thống nhất (khuyến nghị EPSG:4326) + GIST index.
  • Vector: Shapefile (kinh điển nhưng hạn chế tên cột 10 ký tự, 2GB, nhiều file), GeoJSON (chuẩn web, luôn 4326 và [lon, lat]), GeoPackage (SQLite, một file, hiện đại), KML/KMZ (Google Earth), WKT/WKB (biểu diễn hình học trong CSDL), TopoJSON (GeoJSON tối ưu topology). Raster: GeoTIFF.
  • Công cụ: ogr2ogr (GDAL — chuyển mọi định dạng + reproject), shp2pgsql (nạp Shapefile vào PostGIS, -I tạo index), QGIS (nạp trực quan), ST_AsGeoJSON (xuất PostGIS ra web).
  • CRS/EPSG: 4326 (kinh/vĩ độ), 3857 (Web Mercator), 32648 (UTM 48N mét), VN-2000. Luôn biết CRS nguồn và reproject; quên bước này là lỗi âm thầm nghiêm trọng nhất.
  • Pipeline ngân hàng: ranh giới (GADM/OSM) + điểm nội bộ (lat/lon) + địa chỉ khách (geocoding) → chuẩn hoá CRS → PostGIS → phục vụ phân tích/bản đồ.
  • Chất lượng không gian: toạ độ đảo trục, Null Island (0,0), CRS lẫn lộn, hình học không hợp lệ — một lát cắt của data quality.
  • Trên sandbox không có PostGIS/GDAL: mọi lệnh GIS là minh hoạ; chỉ câu gộp theo city trên customers chạy thật — loại suy cho "gom theo địa bàn" sau khi dữ liệu đã sẵn sàng.

Bài viết liên quan

Các kỹ thuật phân tích không gian tạo giá trị kinh doanh cho ngân hàng: phân tích mật độ & hotspot, gom cụm ST_ClusterDBSCAN/KMeans, tự tương quan không gian (Moran's I), chọn địa điểm ATM/chi nhánh bằng service area, isochrone và overlay đa lớp. Nối tiếp bài truy vấn không gian, minh hoạ bằng SQL PostGIS và quy trình site selection.

13 thg 7, 2026 4

Nhập môn dữ liệu không gian (spatial/geospatial): dữ liệu gắn vị trí trên Trái Đất, các loại hình học điểm/đường/vùng, hệ toạ độ CRS/SRID (WGS84, UTM/VN2000), vector vs raster, quan hệ và phép đo không gian. Đặt nền cho cả series GIS và giá trị của nó với ngân hàng NCB: mạng lưới chi nhánh/ATM, phân tích khách hàng theo địa bàn, rủi ro và gian lận theo vị trí.

13 thg 7, 2026 4

Biến dữ liệu không gian thành bản đồ để ra quyết định. Bản đồ chuyên đề: choropleth (phải chuẩn hoá), symbol/bubble, heatmap, cluster, flow map — chọn theo dữ liệu. Công cụ: QGIS, Leaflet/Mapbox GL/deck.gl/Kepler.gl, bản đồ trong Power BI & Superset; tile OSM, level of detail. Luồng PostGIS → GeoJSON (ST_AsGeoJSON) → web map, nguyên tắc thiết kế và cạm bẫy. Bối cảnh NCB: dashboard dư nợ/huy động/khách theo tỉnh cho lãnh đạo.

13 thg 7, 2026 3

PostGIS biến PostgreSQL thành cơ sở dữ liệu không gian đầy đủ. Bài này đi từ cài đặt CREATE EXTENSION, kiểu geometry vs geography, SRID/EPSG:4326, cách nhập điểm bằng ST_MakePoint/ST_GeomFromText, các hàm cốt lõi (ST_Distance, ST_DWithin, ST_Contains, ST_Buffer, ST_Transform...), chỉ mục GIST bắt buộc cho hiệu năng, tới bài toán tìm ATM/chi nhánh trong bán kính quanh khách hàng NCB.

13 thg 7, 2026 3