All Products
Search
Document Center

PolarDB:Quick Start

Last Updated:Mar 30, 2026

GanosBase includes a MapMatching engine that snaps GPS trajectories to the nearest roads in a road network. This guide walks you through the full workflow: install the extension, load road network data, build a workspace, and run your first map matching query.

Prerequisites

Before you begin, make sure you have:

  • A running PolarDB for Oracle instance with GanosBase available

  • Database superuser or schema-level CREATE privileges

Key terms

Term Definition
Road network A comprehensive and organized digital representation of the structure and characteristics of a road network, including the locations, types, classifications, connections, geometric shapes, and traffic regulations of roads.
Node A point at which roads intersect or end in a road network. A node is a connecting point between edges.
Edge An abstract concept that connects two nodes in a road network. In an undirected graph, edges have no direction. In a directed graph, edges represent the travel direction. Edges carry attribute information such as length and passability, and form the structural framework of a road network.
Segment A section of a road with physical attributes and geographic location information. A segment is a continuous section of road that may span from one intersection to the next, or cover a section with uniform characteristics such as lane count and speed limit. Segments are the basic units in navigation, transportation analysis, and road maintenance planning.

Install the extension

Run the following commands to install the ganos_mapmatching extension and its required companion ganos_fdw:

CREATE EXTENSION ganos_mapmatching CASCADE;
CREATE EXTENSION ganos_fdw CASCADE;

Installing ganos_mapmatching automatically installs three additional extensions: ganos_geometry, ganos_spatialref, and ganos_trajectory.

If you see ERROR: invalid extension name: "ganos_trajectory", contact Alibaba Cloud support for assistance.

To avoid permission issues, install the extensions in the public schema:

CREATE EXTENSION ganos_mapmatching WITH SCHEMA PUBLIC CASCADE;
CREATE EXTENSION ganos_fdw WITH SCHEMA PUBLIC CASCADE;

How it works

Map matching requires three inputs:

  1. A road network — a set of road segments, each with a unique ID, a start node, an end node, and a geometry.

  2. A workspace — an in-memory topological network graph built from the road network, used for matching queries.

  3. A trajectory — a LineString geometry representing raw GPS points.

The st_createworkspace function builds the workspace from your road network data. The st_mapmatching function then matches a trajectory to the closest roads in that workspace and returns a snapped LineString.

Required columns for st_createworkspace:

Column Type Description
fid bigint Unique segment ID
source bigint Start node ID
target bigint End node ID
geometry column geometry(LineString) Segment geometry (WGS84, SRID 4326)

The cost column is not used by the map matching algorithm. You can include it in your table for future use, but it does not affect matching results.

Example 1: Match a trajectory against your own road network

Step 1: Create and load road network data

Create a table with the required schema. Each row represents one road segment — a directed connection between two nodes:

CREATE TABLE network (
    fid    bigint,                           -- Segment ID (unique identifier)
    source bigint,                           -- Start node ID
    target bigint,                           -- End node ID
    cost   double precision,                 -- Edge weight (reserved; not used by map matching)
    geom   public.geometry(LineString,4326)  -- Segment geometry (WGS84)
);

Insert the road segment data:

INSERT INTO network(fid, source, target, cost, geom) VALUES
(1,  1,  2,  1, st_geomfromtext('LINESTRING(2 1,2 0)')),
(2,  2,  1,  1, st_geomfromtext('LINESTRING(2 0,2 1)')),
(3,  3,  1,  1, st_geomfromtext('LINESTRING(3 1,2 1)')),
(4,  4,  3,  1, st_geomfromtext('LINESTRING(4 1,3 1)')),
(5,  1,  5,  1, st_geomfromtext('LINESTRING(2 1,2 2)')),
(6,  5,  1,  1, st_geomfromtext('LINESTRING(2 2,2 1)')),
(7,  3,  6,  1, st_geomfromtext('LINESTRING(3 1,3 2)')),
(8,  7,  8,  1, st_geomfromtext('LINESTRING(0 2,1 2)')),
(9,  8,  7,  1, st_geomfromtext('LINESTRING(1 2,0 2)')),
(10, 5,  8,  3, st_geomfromtext('LINESTRING(2 2,1 2)')),
(11, 8,  5,  3, st_geomfromtext('LINESTRING(1 2,2 2)')),
(12, 6,  5,  1, st_geomfromtext('LINESTRING(3 2,2 2)')),
(13, 5,  6,  1, st_geomfromtext('LINESTRING(2 2,3 2)')),
(14, 6,  9,  1, st_geomfromtext('LINESTRING(3 2,4 2)')),
(15, 9,  6,  1, st_geomfromtext('LINESTRING(4 2,3 2)')),
(16, 10, 5,  1, st_geomfromtext('LINESTRING(2 3,2 2)')),
(17, 5,  10, 1, st_geomfromtext('LINESTRING(2 2,2 3)')),
(18, 6,  11, 1, st_geomfromtext('LINESTRING(3 2,3 3)')),
(19, 10, 11, 1, st_geomfromtext('LINESTRING(2 3,3 3)')),
(20, 11, 12, 1, st_geomfromtext('LINESTRING(3 3,4 3)')),
(21, 13, 10, 1, st_geomfromtext('LINESTRING(2 4,2 3)')),
(22, 10, 13, 1, st_geomfromtext('LINESTRING(2 3,2 4)')),
(23, 9,  12, 1, st_geomfromtext('LINESTRING(4 2,4 3)')),
(24, 12, 9,  1, st_geomfromtext('LINESTRING(4 3,4 2)')),
(25, 9,  4,  1, st_geomfromtext('LINESTRING(4 2,4 1)')),
(26, 4,  9,  1, st_geomfromtext('LINESTRING(4 1,4 2)')),
(27, 14, 15, 1, st_geomfromtext('LINESTRING(0.5 3.5,2 3.5)')),
(28, 15, 14, 1, st_geomfromtext('LINESTRING(2 3.5,0.5 3.5)')),
(29, 16, 17, 1, st_geomfromtext('LINESTRING(3.5 4,3.5 2.3)')),
(30, 17, 16, 1, st_geomfromtext('LINESTRING(3.5 2.3,3.5 4)'));

The road network looks like this:

image

Step 2: Build a map matching workspace

Build a workspace named mm_ws_test1 from the road network. The SELECT statement passed to st_createworkspace must include fid, source, target, and the geometry column:

SELECT st_createworkspace('mm_ws_test1', 'select fid, source, target, geom from network');

This generates the topological network graph used for matching:

image

Step 3: Create trajectory data

Create a table and insert the GPS trajectory you want to match. The trajectory is a LineString in WGS84 (SRID 4326):

CREATE TABLE traj (id int, geom geometry(linestring, 4326));

INSERT INTO traj(id, geom)
VALUES (1, st_geomfromtext('LINESTRING(4.15 1.6,3.47 0.92,2.4 0.92,2.14 1.53,2.14 2.57,2.49 2.98)'));

The raw trajectory looks like this:

image

Step 4: Run map matching

Match the trajectory against the road network:

SELECT st_astext(
    st_mapmatching(
        'mm_ws_test1',
        geom,
        '{"algorithm":"stmatch","k":4,"r":0.25,"e":0.5}'::text
    )
) AS geom
FROM traj;

Result:

geom
-----------------------------------------------
 LINESTRING(4 1.6,4 1,3 1,2 1,2 2,2 3,2.49 3)
(1 row)

The output is a LineString snapped to the road network. Each coordinate in the result aligns to a road segment in the workspace. The matched path is visualized below:

image

Example 2: Match a trajectory using OpenStreetMap (OSM) data

Use this approach when you have real-world road network data from OpenStreetMap (OSM) instead of a custom dataset.

Step 1: Import OSM data from Object Storage Service (OSS)

OSM data must be imported from OSS. Download the sample OSM file for Macau (China) and upload it to an OSS bucket, then run:

-- Register the OSM file as a foreign table.
-- Replace the placeholders with your OSS AccessKey ID, AccessKey secret, endpoint, bucket, and directory.
SELECT st_regforeigntables(
    'OSS://{accesskeyid}:{accesskeysecret}@{endpoint}/{bucket}/{directory}/macau-latest.osm.pbf',
    'osmserver',
    'OSMNT'
);

-- Set the OSS endpoint for data access.
SELECT st_setcplconfig('OSS_ENDPOINT', '{endpoint}');

Extract node data (intersections) from the OSM file into a local table:

CREATE TABLE macau_network_nodes (
    id    BIGSERIAL,
    fid   BIGINT,
    eout  INTEGER,
    lon   DOUBLE PRECISION,
    lat   DOUBLE PRECISION,
    cnt   INTEGER,
    chk   INTEGER,
    ein   INTEGER,
    name  TEXT,
    tags  TEXT,
    point GEOMETRY(point, 4326)
);

INSERT INTO macau_network_nodes(fid, lon, lat, name, tags, point)
SELECT osm_id::bigint, ST_X(geom), ST_Y(geom), name, to_json(other_tags)::jsonb, geom
FROM points;

