To learn about geospatial objects, see the Geospatial objects developer guide.
Prerequisites
To follow the code examples in this guide, you must install Docker locally and download recipes.Navigate to recipe
- If you haven’t already, download recipes.
- In terminal, go to the recipe by running the following command:
Launch Pinot Cluster
You can spin up a Pinot Cluster by running the following command:Generating Geospatial data
This recipe contains a data generator that produces JSON documents that contain various geospatial objects in Well-known text (WKT) format. You’ll need to first install the following dependencies:Kafka ingestion
We’re going to ingest this data into an Apache Kafka topic using the kcat command line tool. We’ll also usejq to structure the data in the key:payload structure that Kafka expects:
Pinot Schema and Table
Now let’s create a Pinot Schema and Table. First, the schema:point has a data type of BYTES. Geospatial columns must use the BYTES type because Pinot will serialize the Geospatial objects into bytes for storage purposes.
Now for the table config:
point column. If you scroll down a bit, under ingestionConfig.transformConfigs you can see transformation functions that converts the WKT string from our Kafka streams into a Geospatial object.
We’ll create the table by running the following:
When is the Geospatial index used?
Now that we’ve created a table that contains a column with a Geospatial index, it’d be useful to know when that index will be used. This index is used when a variety of predicates appear in theWHERE clause of a query.
ST_Distance
The ST_Distance function computes the distance in meters between two sets of coordinates.
When used with this function, one of the arguments must be an identifer (i.e. column name) and the other a literal value. The result of calling ST_Distance must then be used in a range query i.e. it should be less than or greater than a specified distance.
Examples are shown below:
ST_Within
ST_Within checks the containment of two geospatial objects. It returns true if and only if the first geometry is completely inside the second geometry.
When used with this function, the first argument must be an identifier (i.e. column name) and the other a literal value. An example is shown below:
ST_Contains
ST_Contains also checks the containment of two geospatial objects. More specifically, it returns true if and only if no points of the second geometry lie in the exterior of the first geometry, and at least one point of the interior of the first geometry lies in the interior of the second geometry.
When used with this function, the first argument must be a literal and the other an identifier (i.e. column name). An example is shown below:
Geospatial Querying
Now let’s head on over to the Pinot UI and write some queries that use the Geospatial index. The following query counts how many points fit inside a polygon that covers an area from Delaware to West Virginia.
Query Results
We can flip that query around to use
ST_Contains like this:
Query Results
How do I check that the Geospatial index is being used?
We can check that the Geospatial index is being used by prefixing a query withEXPLAIN PLAN FOR, which will return the query plan.
To get the query plan for the ST_Distance function, we’d write the following:
Query Results
We must see
FILTER_H3_INDEX as one of the operators, otherwise the index isn’t being used.
We can do the same thing for the ST_Within and ST_Contains queries. We should see the INCLUSION_FILTER_H3_INDEX operator for both these queries:
For ST_Within, we’ll see the following plan:
Query Results
Notice that the
INCLUSION_FILTER_H3_INDEX operator contains the stwithin predicate.
And for ST_Contains, we’ll see this plan:
Query Results
And notice on this one that the
INCLUSION_FILTER_H3_INDEX operator contains the stcontains predicate.
