Skip to main content

geopoint

The geopoint template is a geospatial analyzer for the common case where each row is a single point whose coordinates are already stored as latitude and longitude. Rather than requiring GeoJSON, it reads the two coordinates straight from a JSON value and emits the S2 cell-ID terms that the inverted index stores and matches — so the column can be queried by region and distance just like a geojson column.

How it works

The analyzer pulls a latitude and a longitude out of each indexed JSON value, builds the point and emits an S2 cell covering of it as index terms. There are two input shapes:

  • Named fields — set latitude and longitude to the field names (or slash-separated paths such as loc/lat). The analyzer reads {"lat": …, "lng": …}-style objects.
  • Coordinate array — leave both options unset (the default) and the analyzer treats the indexed value as a [latitude, longitude] array. Note this is [lat, lng] order, the reverse of GeoJSON's [longitude, latitude].

latitude and longitude must be set together or left unset together — setting only one is an error.

When to use geopoint vs geojson

Use geopoint when each row is one point held as separate lat/lng fields: it skips GeoJSON assembly and indexes the coordinates directly. Use geojson when rows hold arbitrary geometries (polygons, lines) or points already expressed as GeoJSON. Both emit the same S2 terms, so a given point is queried identically whichever template indexed it.

Options

OptionTypeDefaultDescription
latitudestring(none — array input)Field name or slash path holding the latitude
longitudestring(none — array input)Field name or slash path holding the longitude
minlevelinteger4Minimum S2 cell level (0–30)
maxlevelinteger23Maximum S2 cell level (0–30); ~1 m precision at level 23
maxcellsinteger20Maximum number of S2 cells in a covering
levelmodinteger1S2 level step (1, 2 or 3)
optimizeforspacebooleanfalseOptimize the S2 covering for space rather than speed

Usage

Create the dictionary naming the coordinate fields, then attach it to a JSON column in a USING inverted index:

Query
CREATE TEXT SEARCH DICTIONARY geopoint_dict (    template = 'geopoint',    latitude = 'lat',    longitude = 'lng');

ts_lexize shows the cell-ID terms a point expands into. Because geopoint and geojson describe the same physical location, the same point produces an identical covering whichever template indexes it — here central Berlin as {"lat": …, "lng": …} versus the GeoJSON [lon, lat] of the geojson example:

Query
SELECT ts_lexize(    'geopoint_dict',    '{"lat":52.52,"lng":13.405}');
Result
 ts_lexize--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- {47b,47ac,47a9,47a84,47a85,47a854,47a851,47a851c,47a851d,47a851dc,47a851df,47a851dfc,47a851dff,47a851dfec,47a851dfed,47a851dfecc,47a851dfecd,47a851dfeccc,47a851dfecc9,47a851dfecc9c}

For the full indexing-and-query walkthrough — ST_Intersects, ST_Contains and distance predicates — see Geospatial Search.

See also