q3c
q3c : q3c sky indexing plugin
Overview
| ID | Extension | Package | Version | Category | License | Language |
|---|---|---|---|---|---|---|
| 1540 | q3c | q3c | 2.0.2 | GIS | GPL-2.0 | C |
| Attribute | Has Binary | Has Library | Need Load | Has DDL | Relocatable | Trusted |
|---|---|---|---|---|---|---|
--s-d-r | No | Yes | No | Yes | yes | no |
| Relationships | |
|---|---|
| See Also | h3 pg_geohash earthdistance pg_sphere postgis postgis_topology postgis_raster postgis_sfcgal |
Packages
| Type | Repo | Version | PG Major Compatibility | Package Pattern | Dependencies |
|---|---|---|---|---|---|
| EXT | PGDG | 2.0.2 | 18 17 16 15 14 | q3c | - |
| RPM | PGDG | 2.0.2 | 18 17 16 15 14 | q3c_$v | - |
| DEB | PGDG | 2.0.2 | 18 17 16 15 14 | postgresql-$v-q3c | - |
| Linux / PG | PG18 | PG17 | PG16 | PG15 | PG14 |
|---|---|---|---|---|---|
el8.x86_64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
el8.aarch64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
el9.x86_64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
el9.aarch64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
el10.x86_64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
el10.aarch64 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 | PIGSTY 2.0.2 |
d12.x86_64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
d12.aarch64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
d13.x86_64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
d13.aarch64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
u22.x86_64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
u22.aarch64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
u24.x86_64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
u24.aarch64 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 | PGDG 2.0.2 |
Source
pig build pkg q3c; # build rpmInstall
Make sure PGDG repo available:
pig repo add pgdg -u # add pgdg repo and update cacheInstall this extension with pig:
pig install q3c; # install via package name, for the active PG version
pig install q3c -v 18; # install for PG 18
pig install q3c -v 17; # install for PG 17
pig install q3c -v 16; # install for PG 16
pig install q3c -v 15; # install for PG 15
pig install q3c -v 14; # install for PG 14Create this extension with:
CREATE EXTENSION q3c;Usage
Source:
segasai/q3c| ADASS Paper | ASCL
Q3C (Quad Tree Cube) is a PostgreSQL extension for fast sky-indexing of astronomical catalogues. It enables efficient spatial queries on spherical coordinates (right ascension and declination), including cone searches, ellipse searches, polygon queries, positional cross-matches, and nearest-neighbor lookups.
All angles (ra, dec, distances) are in degrees, proper motions in mas/year, and epochs in years (e.g. 2000.5, 2010.5). All Q3C function names start with the q3c_ prefix.
Table Preparation
To use Q3C, create a spatial index on your table with ra and dec columns (in degrees):
CREATE INDEX ON mytable (q3c_ang2ipix(ra, dec));Optionally cluster the table by the index to ensure faster queries on large datasets:
CLUSTER mytable_q3c_ang2ipix_idx ON mytable;Alternatively, reorder the table before indexing:
CREATE TABLE mytable1 AS SELECT * FROM mytable ORDER BY q3c_ang2ipix(ra, dec);After indexing, analyze the table:
ANALYZE mytable;Functions
q3c_ang2ipix(ra, dec)– returns the ipix value (64-bit integer pixel identifier) for given ra and decq3c_dist(ra1, dec1, ra2, dec2)– returns the distance in degrees between two pointsq3c_dist_pm(ra1, dec1, pmra1, pmdec1, cosdec_flag, epoch1, ra2, dec2, epoch2)– returns distance in degrees between two points, taking proper motion into account. Thecosdec_flag(0 or 1) indicates whether the proper motion includes the cos(dec) term (1) or not (0).q3c_join(ra1, dec1, ra2, dec2, radius)– returns true if (ra1, dec1) is withinradiusspherical distance of (ra2, dec2). Use when the index onq3c_ang2ipix(ra2, dec2)is created.q3c_join_pm(ra1, dec1, pmra1, pmdec1, cosdec_flag, epoch1, ra2, dec2, epoch2, max_delta_epoch, radius)– likeq3c_joinbut takes proper motion into account.max_delta_epochis the maximum epoch difference possible between two tables.q3c_ellipse_join(ra1, dec1, ra2, dec2, major, ratio, pa)– likeq3c_join, except (ra1, dec1) must be within an ellipse with semi-major axismajor, axis ratioratio, and position anglepa(from north through east)q3c_radial_query(ra, dec, center_ra, center_dec, radius)– returns true if (ra, dec) is withinradiusdegrees of (center_ra, center_dec). Main function for cone searches. Requires index onq3c_ang2ipix(ra, dec).q3c_ellipse_query(ra, dec, center_ra, center_dec, maj_ax, axis_ratio, PA)– returns true if (ra, dec) is within the ellipse from (center_ra, center_dec), specified by semi-major axis, axis ratio, and positional angle.q3c_poly_query(ra, dec, poly)– returns true if (ra, dec) is within the spherical polygon specified as an array of RA/DEC values or a PostgreSQL polygon type. Uses the index.q3c_ipix2ang(ipix)– returns a two-element array of (ra, dec) corresponding to a given ipixq3c_pixarea(ipix, bits)– returns the spherical area corresponding to a given ipix at the pixelisation level given bybits(1 is smallest, 30 is the cube face)q3c_ipixcenter(ra, dec, bits)– returns the ipix value of the pixel center at certain pixel depth covering the specified (ra, dec)q3c_in_poly(ra, dec, poly)– returns true/false if point is inside a polygon. Does NOT use the q3c index.q3c_version()– returns the installed version of Q3C
Examples
Cone Search
Query all objects within 0.1 degrees of (ra, dec) = (11, 12):
SELECT * FROM mytable WHERE q3c_radial_query(ra, dec, 11, 12, 0.1);The column names of the table must come first, and the search location after, otherwise the index will not be used.
Alternative cone search using q3c_join (can be faster for small tables):
SELECT * FROM mytable WHERE q3c_join(11, 12, ra, dec, 0.1);Ellipse Search
Search for objects within an ellipse centered at (10, 20) with semi-major axis 1 degree, axis ratio 0.5, and PA of 10 degrees:
SELECT * FROM mytable WHERE q3c_ellipse_query(ra, dec, 10, 20, 1, 0.5, 10);Polygon Search
Query objects inside a spherical polygon with vertices (0,0), (2,0), (2,1), (0,1):
SELECT * FROM mytable WHERE
q3c_poly_query(ra, dec, ARRAY[0, 0, 2, 0, 2, 1, 0, 1]);Using PostgreSQL polygon type:
SELECT * FROM mytable WHERE
q3c_poly_query(ra, dec, '((0, 0), (2, 0), (2, 1), (0, 1))'::polygon);Positional Cross-Match
Cross-match table1 and table2 within 0.001 degrees. The index must exist on q3c_ang2ipix(ra, dec) of table2:
SELECT * FROM table1 AS a, table2 AS b WHERE
q3c_join(a.ra, a.dec, b.ra, b.dec, 0.001);The ra/dec columns from the indexed table must be the 3rd and 4th arguments. This returns all pairs within the matching distance, not just nearest neighbors.
With per-object error radius:
SELECT * FROM table1 AS a, table2 AS b WHERE
q3c_join(a.ra, a.dec, b.ra, b.dec, a.err);Ellipse Cross-Match
Cross-match using elliptical error areas (e.g., matching within galaxy elliptical bodies):
SELECT * FROM table1 AS a, table2 AS b WHERE
q3c_ellipse_join(a.ra, a.dec, b.ra, b.dec, a.maj_ax, a.axis_ratio, a.PA);Cross-Match with Proper Motion
Cross-match with proper motion correction. Assumes table1 has pmra, pmdec (mas/yr) and epoch columns, pmra includes cos(dec) factor, and max epoch difference is 30 years:
SELECT * FROM table1 AS a, table2 AS b WHERE
q3c_join_pm(a.ra, a.dec, a.pmra, a.pmdec, 1,
a.epoch, b.ra, b.dec, b.epoch, 30, 0.001);Nearest Neighbour (with NULLs for unmatched)
Returns the nearest neighbour for each row, with NULLs if no match exists within 1 arcsecond:
SELECT t.*, ss.* FROM mytable AS t
LEFT JOIN LATERAL (
SELECT s.*
FROM sdssdr9.phototag AS s
WHERE q3c_join(t.ra, t.dec, s.ra, s.dec, 1./3600)
ORDER BY q3c_dist(t.ra, t.dec, s.ra, s.dec) ASC
LIMIT 1
) AS ss ON true;Nearest Neighbour (matched only)
Returns only objects that have neighbours:
SELECT t.*, ss.* FROM mytable AS t,
LATERAL (
SELECT s.*
FROM sdssdr9.phototag AS s
WHERE q3c_join(t.ra, t.dec, s.ra, s.dec, 1./3600)
ORDER BY q3c_dist(t.ra, t.dec, s.ra, s.dec) ASC
LIMIT 1
) AS ss;Nearest Neighbour (CTE variant)
Uses a CTE with an object ID column (requires an index on the ID column):
WITH x AS MATERIALIZED (
SELECT *, (
SELECT objid FROM sdssdr9.phototag AS p
WHERE q3c_join(m.ra, m.dec, p.ra, p.dec, 1./3600)
ORDER BY q3c_dist(m.ra, m.dec, p.ra, p.dec) ASC
LIMIT 1
) AS match_objid
FROM mytable AS m
)
SELECT * FROM x, sdssdr9.phototag AS s WHERE x.match_objid = s.objid;Density Estimation
Estimate object density using pixelation depth of 25:
SELECT (q3c_ipix2ang(i))[1] AS ra,
(q3c_ipix2ang(i))[2] AS dec,
c,
q3c_pixarea(i, 25) AS area
FROM (
SELECT q3c_ipixcenter(ra, dec, 25) AS i, count(*) AS c
FROM mytable
GROUP BY i
) AS x;Note: Q3C does not have uniform pixel areas (unlike HEALPIX).
Limitations
- Querying very large polygons with diameter greater than ~25 degrees is not supported
- Polygons with more than 100 vertices are not supported
Performance Tips
- Ensure correct argument order in Q3C functions (e.g.,
q3c_radial_query(ra, dec, 120, 3, 1)notq3c_radial_query(120, 3, ra, dec, 1)) - Use
EXPLAINto verify the query plan uses bitmap scans on the Q3C index - If the planner chooses a bad plan, try:
SET enable_mergejoin TO off; SET enable_seqscan TO off; SET enable_hashjoin TO off; - Cluster the table using the Q3C index for best performance
- When combining
q3c_join()with additional filter clauses, use CTEs withMATERIALIZEDto avoid plan issues:
WITH x AS MATERIALIZED (SELECT * FROM t1 WHERE t1.mag < 1),
y AS (SELECT *, t2.mag AS t2mag FROM x, t2 WHERE q3c_join(x.ra, x.dec, t2.ra, t2.dec, 1./3600))
SELECT * FROM y WHERE t2mag > 33;