Phân Tích Định Tuyến Không Gian với pgRouting trên ServBay
pgRouting
là một module mở rộng mạnh mẽ cho cơ sở dữ liệu PostgreSQL và PostGIS, chuyên cung cấp các chức năng định tuyến và phân tích mạng phong phú cho dữ liệu không gian. Với pgRouting
, các nhà phát triển có thể thực hiện những truy vấn phức tạp trên dữ liệu mạng đường, ví dụ như tìm đường đi ngắn nhất giữa hai điểm, giải bài toán người đi giao hàng (TSP) hoặc phân tích vùng phục vụ. Những tính năng này đặc biệt hữu ích trong việc xây dựng các ứng dụng bản đồ, lên kế hoạch logistics, phân tích giao thông và nhiều kịch bản khác.
Bài viết này sẽ hướng dẫn chi tiết cách kích hoạt nhanh chóng pgRouting cho cơ sở dữ liệu PostgreSQL trong môi trường phát triển Web cục bộ ServBay, cũng như cấu hình cơ bản và thực hiện các phân tích định tuyến.
Tổng quan
ServBay mang lại môi trường phát triển tích hợp tiện lợi trên macOS, bao gồm nhiều máy chủ Web, cơ sở dữ liệu và ngôn ngữ lập trình. Gói PostgreSQL của ServBay đã tích hợp sẵn các tiện ích mở rộng pgRouting
và PostGIS
. Điều này có nghĩa bạn không cần tải về hay biên dịch thủ công các module này, chỉ đơn giản kích hoạt chúng trong cơ sở dữ liệu là có thể sử dụng ngay.
Yêu cầu trước khi bắt đầu
Trước khi sử dụng pgRouting
, cần đảm bảo các điều kiện sau:
- Đã cài đặt và chạy ServBay: Nếu chưa cài, hãy truy cập Trang chủ ServBay để tải và cài đặt phiên bản mới nhất.
- Đã cài đặt và khởi động PostgreSQL trên ServBay: Kiểm tra trong giao diện ServBay đảm bảo gói PostgreSQL đã được cài và đang hoạt động.
- Có kiến thức cơ bản về SQL và PostgreSQL: Bài viết này giả định bạn đã quen thao tác cơ bản với cơ sở dữ liệu PostgreSQL và câu lệnh SQL.
- Hiểu cơ bản về PostGIS:
pgRouting
phụ thuộc vàoPostGIS
để làm việc với kiểu dữ liệu địa lý. Đảm bảo bạn đã kích hoạt tiện ích PostGIS trên cơ sở dữ liệu. Gói PostgreSQL của ServBay đã tích hợp sẵn PostGIS.
Cài đặt và Kích hoạt tiện ích pgRouting
ServBay đã chuẩn bị sẵn tập tin tiện ích pgRouting
cho bạn, chỉ cần bật lên trong cơ sở dữ liệu mong muốn là có thể sử dụng.
Kết nối vào cơ sở dữ liệu PostgreSQL:
Bạn có thể sử dụng nhiều cách kết nối (như dòng lệnh
psql
, công cụ giao diện đồ họa như pgAdmin, DBeaver hoặc qua thư viện ngôn ngữ lập trình).Kết nối bằng công cụ dòng lệnh
psql
mà ServBay cung cấp là cách đơn giản và hiệu quả. Có thể mở nhanh terminal đã thiết lập sẵn biến môi trường qua nút “Terminal” trong ServBay, hoặc tự thêm thư mục bin của ServBay vào PATH.Ví dụ, để kết nối vào cơ sở dữ liệu
servbay_geo_db
với user mặc địnhservbay
, chạy lệnh sau trong terminal:bashpsql -U servbay -d servbay_geo_db
1Nếu tên user, tên database hoặc mật khẩu của bạn khác, hãy thay đổi cho phù hợp.
Kiểm tra và kích hoạt tiện ích PostGIS (nếu chưa bật):
pgRouting
yêu cầu cóPostGIS
. Trong terminalpsql
, nhập:sqlCREATE EXTENSION IF NOT EXISTS postgis;
1Lệnh này sẽ tạo tiện ích PostGIS nếu chưa có.
Kích hoạt tiện ích pgRouting:
Vẫn trong kết nối cơ sở dữ liệu, chạy lệnh SQL sau để tạo tiện ích
pgRouting
:sqlCREATE EXTENSION pgrouting;
1Nếu thành công, sẽ có thông báo
CREATE EXTENSION
.Kiểm tra cài đặt:
Hiển thị danh sách tiện ích đã cài để kiểm chứng:
sql\dx
1Bạn sẽ thấy tên
postgis
vàpgrouting
xuất hiện cùng các thông tin liên quan.
Cấu hình pgRouting: Chuẩn bị dữ liệu mạng đường và tạo Topology
Các thuật toán của pgRouting
cần hoạt động trên bảng mạng đường thể hiện cấu trúc mạng lưới. Thông thường đó là một bảng chứa các đoạn đường (LineString), mỗi đoạn có điểm đầu, điểm cuối và trọng số (ví dụ chiều dài, thời gian di chuyển). Để định tuyến hiệu quả, cần xây dựng một cấu trúc topology—mô tả sự kết nối giữa các đoạn đường (các nút giao).
Tạo bảng lưu dữ liệu mạng đường
Ví dụ sau cho thấy cách tạo bảng ways
để lưu dữ liệu mạng đường:
-- Tạo bảng lưu dữ liệu mạng đường
CREATE TABLE ways (
id SERIAL PRIMARY KEY, -- Mã duy nhất của đoạn đường
source INTEGER, -- ID nút bắt đầu
target INTEGER, -- ID nút kết thúc
cost DOUBLE PRECISION, -- Trọng số di chuyển theo chiều thuận (ví dụ: dài, thời gian)
reverse_cost DOUBLE PRECISION, -- Trọng số di chuyển ngược chiều
geom GEOMETRY(LineString, 4326) -- Hình học đoạn đường, kiểu LineString với SRID 4326 (WGS 84)
);
2
3
4
5
6
7
8
9
Giải thích:
SERIAL PRIMARY KEY
: Tạo mã duy nhất tự động cho mỗi đoạn đường.source
,target
: ID của nút đầu và nút cuối trên topology. Sẽ được tạo hoặc liên kết tự động khi xây dựng topology.cost
,reverse_cost
: Định nghĩa trọng số (như chiều dài, thời gian). Nếu là đường một chiều,reverse_cost
có thể để NULL hoặc giá trị rất lớn.geom
: Lưu thông tin hình học bằng kiểu của PostGIS.LineString
là dạng đoạn thẳng,4326
là SRID phổ biến (tọa độ WGS 84 toàn cầu).
Thêm dữ liệu mẫu
Chèn một số đoạn đường mẫu vào bảng ways
:
-- Thêm các đoạn đường mẫu
INSERT INTO ways (source, target, cost, reverse_cost, geom) VALUES
(1, 2, 1.0, 1.0, ST_SetSRID(ST_MakeLine(ST_MakePoint(116.4074, 39.9042), ST_MakePoint(116.4084, 39.9052)), 4326)),
(2, 3, 1.0, 1.0, ST_SetSRID(ST_MakeLine(ST_MakePoint(116.4084, 39.9052), ST_MakePoint(116.4094, 39.9062)), 4326)),
(3, 4, 1.0, 1.0, ST_SetSRID(ST_MakeLine(ST_MakePoint(116.4094, 39.9062), ST_MakePoint(116.4104, 39.9072)), 4326));
2
3
4
5
Giải thích:
ST_MakePoint(x, y)
: Tạo điểm với kinh độ, vĩ độ.ST_MakeLine(point1, point2)
: Tạo đoạn thẳng qua hai điểm.ST_SetSRID(geometry, srid)
: Gán hệ tọa độ cho hình học.- Dữ liệu mẫu gồm ba đoạn nối tiếp nhau, mỗi đoạn có trọng số 1.0. Vị trí là một khu vực ở Hà Nội/Bắc Kinh dùng làm demo.
Tạo topology
Sau khi có dữ liệu mạng đường, sử dụng hàm pgr_createTopology
để tạo topology. Hàm này sẽ phân tích các đoạn đường, nhận diện các nút giao (node), đồng thời điền giá trị vào cột source
và target
của bảng bạn cũng như sinh ra bảng nút giao mới (thường tên là [tên_bảng]_vertices_pgr
).
-- Tạo topology cho dữ liệu mạng đường
-- Các tham số:
-- 'ways': tên bảng mạng đường
-- 0.00001: giá trị dung sai, giúp phân biệt các nút giao gần nhau
-- 'geom': tên cột chứa hình học
-- 'id': tên cột chứa ID đoạn đường
SELECT pgr_createTopology('ways', 0.00001, 'geom', 'id');
2
3
4
5
6
7
Giải thích:
pgr_createTopology
: Hàm "xương sống" của pgRouting, xây dựng mô hình topology node-edge.- Giá trị dung sai (tolerance) giúp nhóm những điểm rất gần nhau thành một nút giao duy nhất. Giá trị này tùy chỉnh dựa trên chất lượng và độ chính xác dữ liệu của bạn.
Sau khi thực thi, cột source
và target
của bảng ways
sẽ được điền, đồng thời tạo bảng ways_vertices_pgr
chứa tất cả các nút giao với tọa độ tương ứng.
Thực hiện phân tích định tuyến bằng pgRouting
Sau khi đã xây dựng topology, bạn có thể thực hiện các loại phân tích định tuyến phong phú mà pgRouting cung cấp. Dưới đây là một số ví dụ thường dùng.
Phân tích đường đi ngắn nhất (Dijkstra)
Tìm đường đi ngắn nhất giữa hai nút là nhu cầu phổ biến nhất. pgRouting hỗ trợ thuật toán Dijkstra như sau:
-- Tìm đường đi ngắn nhất từ nút 1 đến nút 4
-- Tham số:
-- 'SELECT id, source, target, cost FROM ways': truy vấn dùng để tạo đồ thị, bắt buộc đủ 4 cột id, source, target, cost
-- 1: id nút bắt đầu
-- 4: id nút kết thúc
-- directed := true: chỉ định đồ thị có hướng (ngược chiều có thể khác trọng số)
SELECT seq, id1 AS node, id2 AS edge, cost, geom
FROM pgr_dijkstra(
'SELECT id, source, target, cost FROM ways',
1, -- ID nút bắt đầu
4, -- ID nút kết thúc
directed := true -- muốn tính cả reverse_cost có thể để false hoặc bỏ qua tham số này
)
JOIN ways ON edge = ways.id; -- Nối kết quả với bảng ways cực kỳ hữu ích để lấy hình học cho trực quan hóa
2
3
4
5
6
7
8
9
10
11
12
13
14
Giải thích:
pgr_dijkstra
: Gọi thuật toán đường đi ngắn nhất Dijkstra.- Tham số đầu là truy vấn trả về dữ liệu đoạn đường, ít nhất gồm
id
,source
,target
,cost
. Nếu muốn tính cả chiều ngược, bổ sung thêmreverse_cost
và đểdirected = false
. - Tham số tiếp là id nút bắt đầu, sau đó là id nút đích.
- Kết quả nối với bảng gốc để lấy hình học (
geom
), nhằm tiện cho hiển thị trên bản đồ.
Bài toán người giao hàng (Traveling Salesperson Problem - TSP)
TSP tìm vòng đường tối ưu qua loạt điểm (node) chỉ định xuất phát từ một điểm.
-- Giải TSP qua các nút 1, 2, 3, 4, bắt đầu tại nút 1
-- Tham số:
-- 'SELECT id, x::float8 AS x, y::float8 AS y FROM ways_vertices_pgr': truy vấn danh sách node cần đi qua cùng toạ độ
-- start_id := 1: id nút bắt đầu
SELECT seq, node, edge, cost
FROM pgr_tsp(
'SELECT id, ST_X(the_geom)::float8 AS x, ST_Y(the_geom)::float8 AS y FROM ways_vertices_pgr WHERE id IN (1, 2, 3, 4)',
start_id := 1
);
2
3
4
5
6
7
8
9
Giải thích:
pgr_tsp
: Thực hiện thuật toán TSP.- Truy vấn đầu vào phải trả về ba cột:
id
,x
,y
—thường lấy từ bảngways_vertices_pgr
mới tạo ở bước topology. - Tham số
start_id
chỉ định điểm xuất phát.
Phân tích vùng phục vụ (Driving Distance / Driving Time)
Xác định tất cả khu vực hoặc đoạn đường mà từ một điểm xuất phát có thể đi được trong phạm vi giới hạn chi phí nhất định (ví dụ khoảng cách, thời gian).
-- Từ nút 1 tìm các đoạn có thể đi tới trong giới hạn chi phí 2
-- Tham số:
-- 'SELECT id, source, target, cost FROM ways': truy vấn mạng lưới
-- 1: id nút xuất phát
-- 2: chi phí tối đa cho phép
-- directed := true: đồ thị có hướng
SELECT seq, id1 AS node, id2 AS edge, cost, geom
FROM pgr_drivingDistance(
'SELECT id, source, target, cost FROM ways',
1, -- ID nút bắt đầu
2, -- Chi phí tối đa cho phép
directed := true
)
JOIN ways ON edge = ways.id; -- Nối kết quả lấy hình học phục vụ trực quan hóa
2
3
4
5
6
7
8
9
10
11
12
13
14
Giải thích:
pgr_drivingDistance
: Thuật toán phân tích vùng phục vụ.- Tham số giống như với Dijkstra.
- Tham số chi phí là giới hạn phạm vi (ví dụ tổng chiều dài đường đi).
- JOIN để lấy hình học hiển thị bản đồ.
Trực quan hóa kết quả định tuyến
Việc hiển thị kết quả phân tích định tuyến giúp dễ hiểu cũng như trình bày trực quan hơn. Bạn có thể dùng phần mềm GIS máy tính bàn hoặc tích hợp thư viện bản đồ vào Web.
Dùng công cụ GIS máy tính bàn (VD: QGIS)
QGIS là phần mềm mã nguồn mở mạnh mẽ giúp kết nối trực tiếp tới cơ sở dữ liệu PostgreSQL/PostGIS và hiển thị dữ liệu không gian, bao gồm cả kết quả từ pgRouting.
- Mở QGIS.
- Chọn Layer (Lớp) > Data Source Manager (Quản lý nguồn dữ liệu).
- Chọn PostGIS ở menu bên trái.
- Nhấn New để tạo kết nối cơ sở dữ liệu mới.
- Điền thông tin kết nối PostgreSQL trên ServBay (ví dụ Host:
localhost
, Port:5432
, Database:servbay_geo_db
, User:servbay
, Password: mật khẩu của bạn). Có thể kiểm tra kết nối ngay ở bước này. - Kết nối thành công, hãy mở rộng database sẽ thấy bảng dữ liệu như
ways
vàways_vertices_pgr
. - Chọn bảng hoặc view (ví dụ dữ liệu kết quả tuyến đường ngắn nhất) và nhấn Add (Thêm) để đưa vào QGIS hiển thị.
Hiển thị trên Web (Leaflet hoặc OpenLayers)
Đối với ứng dụng Web, bạn cần có backend (ví dụ PHP, Node.js, Python chạy qua ServBay) thực thi truy vấn pgRouting và trả kết quả về (thường qua định dạng GeoJSON) cho frontend. Frontend sẽ dùng thư viện bản đồ như Leaflet hoặc OpenLayers để hiển thị dữ liệu địa lý.
Dưới đây là ví dụ HTML cơ bản mô tả thêm một tuyến cố định vào bản đồ Leaflet. Để hiển thị kết quả động, bạn cần:
- Thực thi truy vấn pgRouting ở backend.
- Chuyển đổi kết quả hình học sang GeoJSON hoặc định dạng phù hợp khác.
- Cung cấp GeoJSON qua API cho frontend.
- Dùng phương thức như
L.geoJSON
trong Leaflet để hiển thị.
<!DOCTYPE html>
<html>
<head>
<title>Demo trực quan hóa pgRouting bằng ServBay</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<style>
#map { height: 600px; width: 100%; } /* Kích thước vùng bản đồ */
</style>
</head>
<body>
<h1>Trực quan hóa kết quả pgRouting trên ServBay</h1>
<div id="map"></div>
<script>
// Khởi tạo bản đồ, điểm tâm và mức độ zoom
var map = L.map('map').setView([39.906, 116.409], 14); // Khu vực trung tâm vị trí mẫu
// Thêm nền bản đồ OpenStreetMap
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors'
}).addTo(map);
// Ví dụ: Thêm dữ liệu GeoJSON demo - thường sẽ được cung cấp động qua AJAX
var geojsonData = {
"type": "FeatureCollection",
"features": [
{
"type": "Feature",
"properties": {
"id": 1,
"cost": 1.0
},
"geometry": {
"type": "LineString",
"coordinates": [
[116.4074, 39.9042],
[116.4084, 39.9052]
]
}
},
{
"type": "Feature",
"properties": {
"id": 2,
"cost": 1.0
},
"geometry": {
"type": "LineString",
"coordinates": [
[116.4084, 39.9052],
[116.4094, 39.9062]
]
}
},
{
"type": "Feature",
"properties": {
"id": 3,
"cost": 1.0
},
"geometry": {
"type": "LineString",
"coordinates": [
[116.4094, 39.9062],
[116.4104, 39.9072]
]
}
}
]
};
// Thêm GeoJSON vào bản đồ
L.geoJSON(geojsonData, {
style: function (feature) {
return {color: "#ff0000", weight: 4}; // Vẽ tuyến bằng màu đỏ, nét dày
}
}).addTo(map);
// Canh lại bản đồ để vừa với các đối tượng tuyến vừa thêm
if (L.geoJSON(geojsonData).getBounds().isValid()) {
map.fitBounds(L.geoJSON(geojsonData).getBounds());
}
</script>
</body>
</html>
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
Lưu file HTML này vào thư mục gốc Web trên ServBay của bạn (ví dụ /Applications/ServBay/www/pgrouting-demo/index.html
), và truy cập qua ServBay (chẳng hạn http://pgrouting-demo.servbay.demo
) sẽ thấy bản đồ hiển thị tuyến mẫu. Đây là dữ liệu tĩnh, nếu muốn động cần bổ sung backend như đã hướng dẫn.
Lưu ý
- Chất lượng dữ liệu: Kết quả của pgRouting phụ thuộc hoàn toàn vào chất lượng dữ liệu mạng đường. Đảm bảo dữ liệu chính xác, đầy đủ và topology hợp lý.
- Hiệu năng: Khi mạng đường lớn, truy vấn định tuyến sẽ tiêu tốn nhiều tài nguyên. Nên dùng index, đơn giản mạng lưới hoặc lựa chọn thuật toán hiệu quả cho trường hợp cụ thể.
- Bộ nhớ: Đối với topology lớn, cần nhiều RAM trên máy chủ database.
Câu hỏi thường gặp (FAQ)
Q: Khi chạy CREATE EXTENSION pgrouting;
bị báo lỗi chưa có extension thì xử lý thế nào? A: Đầu tiên, kiểm tra gói PostgreSQL của ServBay đã cài và chạy đúng chưa. Sau đó chắc chắn database bạn sử dụng tương thích pgRouting và phiên bản PostgreSQL của ServBay có tích hợp sẵn extension này (thường là có). Nếu vẫn lỗi, xem log của ServBay/PostgreSQL để biết chi tiết. Đảm bảo bạn kết nối bằng user đủ quyền hạn (như servbay
).
Q: Giá trị tolerance trong hàm pgr_createTopology
nên chọn bao nhiêu? A: Giá trị này phụ thuộc vào độ chính xác của dữ liệu không gian của bạn. Nó là khoảng cách nhỏ nhất để hai điểm được xem là cùng một nút. Nếu vị trí rất chính xác (bằng GPS cao), có thể chọn 0.000001 hoặc nhỏ hơn. Nếu dữ liệu thô hoặc từ nhiều nguồn, giá trị nên cao hơn để đảm bảo các đoạn giao nhau tạo đúng nút. Nếu để quá lớn, có thể nối nhầm các đoạn không liên quan.
Q: Làm sao xử lý đường một chiều hoặc các luật cấm quay đầu? A: Hai trường cost
và reverse_cost
trong bảng ways
cho phép thiết lập hướng đi. Nếu là đường một chiều, đặt reverse_cost
là NULL hoặc giá trị rất lớn. Đối với luật giao thông như cấm quay đầu, thường cần mô hình mạng đường phức tạp hơn hoặc xử lý hậu kỳ—pgRouting cũng cung cấp các chức năng nâng cao hỗ trợ.
Tổng kết
Với ServBay, việc thiết lập môi trường phát triển cục bộ cho PostgreSQL hỗ trợ pgRouting rất đơn giản. Bạn chỉ cần các câu lệnh SQL cơ bản để kích hoạt extension, nhập dữ liệu mạng đường, xây dựng topology là đã có thể tận dụng sức mạnh định tuyến không gian của pgRouting. Kết hợp với công cụ GIS máy tính bàn hoặc thư viện bản đồ Web, bạn dễ dàng trực quan hóa kết quả định tuyến và cung cấp dữ liệu không gian mạnh mẽ cho ứng dụng Web hoặc dự án GIS của mình. ServBay đã đơn giản hóa công đoạn thiết lập môi trường, giúp nhà phát triển tập trung tối đa vào logic và chức năng ứng dụng.