Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 0 additions & 23 deletions .github/workflows/c.yml

This file was deleted.

37 changes: 0 additions & 37 deletions .github/workflows/cmake.yml

This file was deleted.

51 changes: 51 additions & 0 deletions .github/workflows/lint.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
name: Lint

# Static analysis only -- no compiling. This project's real build needs
# PostgreSQL + Citus + PostGIS headers, some of which turned out to be
# undocumented/version-specific gaps not shipped by any package (see
# third_party/postgis-lwgeom/README.md), making a genuine `cmake --build`
# too fragile to run reliably as a PR gate for now. These jobs instead
# catch real bugs/style issues in the C sources, shell scripts, and the
# workflow files themselves, without needing that environment at all.

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]

jobs:
actionlint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: raven-actions/actionlint@v2.2.0

shellcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: ludeeus/action-shellcheck@2.0.0
with:
scandir: './scripts'
severity: warning

cppcheck:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install cppcheck
run: sudo apt-get update && sudo apt-get install -y cppcheck
- name: Run cppcheck
run: |
# 'style' is deliberately excluded: it's almost entirely const-
# correctness/redundant-condition suggestions with no real bugs
# found in this codebase, and including it would make this job
# fail on pre-existing code with nothing actionable for a PR to
# fix. 'warning'/'performance'/'portability' plus cppcheck's
# always-on checks (missingReturn, uninitvar, null dereference)
# are what actually caught real bugs while writing this job.
cppcheck --enable=warning,performance,portability \
--suppress=missingInclude --suppress=missingIncludeSystem \
--inline-suppr \
--error-exitcode=1 -I include src
9 changes: 4 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -131,11 +131,10 @@ if(PROJ_INCLUDE_DIRS)
endif()

# liblwgeom.h (used for GBOX) is PostGIS' own internal header and is not
# shipped by any postgresql-*-postgis-3 package; it must be sourced from a
# PostGIS/MobilityDB checkout. See README for how to place a copy under
# /usr/local/include/postgis-lwgeom/liblwgeom (alongside its required
# ../postgis_config.h).
include_directories(SYSTEM /usr/local/include/postgis-lwgeom/liblwgeom)
# shipped by any postgresql-*-postgis-3 package -- see
# third_party/postgis-lwgeom/README.md for why a copy is vendored directly
# in this repo instead of requiring a manual host-wide install step.
include_directories(SYSTEM "${CMAKE_CURRENT_SOURCE_DIR}/third_party/postgis-lwgeom/liblwgeom")

