🇬🇧 Read the English version of this article on tanhdev.com
GraphHopper Distance Matrix Là Gi?
Answer-first: GraphHopper distance matrix là API endpoint /matrix thuộc thư viện định tuyến mã nguồn mở (open-source routing engine) GraphHopper. Nó tiếp nhận thông tin tọa độ của N điểm trạm và trả về một ma trận kết quả kích cỡ N×N chứa toàn bộ dữ liệu thời gian di chuyển (tính theo giây) và độ dài khoảng cách (tính theo mét) dựa trên mạng lưới giao thông thực tế được cung cấp bởi bản đồ OpenStreetMap — hoàn toàn miễn phí khi bạn chọn cách tự triển khai (self-hosted). Với quy mô 100 điểm dừng giao hàng (delivery stops), cỗ máy này dễ dàng xử lý toàn bộ 10,000 cặp lộ trình chỉ trong khoảng thời gian dưới 50 mili-giây (50ms) ngay trên một máy chủ VPS thông thường.
Nội dung dưới đây trình bày chi tiết mọi kỹ thuật bạn cần để vận hành GraphHopper distance matrix hiệu quả trong môi trường production: triển khai Docker, sử dụng /matrix API, sử dụng Custom Models để thiết lập quy tắc cho xe tải/xe máy, dựng tầng cache H3-based cho Redis, và cuối cùng là đánh giá trực quan và so sánh cùng OSRM, Valhalla, và Google Maps (để hiểu sâu hơn về việc chọn lựa routing engine, hãy xem bài So sánh Kiến trúc OSRM và GraphHopper).
Tại Sao Nên Chọn GraphHopper Distance Matrix?
Khi lựa chọn các công cụ định tuyến mã nguồn mở nhằm tính toán khoảng cách ma trận (route distance matrix computation), người ta thường nhắc đến ba giải pháp chính là Haversine (tính toán khoảng cách theo đường chim bay), OSRM (viết bằng C++, tốc độ rất cao nhưng cấu hình cứng - rigid profiles), và GraphHopper (viết bằng Java, độ linh hoạt cao nhờ tính năng Custom Models). Bên cạnh đó là giải pháp dịch vụ API trả phí (Google Maps, HERE, Mapbox).
| Yếu Tố (Criterion) | GraphHopper | OSRM | Haversine | Google Maps |
|---|---|---|---|---|
| Chi Phí (Cost) | Miễn phí (self-hosted) | Miễn phí (self-hosted) | Miễn phí | $0.005/element |
| Độ Chuẩn Xác (Accuracy) | Theo đường nhựa ✅ | Theo đường nhựa ✅ | Đường chim bay ❌ | Đường nhựa + Kẹt xe ✅ |
| Thời Gian Xử Lý 100×100 | ~50ms | ~20ms | <1ms | Từ 500ms+ |
| Thay đổi quy tắc định tuyến khi Runtime | ✅ Hỗ trợ Custom Models | ❌ Không (Cần recompile + Lua) | Miễn bàn (N/A) | Cần cấu hình thêm theo gói |
| Hỗ trợ SDK Java/Python | ✅ Hỗ trợ SDK Java Native | Gọi qua HTTP API | Hàng tích sẵn Native | Gọi qua HTTP API |
| Triển Khai Docker | ✅ Có ảnh chính thức (Official) | ✅ Có ảnh chính thức (Official) | N/A | N/A |
| Phù hợp nhất cho (Best for) | Đội xe hỗn hợp nhiều quy tắc | Tối ưu tốc độ cho một loại phương tiện | Lọc nhanh các vị trí ban đầu | Cần dữ liệu giao thông thực tế (ETA) |
Kinh Nghiệm Rút Ra (Rule of thumb): Nên dùng GraphHopper trong trường hợp hệ thống cần xử lý nhiều loại phương tiện với các quy tắc định tuyến (routing rules) khác nhau (ví dụ: giới hạn tải trọng xe tải, quy tắc di chuyển cho xe máy, hoặc tránh trạm thu phí). Trong khi đó, OSRM là lựa chọn tối ưu khi hệ thống chỉ phục vụ duy nhất một loại phương tiện và yêu cầu tốc độ phản hồi tối đa.
Hướng Dẫn Khởi Động Nhanh (Quick Start): GraphHopper Distance Matrix Với Docker
Bước 1: Khởi Động GraphHopper Server
Để chạy, GraphHopper sử dụng dữ liệu bản đồ dạng .osm.pbf từ OpenStreetMap. Bạn có thể tải miễn phí các bản cắt phân khu (regional extracts) từ trang Geofabrik.
# Tạo thư mục chứa dữ liệu (Create a data directory)
mkdir -p ./graphhopper-data
# Khởi chạy container GraphHopper — tự động tải bản đồ OSM Việt Nam
docker run -d \
--name graphhopper \
-p 8989:8989 \
-v $(pwd)/graphhopper-data:/data \
israelhikingmap/graphhopper:latest \
--url https://download.geofabrik.de/asia/vietnam-latest.osm.pbf \
--host 0.0.0.0
# Theo dõi log — quá trình xử lý đồ thị lần đầu mất khoảng 5-15 phút
docker logs -f graphhopper
Chờ cho đến khi xuất hiện dòng log: Started server at HTTP 0.0.0.0:8989
Bước 2: Thử Nghiệm Gọi Matrix API
# Gửi yêu cầu tính toán ma trận 3×3 cho 3 địa điểm tại TP.HCM
curl -X POST http://localhost:8989/matrix \
-H "Content-Type: application/json" \
-d '{
"points": [
[106.7011, 10.7712],
[106.7100, 10.7780],
[106.6980, 10.7650]
],
"profile": "car",
"out_arrays": ["times", "distances"],
"fail_fast": false
}'
⚠️ Lưu ý về định dạng tọa độ GeoJSON: GraphHopper sử dụng thứ tự tọa độ
[kinh độ longitude, vĩ độ latitude](thay vì[lat, lng]). Đây là lỗi phổ biến khi chuyển từ các thư viện khác sang.
Kết quả phản hồi (Response):
{
"times": [[0, 320, 185], [315, 0, 410], [180, 405, 0]],
"distances": [[0, 2100, 1350], [2050, 0, 2900], [1300, 2880, 0]],
"info": {"took": 12, "copyrights": ["OpenStreetMap contributors"]}
}
- Nhãn
times: ma trận N×N chứa thời gian đo bằng giây (seconds) - Nhãn
distances: ma trận N×N chỉ khoảng cách tính bằng mét (meters) - Đường chéo chính (Diagonal) có giá trị
0(khoảng cách và thời gian từ một điểm đến chính nó).
Xây Dựng Python Client Dành Cho Production
import requests
from dataclasses import dataclass
from typing import Optional
@dataclass
class Location:
lat: float
lng: float
label: Optional[str] = None
@dataclass
class DistanceMatrix:
durations: list[list[int]] # tính theo giây (seconds), ma trận N×N
distances: list[list[int]] # tính theo mét (meters), ma trận N×N
class GraphHopperClient:
"""
Python client cho GraphHopper Distance Matrix API đạt chuẩn Production-ready.
Tự động xử lý định dạng [lng, lat], quản lý lỗi và hỗ trợ cơ chế thử lại (retries).
"""
def __init__(self, base_url: str = "http://localhost:8989", profile: str = "car"):
self.base_url = base_url.rstrip("/")
self.profile = profile
self.session = requests.Session()
self.session.headers.update({"Content-Type": "application/json"})
def get_matrix(self, locations: list[Location], timeout: int = 30) -> DistanceMatrix:
"""
Tính toán ma trận khoảng cách N×N cho danh sách các địa điểm truyền vào.
Tham số (Args):
locations: Danh sách đối tượng Location (chứa lat/lng).
timeout: Thời gian chờ tối đa cho HTTP request (tính theo giây).
Kết quả (Returns):
Đối tượng DistanceMatrix chứa 'durations' (giây) và 'distances' (mét).
Ngoại lệ (Raises):
requests.HTTPError: Xảy ra khi GraphHopper trả về lỗi HTTP.
ValueError: Xảy ra nếu danh sách truyền vào có ít hơn 2 địa điểm.
"""
if len(locations) < 2:
raise ValueError("Cần tối thiểu 2 địa điểm để tính toán ma trận khoảng cách.")
# Cẩn thận: GraphHopper ăn theo chuẩn [lng, lat] — định dạng GeoJSON
points = [[loc.lng, loc.lat] for loc in locations]
payload = {
"points": points,
"profile": self.profile,
"out_arrays": ["times", "distances"],
"fail_fast": False, # Trả về kết quả cho các cặp hợp lệ ngay cả khi có cặp không tìm được đường đi
}
response = self.session.post(
f"{self.base_url}/matrix",
json=payload,
timeout=timeout
)
response.raise_for_status()
data = response.json()
return DistanceMatrix(
durations=data["times"],
distances=data["distances"],
)
# --- Khúc rải múa trình diễn cách xài (Usage example) ---
client = GraphHopperClient(base_url="http://localhost:8989", profile="car")
locations = [
Location(lat=10.7712, lng=106.7011, label="Kho hàng (Warehouse)"),
Location(lat=10.7780, lng=106.7100, label="Khách C (Customer A)"),
Location(lat=10.7650, lng=106.6980, label="Khách B (Customer B)"),
]
matrix = client.get_matrix(locations)
# In ma trận thời gian di chuyển (Print duration matrix)
for i, from_loc in enumerate(locations):
for j, to_loc in enumerate(locations):
if i != j:
duration_min = matrix.durations[i][j] // 60
distance_km = matrix.distances[i][j] / 1000
print(f"{from_loc.label} → {to_loc.label}: tốn {duration_min}min, khoảng {distance_km:.1f}km")
Quản Lý Cấu Hình Phương Tiện (Vehicle Profiles) Và Custom Models
Ưu điểm vượt trội của GraphHopper so với OSRM là tính năng Custom Models, cho phép thay đổi quy tắc định tuyến (routing rules) trực tiếp tại thời điểm chạy (runtime) mà không cần phải xử lý hay biên dịch lại dữ liệu bản đồ.
Cấu Hình Có Sẵn (Built-in Profiles)
# Cấu hình mặc định cho xe ô tô (car)
curl -X POST http://localhost:8989/matrix \
-d '{"points": [[106.7011, 10.7712], [106.7100, 10.7780]], "profile": "car", "out_arrays": ["times", "distances"]}'
# Cấu hình cho xe máy (motorcycle)
curl -X POST http://localhost:8989/matrix \
-d '{"points": [[106.7011, 10.7712], [106.7100, 10.7780]], "profile": "motorcycle", "out_arrays": ["times", "distances"]}'
# Cấu hình cho xe đạp (bike)
curl -X POST http://localhost:8989/matrix \
-d '{"points": [[106.7011, 10.7712], [106.7100, 10.7780]], "profile": "bike", "out_arrays": ["times", "distances"]}'
# Cấu hình cho người đi bộ (foot)
curl -X POST http://localhost:8989/matrix \
-d '{"points": [[106.7011, 10.7712], [106.7100, 10.7780]], "profile": "foot", "out_arrays": ["times", "distances"]}'
Tùy Biến Với Custom Models — Thay Đổi Quy Tắc Tại Thời Điểm Chạy (Runtime)
Tính năng Custom Models cho phép điều chỉnh hành vi định tuyến (routing behavior) linh hoạt mà không cần khởi động lại máy chủ hay biên dịch lại bản đồ. Đây là yếu tố then chốt cho các hệ thống logistics vận hành đội xe hỗn hợp (mixed fleets).
Ví dụ: Quy định định tuyến cho xe tải nặng (tránh đường cao tốc và hạn chế vào đường dân cư)
{
"points": [[106.7011, 10.7712], [106.7100, 10.7780]],
"profile": "car",
"out_arrays": ["times", "distances"],
"custom_model": {
"speed": [
{
"if": "road_class == MOTORWAY",
"limit_to": 90
},
{
"if": "road_environment == TUNNEL",
"multiply_by": 0
}
],
"priority": [
{
"if": "max_weight < 10",
"multiply_by": 0
},
{
"if": "road_class == RESIDENTIAL",
"multiply_by": 0.3
}
]
}
}
Ví dụ: Định tuyến né trạm thu phí (Toll-avoidance routing)
{
"custom_model": {
"priority": [
{
"if": "toll == ALL",
"multiply_by": 0
}
]
}
}
Trường hợp sử dụng thực tế (Real-world use case): Một doanh nghiệp logistics quản lý đồng thời cả xe máy giao hàng chặng cuối (last-mile) và xe tải 10 tấn có thể dùng chung một instance GraphHopper duy nhất. Bằng cách gửi kèm Custom Model tương ứng cho từng loại phương tiện trong mỗi request, hệ thống xử lý linh hoạt mà không cần duy trì nhiều hạ tầng khác nhau.
Triển Khai Dạng Nhúng Với Java SDK (Embedded Mode)
Đối với các hệ thống backend phát triển bằng Java, bạn có thể nhúng trực tiếp thư viện GraphHopper vào tiến trình ứng dụng (in-process). Cách làm này loại bỏ hoàn toàn chi phí truyền tải qua HTTP (zero HTTP overhead) khi tính toán ma trận khoảng cách.
import com.graphhopper.GraphHopper;
import com.graphhopper.GraphHopperConfig;
import com.graphhopper.config.CHProfile;
import com.graphhopper.config.Profile;
import com.graphhopper.routing.matrix.MatrixResult;
public class EmbeddedGraphHopperMatrix {
private final GraphHopper hopper;
public EmbeddedGraphHopperMatrix(String osmFile, String graphLocation) {
GraphHopperConfig config = new GraphHopperConfig();
config.putObject("graph.location", graphLocation);
this.hopper = new GraphHopper();
this.hopper.setOSMFile(osmFile);
this.hopper.setGraphHopperLocation(graphLocation);
this.hopper.setProfiles(
new Profile("car").setVehicle("car").setWeighting("fastest"),
new Profile("truck").setVehicle("car").setWeighting("custom")
);
this.hopper.getCHPreparationHandler()
.setCHProfiles(new CHProfile("car"));
this.hopper.importOrLoad();
}
// Phương thức tiện ích sử dụng GHMatrixAPI cho các tính toán N×N
// Tham khảo chi tiết tại: https://github.com/graphhopper/graphhopper/tree/master/web-api
public void shutdown() {
hopper.close();
}
}
So sánh giữa Embedded Mode và HTTP API:
- Embedded Mode: Độ trễ cực thấp (~1ms mỗi request) nhờ loại bỏ hoàn toàn network overhead. Phù hợp cho các Java microservices cần thực hiện hàng nghìn truy vấn ma trận mỗi giây.
- HTTP API: Không phụ thuộc ngôn ngữ lập trình (Language-agnostic), dễ dàng mở rộng hàng ngang (scale horizontally). Lựa chọn tối ưu cho các hệ thống đa ngôn ngữ hoặc ứng dụng viết bằng Python, Go, Node.js.
Chiến Lược Caching Ma Trận Với Redis Và Chỉ Mục Không Gian H3
Mạng lưới giao thông rất ít khi thay đổi. Việc lưu cache kết quả ma trận khoảng cách dựa trên cặp ô chỉ mục không gian H3 (H3 cell pairs) giúp giảm hơn 90% số lượng request đến GraphHopper khi hệ thống đi vào vận hành ổn định.
import h3
import json
import redis
from graphhopper_client import GraphHopperClient, Location, DistanceMatrix
class CachedDistanceMatrix:
"""
Tầng Caching cho GraphHopper Distance Matrix dựa trên chỉ mục H3 và Redis.
Tỷ lệ cache hit có thể đạt trên 90% khi hệ thống vận hành ổn định.
"""
H3_RESOLUTION = 9 # Mỗi ô H3 có bán kính ~174m (tương đương một khối nhà phố)
CACHE_TTL_DAYS = 30 # Dữ liệu đường xá ít thay đổi nên lưu cache 30 ngày
def __init__(self, gh_client: GraphHopperClient, redis_client: redis.Redis):
self.gh = gh_client
self.redis = redis_client
def _h3_key(self, loc_a: Location, loc_b: Location) -> str:
"""Tạo cache key chuẩn hóa từ hai H3 cell ID."""
cell_a = h3.latlng_to_cell(loc_a.lat, loc_a.lng, self.H3_RESOLUTION)
cell_b = h3.latlng_to_cell(loc_b.lat, loc_b.lng, self.H3_RESOLUTION)
# Sắp xếp hai cell ID để đảm bảo tính đối xứng (cặp A->B và B->A dùng chung một cache key)
return f"gh:matrix:{min(cell_a, cell_b)}:{max(cell_a, cell_b)}"
def get_pair(self, origin: Location, dest: Location) -> dict:
"""
Lấy thông tin khoảng cách và thời gian cho một cặp địa điểm từ Redis cache.
Kết quả (Returns): {"duration_s": int, "distance_m": int}
"""
cache_key = self._h3_key(origin, dest)
cached = self.redis.get(cache_key)
if cached:
return json.loads(cached)
# Khi cache miss: gọi GraphHopper API để tính toán
matrix = self.gh.get_matrix([origin, dest])
result = {
"duration_s": matrix.durations[0][1],
"distance_m": matrix.distances[0][1],
}
self.redis.setex(
cache_key,
self.CACHE_TTL_DAYS * 86400,
json.dumps(result)
)
return result
def get_matrix_cached(self, locations: list[Location]) -> DistanceMatrix:
"""
Lấy ma trận N×N bằng cách kết hợp dữ liệu từ Redis cache và gọi GraphHopper cho các cặp bị miss.
"""
n = len(locations)
durations = [[0] * n for _ in range(n)]
distances = [[0] * n for _ in range(n)]
missing_pairs = []
# Kiểm tra cache cho tất cả các cặp địa điểm
cache_keys = {}
for i in range(n):
for j in range(n):
if i == j:
continue
key = self._h3_key(locations[i], locations[j])
cached = self.redis.get(key)
if cached:
data = json.loads(cached)
durations[i][j] = data["duration_s"]
distances[i][j] = data["distance_m"]
else:
missing_pairs.append((i, j))
if missing_pairs:
# Gửi request tính toán các cặp bị thiếu qua GraphHopper
missing_locs = list({idx for pair in missing_pairs for idx in pair})
loc_subset = [locations[i] for i in missing_locs]
sub_matrix = self.gh.get_matrix(loc_subset)
idx_map = {orig_idx: sub_idx for sub_idx, orig_idx in enumerate(missing_locs)}
for i, j in missing_pairs:
si, sj = idx_map[i], idx_map[j]
dur = sub_matrix.durations[si][sj]
dist = sub_matrix.distances[si][sj]
durations[i][j] = dur
distances[i][j] = dist
# Lưu thông tin tính được vào Redis cache
key = self._h3_key(locations[i], locations[j])
self.redis.setex(
key,
self.CACHE_TTL_DAYS * 86400,
json.dumps({"duration_s": dur, "distance_m": dist})
)
return DistanceMatrix(durations=durations, distances=distances)
Dành cho các hệ thống vi dịch vụ (microservices) bằng Go, đây là tầng caching tương đương sử dụng gói thư viện github.com/uber/h3-go/v4 và github.com/redis/go-redis/v9:
package matrix
import (
"context"
"encoding/json"
"fmt"
"time"
"github.com/redis/go-redis/v9"
"github.com/uber/h3-go/v4"
)
type Location struct {
Lat float64 `json:"lat"`
Lng float64 `json:"lng"`
}
type CachedMatrix struct {
gh *GraphHopperClient
redis *redis.Client
}
func (c *CachedMatrix) h3Key(a, b Location) string {
cellA := h3.LatLngToCell(h3.NewLatLng(a.Lat, a.Lng), 9)
cellB := h3.LatLngToCell(h3.NewLatLng(b.Lat, b.Lng), 9)
minCell, maxCell := cellA, cellB
if cellB < cellA {
minCell, maxCell = cellB, cellA
}
return fmt.Sprintf("gh:matrix:%x:%x", minCell, maxCell)
}
func (c *CachedMatrix) GetPair(ctx context.Context, origin, dest Location) (map[string]int, error) {
key := c.h3Key(origin, dest)
cached, err := c.redis.Get(ctx, key).Result()
if err == nil {
var result map[string]int
json.Unmarshal([]byte(cached), &result)
return result, nil
}
// Xử lý khi miss cache, gọi fallback tới API HTTP của GraphHopper
matrix, err := c.gh.GetMatrix([]Location{origin, dest})
if err != nil {
return nil, err
}
result := map[string]int{
"duration_s": matrix.Durations[0][1],
"distance_m": matrix.Distances[0][1],
}
data, _ := json.Marshal(result)
c.redis.SetEx(ctx, key, data, 30*24*time.Hour)
return result, nil
}
Hiệu quả thực tế của tầng Caching (Cache hit ratio in practice):
- Ngày đầu tiên (Cold cache): Tỷ lệ hit ~0%, hệ thống tính toán và lấp đầy dữ liệu vào Redis cache.
- Sau 7 ngày: Tỷ lệ hit đạt ~70%.
- Sau 30 ngày (Trạng thái ổn định): Tỷ lệ hit đạt >90% do hầu hết các khu vực giao hàng lặp lại đã được lưu cache.
Đánh Giá Hiệu Năng (Production Benchmark): GraphHopper vs. OSRM vs. Google Maps
Thử nghiệm tính toán ma trận 100×100 (10,000 cặp điểm) trên cấu hình máy chủ VPS DigitalOcean 4-vCPU / 8GB RAM sử dụng dữ liệu bản đồ Việt Nam:
| Routing Engine | 10×10 matrix | 50×50 matrix | 100×100 matrix | Chi phí hàng tháng (Monthly cost) |
|---|---|---|---|---|
| GraphHopper (Self-hosted) | 8ms | 28ms | 52ms | Khoảng ~$20 cho VPS |
| OSRM (Self-hosted) | 4ms | 14ms | 21ms | Khoảng ~$20 cho VPS |
| Valhalla (Self-hosted) | 15ms | 60ms | 120ms | Khoảng ~$20 cho VPS |
| Google Maps Distance Matrix API | 300ms | 1,200ms | Từ 2,500ms+ | Chi phí cao ($510/ngày ở quy mô lớn) |
| HERE Matrix Routing v8 | 150ms | 600ms | 1,200ms | $0.70/đoạn tuyến |
Phân tích kết quả benchmark:
- OSRM đạt tốc độ tính toán ma trận thuần túy nhanh hơn GraphHopper khoảng 2.5 lần.
- Bù lại, GraphHopper vượt trội khi hệ thống cần áp dụng các quy tắc định tuyến động (Custom Models) linh hoạt cho từng loại phương tiện tại runtime.
- Google Maps API có chi phí cao hơn đáng kể và độ trễ lớn hơn. Dịch vụ này chỉ cần thiết khi ứng dụng đòi hỏi dữ liệu giao thông thời gian thực (real-time traffic), trong khi các bài toán định tuyến giao hàng cố định (static delivery routing) nên sử dụng giải pháp Self-hosted như GraphHopper để tối ưu chi phí.
Yêu Cầu Phần Cứng Và Bộ Nhớ RAM (Memory & Hardware Requirements)
GraphHopper nạp toàn bộ đồ thị mạng lưới giao thông vào bộ nhớ RAM. Dung lượng RAM sử dụng phụ thuộc trực tiếp vào dung lượng và phạm vi của tệp bản đồ OSM:
| Khu Vực (Region) | Dung Lượng Tệp OSM | Dung Lượng RAM Yêu Cầu |
|---|---|---|
| TP.HCM mở rộng (Ho Chi Minh City metro) | ~180MB | ~2GB |
| Toàn bộ Việt Nam (Vietnam - entire country) | ~880MB | ~6GB |
| Đông Nam Á (Southeast Asia) | ~4.5GB | ~24GB+ |
| Nước Đức (Germany) | ~3.8GB | ~20GB+ |
Cấu hình đề xuất cho môi trường Production (dữ liệu bản đồ Việt Nam):
- Máy chủ VPS 4 vCPU / 8GB RAM
- Ổ cứng SSD NVMe cho thư mục chứa đồ thị graph-cache
- Bật cấu hình Contraction Hierarchies (CH) để tối ưu thời gian truy vấn
- Khởi chạy tối thiểu 2 instances đằng sau Load Balancer để đảm bảo tính sẵn sàng cao (High Availability - HA)
Chuyên Mục Vấn Đáp (Frequently Asked Questions)
/matrix thuộc công cụ định tuyến mã nguồn mở GraphHopper. API này tiếp nhận danh sách N tọa độ (latitude/longitude) và trả về ma trận N×N chứa thời gian di chuyển (tính bằng giây) cùng khoảng cách (tính bằng mét) dựa trên mạng lưới đường xá từ OpenStreetMap. Giải pháp hoàn toàn miễn phí khi tự triển khai qua Docker và có thể xử lý ma trận 100×100 (10,000 cặp điểm) dưới 50ms trên máy chủ VPS 4-vCPU..osm.pbf của OpenStreetMap. Bạn có thể tải miễn phí các tệp bản đồ theo khu vực hoặc quốc gia từ Geofabrik (geofabrik.de). Ví dụ, dữ liệu bản đồ Việt Nam có thể tải từ: https://download.geofabrik.de/asia/vietnam-latest.osm.pbf. GraphHopper cũng hỗ trợ tự động tải tệp PBF từ URL được cấu hình thông qua tham số --url khi khởi chạy lần đầu.Liên Kết Nội Bộ & Các Bước Tiếp Theo (Internal Links & Next Steps)
- Chuỗi bài viết định tuyến TMĐT (E-commerce routing series): Bài viết này là phần tiếp theo thuộc Phần 7 — Định Tuyến Ma Trận Khoảng Cách Trong Phân Phối Đơn Hàng TMĐT (Distance Matrix Routing in E-commerce Order Allocation), giải thích chi tiết cách cung cấp dữ liệu ma trận khoảng cách cho bộ giải VRP (Vehicle Routing Problem).
- Ứng dụng trong hệ thống gọi xe (Ride-hailing): Tìm hiểu kỹ thuật đánh chỉ mục không gian bằng H3 grid để cache và truy vấn tài xế lân cận trong bài viết Đánh Chỉ Mục Địa Lý H3 Trong Kiến Trúc Gọi Xe Thời Gian Thực.
- Hệ thống tải cao (High-concurrency systems): Để bảo vệ API ma trận khoảng cách dưới lượng request lớn, hãy tham khảo bài viết Kỹ Thuật Rate Limiting & Singleflight Pattern Trong Hệ Thống Tải Cao.