Extract road segment (way) data into a separate table:

CREATE TABLE macau_network_ways (
    gid               BIGSERIAL,
    fid               BIGINT,
    length            DOUBLE PRECISION,
    length_m          DOUBLE PRECISION,
    p                 TEXT,
    source            BIGINT,
    target            BIGINT,
    source_osm        BIGINT,
    target_osm        BIGINT,
    cost              DOUBLE PRECISION,
    reverse_cost      DOUBLE PRECISION DEFAULT -1,
    cost_s            DOUBLE PRECISION,
    reverse_cost_s    DOUBLE PRECISION DEFAULT -1,
    rule              TEXT,
    one_way           INT,
    oneway            TEXT,
    x1                DOUBLE PRECISION,
    y1                DOUBLE PRECISION,
    x2                DOUBLE PRECISION,
    y2                DOUBLE PRECISION,
    maxspeed_forward  DOUBLE PRECISION,
    maxspeed_backward DOUBLE PRECISION DEFAULT -1,
    priority          DOUBLE PRECISION DEFAULT 1,
    name              TEXT,
    tags              JSONB,
    linestring        GEOMETRY(LINESTRING, 4326)
);

INSERT INTO macau_network_ways(fid, source_osm, target_osm, name, tags, linestring)
SELECT osm_id::bigint, source_osm, target_osm, name, to_json(other_tags)::jsonb, geom
FROM lines;

Step 2: Build the road network topology

Link each road segment to its start and end nodes by updating the source and target columns:

UPDATE macau_network_ways
SET source = macau_network_nodes.id
FROM macau_network_nodes
WHERE macau_network_ways.source_osm = macau_network_nodes.fid;

UPDATE macau_network_ways
SET target = macau_network_nodes.id
FROM macau_network_nodes
WHERE macau_network_ways.target_osm = macau_network_nodes.fid;

The resulting road network for Macau (China) looks like this:

image

Step 3: Build a map matching workspace

SELECT st_createworkspace(
    'mm_ws_test2',
    'select fid, source, target, linestring from macau_network_ways'
);

Step 4: Run map matching

Match a GPS trajectory against the Macau (China) road network. This example uses additional parameters to improve matching accuracy for real-world traces:

SELECT st_astext(
    st_mapmatching(
        'mm_ws_test2',
        'LINESTRING(113.5492 22.1881,113.5493 22.1881,113.5504 22.1885,113.5505 22.1886,113.5502 22.189,113.5501 22.1891,113.5491 22.1887,113.5489 22.1887)',
        '{"algorithm":"stmatch","k":4,"r":0.25,"e":0.5,"tolerance":0.5,"vmax":1.0,"factor":0.5}'::text
    )
);

Result:

LINESTRING(113.5492633 22.1880942,113.5493491 22.1881266,113.5504129 22.1885289,113.5505378 22.1885762,113.5502504 22.1892274,113.5505378 22.1885762,113.5502504 22.1892274,113.5501282 22.1891812,113.5490843 22.1887864,113.5489761 22.1887455)

The output coordinates are snapped to the actual road geometries in the workspace:

image

st_mapmatching parameters

All examples use the stmatch algorithm. The JSON options string controls matching behavior:

Parameter Type Description Example value
algorithm string Matching algorithm. Currently only stmatch is supported. "stmatch"
k integer Number of candidate road segments considered for each GPS point. Higher values improve accuracy on dense road networks but increase computation time. 4
r float Search radius in the coordinate unit of your data. Only road segments within this radius are candidates for each GPS point. Increase this value for noisy or sparse traces. 0.25
e float GPS measurement error tolerance. Controls how strictly the algorithm filters out outlier points. 0.5
tolerance float Maximum allowed deviation between a raw GPS point and its matched position. Points that exceed this threshold may be skipped. Use with real-world traces. 0.5
vmax float Maximum speed used to validate transitions between matched road segments. Use with real-world traces. 1.0
factor float Weighting factor that balances spatial distance and transition probability in the matching score. Use with real-world traces. 0.5

Tuning tips:

  • Noisy GPS traces: Increase r (search radius) and e (error tolerance) to allow the algorithm to consider more candidates and tolerate larger measurement errors.

  • Dense road networks: Increase k to evaluate more candidate segments per GPS point, which improves accuracy but increases computation time.

  • Real-world traces: Add tolerance, vmax, and factor (as shown in Example 2) to handle the variability typical of real GPS data.

  • Clean synthetic traces: Use smaller values for r and e (as shown in Example 1) when your data is generated from precise coordinates.