#-------------------
# add the MobilityDB link
Expand Down
65 changes: 55 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ Distributed MobilityDB is an open-source extension for PostgreSQL tailored to ha
- [Use Cases](#use-cases)
- [OpenStreetMap (OSM) Data](#openstreetmap-osm-data)
- [Automatic Identification System (AIS) Data](#automatic-identification-system-ais-data)
- [BerlinMOD Benchmark Data](#berlinmod-benchmark-data)
- [Global Surface Summary of the Day (GSOD) Data](#global-surface-summary-of-the-day-gsod-data)
- [Contributing](#contributing)
- [Contact Us](#contact-us)
Expand Down Expand Up @@ -70,22 +71,24 @@ CREATE EXTENSION Distributed_MobilityDB CASCADE;

### Creating Distributed Tables

The `create_spatiotemporal_distributed_table()` function is utilized to define a distributed table that is partitioned using a Multidimensional Tiling method. It splits the input table into several tiles stored in separate PostgreSQL tables.
The `create_spatiotemporal_distributed_table()` function is utilized to define a distributed table that is partitioned using a Multidimensional Tiling method. It splits the input table into several tiles stored in separate PostgreSQL tables. It can also create a Citus **reference table** instead (a table replicated as-is to every node, with no tiling at all) via the `is_reference_table` flag -- useful for smaller lookup/dimension tables that need to be joined against a distributed table without any repartitioning.

**Function:** `create_spatiotemporal_distributed_table`

| Argument | Required | Description |
|---|---|---|
| `table_name_in` | Yes | Name of the input table. |
| `num_tiles` | Yes | Number of generated tiles. |
| `table_name_out` | Yes | Name of the distributed table. |
| `tiling_method` | Yes | Name of the tiling method: <ins>crange</ins>, <ins>hierarchical</ins>, <ins>grid</ins>. |
| `tiling_granularity` | No | The tiling granularity. Defaults to the value chosen by the tiling method's granularity selection process, which picks between shape- and point-based strategies to create load-balanced tiles. Set this to customize the tiling granularity. |
| `tiling_type` | No | The tiling type of the tiling method: `temporal`, `spatial`, or `spatiotemporal`. Defaults based on the given column type. |
| `colocation_table` | No | Colocate the input table with another table, e.g. to create tiles based on given boundaries such as province borders. Used together with `colocation_column`. |
| `colocation_column` | No | The colocation column to use with `colocation_table`. |
| `physical_partitioning` | No | Whether or not to physically partition data. |
| `object_segmentation` | No | Whether or not to segment the input spatiotemporal column. |
| `table_name_out` | Yes | Name of the distributed (or reference) table to create. Must not already exist. |
| `num_tiles` | No | Number of generated tiles. Defaults to `1`. Ignored when `is_reference_table` is `true` -- reference tables aren't tiled -- except that any value other than `1` is rejected outright rather than silently ignored, to catch accidental misuse. |
| `tiling_method` | No | Name of the tiling method: <ins>crange</ins>, <ins>hierarchical</ins>, <ins>grid</ins>. Defaults to `crange`. Ignored when `is_reference_table` is `true`. |
| `tiling_granularity` | No | The tiling granularity. Defaults to the value chosen by the tiling method's granularity selection process, which picks between shape- and point-based strategies to create load-balanced tiles. Set this to customize the tiling granularity. Ignored when `is_reference_table` is `true`. |
| `tiling_type` | No | The tiling type of the tiling method: `temporal`, `spatial`, or `spatiotemporal`. Defaults based on the given column type. Ignored when `is_reference_table` is `true`. |
| `colocation_table` | No | Colocate the input table with another table, e.g. to create tiles based on given boundaries such as province borders. Used together with `colocation_column`. Ignored when `is_reference_table` is `true`. |
| `colocation_column` | No | The colocation column to use with `colocation_table`. Ignored when `is_reference_table` is `true`. |
| `spatiotemporal_col_name` | No | Name of the spatiotemporal/geometry column to distribute on. Defaults to the column detected automatically from the input table's type. Ignored when `is_reference_table` is `true`. |
| `physical_partitioning` | No | Whether or not to physically partition data. Defaults to `true`. Ignored when `is_reference_table` is `true`. |
| `shape_segmentation` | No | Whether or not to segment the input spatiotemporal column across tiles. Defaults to `true`. Ignored when `is_reference_table` is `true`. |
| `is_reference_table` | No | If `true`, skip tiling entirely and create `table_name_out` as a Citus reference table (a full replica of `table_name_in` on every node) via `create_reference_table()`. Defaults to `false`. |

By utilizing the `create_spatiotemporal_distributed_table()` function with these arguments, you can easily create a distributed table that suits your data management needs.

Expand Down Expand Up @@ -189,6 +192,48 @@ WHERE Destination = 'Kalundborg'
AND timespan(Trip) > '5 days';
```

### BerlinMOD Benchmark Data

**Description:** BerlinMOD is a standard benchmark for moving object databases: a synthetic data generator producing vehicle trip trajectories across a road network, together with the 17 standard BerlinMOD/R benchmark queries. The full set of queries, adapted to run against a distributed `Trips` table, is available in [`demo_queries/berlinmod`](demo_queries/berlinmod), along with the distribution/setup script.

**Download:** https://github.com/MobilityDB/MobilityDB-BerlinMOD

**Reference:** https://github.com/MobilityDB/MobilityDB-BerlinMOD/blob/master/BerlinMOD/berlinmod_r_queries.sql

```sql
-- Input table
CREATE TABLE Trips (
TripId int,
VehicleId int,
Trip tgeompoint
);

-- Distribute the trips table into 4 tiles using the spatiotemporal column: tgeompoint(sequence)
SELECT create_spatiotemporal_distributed_table(table_name_in => 'trips', num_tiles => 4,
table_name_out => 'trips_4t', tiling_method => 'crange', tiling_type => 'spatiotemporal');

-- Query 4: Which vehicles have passed the points from Points?
SELECT DISTINCT p.PointId, p.Geom, v.Licence
FROM trips_4t t, Vehicles v, Points p
WHERE t.VehicleId = v.VehicleId
AND ST_Intersects(trajectory(t.Trip), p.Geom)
ORDER BY p.PointId, v.Licence;

-- Query 6 (Distance-Join): What are the pairs of licence plate numbers of "trucks"
-- that have ever been as close as 10m or less to each other?
WITH Temp(Licence, VehicleId, Trip) AS (
SELECT v.Licence, t.VehicleId, t.Trip
FROM trips_4t t, Vehicles v
WHERE t.VehicleId = v.VehicleId AND v.VehicleType = 'truck'
)
SELECT t1.Licence, t2.Licence
FROM Temp t1, Temp t2
WHERE t1.VehicleId < t2.VehicleId
AND t1.Trip && expandSpace(t2.Trip, 10)
AND eDwithin(t1.Trip, t2.Trip, 10.0)
ORDER BY t1.Licence, t2.Licence;
```

### Global Surface Summary of the Day (GSOD) Data

**Description:** GSOD data is a collection of daily weather observations from weather stations around the world. It includes information such as temperature, time, location, humidity, and atmospheric pressure.
Expand Down
68 changes: 68 additions & 0 deletions demo_queries/berlinmod/partitioning.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
-----------------------------------------------------------------------------------------------------------------------
-- BerlinMOD setup: distribute Trips as a spatiotemporal-tiled table, and the
-- reference tables the BerlinMOD/R queries join against (Vehicles, Licences,
-- Points, Regions, Instants, Periods) as Citus reference tables -- both via
-- create_spatiotemporal_distributed_table(), using its is_reference_table
-- flag for the latter.
--
-- Assumes the BerlinMOD data has already been generated/loaded, e.g. via
-- https://github.com/MobilityDB/MobilityDB-BerlinMOD (berlinmod_datagenerator.sql
-- or berlinmod_load.sql), so tables Trips, Vehicles, Licences, Points,
-- Regions, Instants and Periods already exist and are populated.
--
-- Each source table is renamed to lowercase first (e.g. Trips -> trips) so
-- create_spatiotemporal_distributed_table() can create its distributed
-- output under a new, descriptive name: trips_16t for the tiled table
-- (matching the "_Nt" convention used elsewhere in this repo's demos), and
-- <table>_ref for each reference table.
-----------------------------------------------------------------------------------------------------------------------

-----------------------------------------------------------------------------------------------------------------------
-- Trips
-- The one distributed spatiotemporal table.
-----------------------------------------------------------------------------------------------------------------------
SELECT create_spatiotemporal_distributed_table(table_name_in => 'trips', table_name_out => 'trips_16t',
num_tiles => 16, tiling_method => 'crange', tiling_type => 'spatiotemporal');

-----------------------------------------------------------------------------------------------------------------------
-- Reference tables
-- Replicated to every node (num_tiles is omitted -- it's not meaningful for
-- a reference table, and defaults to the only value is_reference_table
-- accepts), so they can be joined against trips_16t without any
-- repartitioning.
-----------------------------------------------------------------------------------------------------------------------
SELECT create_spatiotemporal_distributed_table(table_name_in => 'vehicles', table_name_out => 'vehicles_ref',
is_reference_table => true);

SELECT create_spatiotemporal_distributed_table(table_name_in => 'licences', table_name_out => 'licences_ref',
is_reference_table => true);

SELECT create_spatiotemporal_distributed_table(table_name_in => 'points', table_name_out => 'points_ref',
is_reference_table => true);

SELECT create_spatiotemporal_distributed_table(table_name_in => 'regions', table_name_out => 'regions_ref',
is_reference_table => true);

SELECT create_spatiotemporal_distributed_table(table_name_in => 'instants', table_name_out => 'instants_ref',
is_reference_table => true);

SELECT create_spatiotemporal_distributed_table(table_name_in => 'periods', table_name_out => 'periods_ref',
is_reference_table => true);

-----------------------------------------------------------------------------------------------------------------------
-- Sample views
-- The standard queries restrict several reference tables to a small sample
-- (suffix 1/2) to keep query result sizes reasonable.
-----------------------------------------------------------------------------------------------------------------------
CREATE OR REPLACE VIEW Licences1 (LicenceId, Licence, VehicleId) AS
SELECT LicenceId, Licence, VehicleId FROM licences_ref LIMIT 10;
CREATE OR REPLACE VIEW Licences2 (LicenceId, Licence, VehicleId) AS
SELECT LicenceId, Licence, VehicleId FROM licences_ref LIMIT 10 OFFSET 10;
CREATE OR REPLACE VIEW Points1 (PointId, Geom) AS
SELECT PointId, Geom FROM points_ref LIMIT 10;
CREATE OR REPLACE VIEW Regions1 (RegionId, Geom) AS
SELECT RegionId, Geom FROM regions_ref LIMIT 10;
CREATE OR REPLACE VIEW Instants1 (InstantId, Instant) AS
SELECT InstantId, Instant FROM instants_ref LIMIT 10;
CREATE OR REPLACE VIEW Periods1 (PeriodId, Period) AS
SELECT PeriodId, Period FROM periods_ref LIMIT 10;
Loading
Loading