Lindorm GanosBase provides spatio-temporal aggregate functions that sort out-of-order points by time, assemble them into trajectories, and compute trajectory metrics. Use these functions for large-scale spatio-temporal workloads such as Internet of Vehicles (IoV), GIS, and Internet of Things (IoT) applications that require trajectory analysis.
Prerequisites
Engine: LindormTable 2.6.5 or later. To view or upgrade your version, see Release notes of LindormTable and Upgrade the minor engine version of a Lindorm instance.
SQL version: Lindorm SQL 2.6.8 or later. To check your version, see SQL versions.
Functions
| Function | Description |
|---|---|
ST_Length_Rows | Sorts out-of-order points by time, aggregates them into a trajectory, and returns the spherical length of the trajectory in meters. |
ST_Resample | Sorts out-of-order points by time, downsamples the points based on temporal and spatial thresholds, and returns the downsampled trajectory as a JSON string. |
ST_TrajectoryProfile | Sorts out-of-order points by time, aggregates them into a trajectory, segments the trajectory by a temporal threshold, and returns the coordinates and timestamps of each segment's start and end points. |
ST_Length_Rows
Sorts out-of-order points by time, aggregates them into a trajectory, and returns the spherical length of the trajectory in meters.
Syntax
double ST_Length_Rows(point column)Parameters
| Parameter | Description |
|---|---|
point column | The geometry column to process. Must contain POINT objects. |
Usage notes
Use
ST_Length_Rowswith aGROUP BYclause to compute trajectory lengths grouped by a column (for example, by vehicle ID).Correct ordering depends on the primary key sort order. Define composite primary keys that include both an entity identifier (such as vehicle ID) and a timestamp column so that rows are stored and scanned in the correct travel order. If the primary key does not guarantee correct ordering, the returned length may be incorrect.
Examples
The following examples use the test_len table, created and populated as follows:
CREATE TABLE test_len (
carid VARCHAR,
collect_time TIMESTAMP,
p GEOMETRY(POINT),
PRIMARY KEY(carid, collect_time)
);
INSERT INTO test_len (carid, collect_time, p) VALUES
('car1', '2023-09-12 00:04:02', ST_GeomFromText('POINT (111.40269 35.61695)')),
('car1', '2023-09-12 00:09:07', ST_GeomFromText('POINT (111.40127 35.616096)')),
('car1', '2023-09-12 00:14:03', ST_GeomFromText('POINT (111.400604 35.616013)')),
('car1', '2023-09-12 00:20:13', ST_GeomFromText('POINT (111.399734 35.613983)')),
('car1', '2023-09-12 00:27:21', ST_GeomFromText('POINT (111.40217 35.616386)')),
('car2', '2023-09-12 00:27:21', ST_GeomFromText('POINT (111.40217 35.616386)'));The primary key (carid, collect_time) ensures that points are stored in ascending time order per vehicle, so the trajectory is assembled correctly.
Example 1: Compute the spherical length of the trajectory for car1.
SELECT ST_LENGTH_ROWS(p) FROM test_len WHERE carid = 'car1';Result:
+--------------------+
| st_length_rows(p) |
+--------------------+
| 805.55323541493414 |
+--------------------+Example 2: Compute the spherical length for each vehicle, grouped by vehicle ID.
SELECT carid, ST_LENGTH_ROWS(p) AS len
FROM test_len
WHERE carid <= 'car2'
GROUP BY carid;Result:
+-------+--------------------+
| carid | len |
+-------+--------------------+
| car1 | 805.55323541493414 |
| car2 | 0 |
+-------+--------------------+ST_Resample
Sorts out-of-order points by time and downsamples them based on temporal and spatial thresholds. Returns the downsampled trajectory as a JSON string.
Syntax
Variant 1: Point column as input.
String ST_Resample(String geomColumnName, String timeColumnName, String config)Variant 2: Separate longitude and latitude columns as input.
String ST_Resample(String xColumnName, String yColumnName, String timeColumnName, String config)Parameters
| Parameter | Description |
|---|---|
geomColumnName | The POINT geometry column. Use this parameter when point data is stored as geometry objects (Variant 1). |
xColumnName | The longitude column (DOUBLE). Must be paired with yColumnName. Use this parameter when point data is stored as separate longitude and latitude values (Variant 2). |
yColumnName | The latitude column (DOUBLE). Must be paired with xColumnName (Variant 2). |
timeColumnName | The time column used to sort points in ascending order. Supports TIME, TIMESTAMP, and LONG data types. If LONG, values must be in milliseconds. |
config | Downsampling configuration in JSON format (STRING). Format: {"parameter": value, ...}. See the table below for available parameters. |
Downsampling parameters (`config`)
| Parameter | Type | Default | Description |
|---|---|---|---|
downsample_time | INT or LONG | -1 (disabled) | Temporal downsampling threshold in milliseconds. Adjacent points in the output are separated by more than this interval. |
downsample_distance | INT, LONG, FLOAT, or DOUBLE | -1.0 (disabled) | Spatial downsampling threshold. The geometry of a trajectory is simplified by using the specified algorithm based on this parameter value. The unit of this parameter is the same as that of coordinates. |
simplifier | STRING | topologypreserving | Simplification algorithm. Valid values: vw (Visvalingam-Whyatt), dp (Douglas-Peucker), topologypreserving (Douglas-Peucker with topology preservation; valid only when downsample_distance is specified). |
Returned value
A time-sorted JSON array of downsampled trajectory points:
[{"x": <longitude>, "y": <latitude>, "t": <time>}, ...]Usage notes
Apply filter conditions to select trajectory points for a specific entity or time range.
ST_Resampleoperates on the filtered result set, not the full table.ST_Resamplecannot be used with aGROUP BYclause.
Example
The following example uses the gps_points table, created and populated as follows:
CREATE TABLE gps_points (
account_id VARCHAR,
collect_time TIMESTAMP,
gps_point GEOMETRY(POINT),
PRIMARY KEY(account_id, collect_time)
);
INSERT INTO gps_points (account_id, collect_time, gps_point) VALUES
('001', '2023-11-10 11:00:30', ST_MakePoint(113.665431, 34.773)),
('001', '2023-11-10 11:00:31', ST_MakePoint(113.665432, 34.773)),
('001', '2023-11-10 11:00:32', ST_MakePoint(113.665433, 34.773)),
('001', '2023-11-10 11:00:33', ST_MakePoint(113.665434, 34.774));Query the trajectory of account 001 within a 24-hour window and downsample it using the Visvalingam-Whyatt algorithm with a spatial threshold of 0.0001:
SELECT ST_Resample(
gps_point,
collect_time,
'{"downsample_distance": 0.0001, "simplifier": "vw"}'
) AS resampled_traj
FROM gps_points
WHERE account_id = '001'
AND collect_time >= '2023-11-10 00:00:00'
AND collect_time <= '2023-11-11 00:00:00';Result:
+-----------------------------------------------------------------------------------------------------+
| resampled_traj |
+-----------------------------------------------------------------------------------------------------+
| [{"x":113.665431,"y":34.773,"t":"2023-11-10 11:00:30.0"},{"x":113.665434,"y":34.774,"t":"2023-11-10 11:00:33.0"}] |
+-----------------------------------------------------------------------------------------------------+ST_TrajectoryProfile
Sorts out-of-order points by time, assembles them into a trajectory, segments the trajectory based on a temporal gap threshold, and returns the coordinates and timestamps of each segment's start and end points.
ST_TrajectoryProfile is typically combined with spatial relationship functions such as ST_DWithinSphere to find when a moving entity first enters and last leaves a defined area within each trajectory segment.
Syntax
Variant 1: Point column as input.
String ST_TrajectoryProfile(String geomColumnName, String timeColumnName, long thresh)Variant 2: Separate longitude and latitude columns as input.
String ST_TrajectoryProfile(String xColumnName, String yColumnName, String timeColumnName, long thresh)Parameters
| Parameter | Description |
|---|---|
geomColumnName | The POINT geometry column. Use this parameter when point data is stored as geometry objects (Variant 1). |
xColumnName | The longitude column (DOUBLE). Must be paired with yColumnName. Use this parameter when point data is stored as separate longitude and latitude values (Variant 2). |
yColumnName | The latitude column (DOUBLE). Must be paired with xColumnName (Variant 2). |
timeColumnName | The time column. Points are sorted in ascending order of this column. |
thresh | (Optional) The maximum time gap in milliseconds between two adjacent points that belong to the same trajectory segment. If the gap between two points exceeds this threshold, they are placed in separate segments. Default: 10000 (10 seconds). |
Returned value
A JSON object where each key is a segment index (0-based) and each value is a JSON string containing the segment's boundary coordinates and timestamps:
{
"0": "{\"startX\": <longitude>, \"startY\": <latitude>, \"startTime\": <epoch ms>, \"endX\": <longitude>, \"endY\": <latitude>, \"endTime\": <epoch ms>}",
"1": "...",
...
}Usage notes
ST_TrajectoryProfilemust be used with aGROUP BYclause to aggregate points into trajectories by entity (for example, by vehicle ID).When a secondary index is used, add all columns referenced in the query—including the
GROUP BYkey, filter condition columns, and function parameter columns—as included columns in the index. This avoids scanning the base table. For example, if the query groups bycaridand passespandcollect_timeto the function, include all three columns in the index.
Example
The following example uses the test_traj table, created and populated as follows:
CREATE TABLE test_traj (
carid VARCHAR,
collect_time TIMESTAMP,
p GEOMETRY(POINT),
status VARCHAR,
PRIMARY KEY(z-order(p), carid, collect_time)
);
INSERT INTO test_traj (carid, collect_time, p, status) VALUES
('car1', '2023-09-12 00:04:02', ST_GeomFromText('POINT (111.40269 35.61695)'), 'normal'),
('car1', '2023-09-12 00:09:07', ST_GeomFromText('POINT (111.40127 35.616096)'), 'normal'),
('car1', '2023-09-12 00:14:03', ST_GeomFromText('POINT (111.400604 35.616013)'), 'normal'),
('car1', '2023-09-12 00:20:13', ST_GeomFromText('POINT (111.399734 35.613983)'), 'normal'),
('car1', '2023-09-12 00:27:21', ST_GeomFromText('POINT (111.40217 35.616386)'), 'normal'),
('car2', '2023-09-12 00:27:21', ST_GeomFromText('POINT (111.40217 35.616386)'), 'normal');For each vehicle, find the first entry and last exit point within a 100-meter radius of POINT (111.40217 35.616386), for points collected between 2023-09-12 00:09:07 and 2023-09-20 00:09:07. Use a segment gap threshold of 30,000 ms (30 seconds):
SELECT
carid,
ST_TrajectoryProfile(p, collect_time, 30000) AS trajprofile
FROM test_traj
WHERE ST_DWithinSphere(ST_GeomFromText('POINT (111.40217 35.616386)'), p, 100.0)
AND collect_time >= '2023-09-12 00:09:07'
AND collect_time <= '2023-09-20 00:09:07'
GROUP BY carid;When a secondary index is used in the query, add carid, p, and collect_time as included columns in the index so that the query does not scan the base table.
Result:
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| carid | trajprofile |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| car1 | {"0":"{\"endY\":35.616096,\"endX\":111.40127,\"startY\":35.616096,\"startTime\":1694448547000,\"startX\":111.40127,\"endTime\":1694448547000}","1":"{\"endY\":35.616386,\"endX\":111.40217,\"startY\":35.616386,\"startTime\":1694449641000,\"startX\":111.40217,\"endTime\":1694449641000}"} |
| car2 | {"0":"{\"endY\":35.616386,\"endX\":111.40217,\"startY\":35.616386,\"startTime\":1694449641000,\"startX\":111.40217,\"endTime\":1694449641000}"} |
+-------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------+car1 has two trajectory segments within the search area (segment 0 and segment 1). car2 has one point in the area, which forms a single segment (segment 0) where the start and end coordinates and timestamps are identical.