Spatial Queries
What You Will Learn
How to define geospatial entities with @GeoPoint and @GeoField annotations, create indexed caches, and run spatial Ickle queries including within circle, within box, within polygon, distance projections, and spatial ordering.
Prerequisites
-
Java 17+
-
An Infinispan Server running on
localhost:11222(or Docker/Podman available for Testcontainers)
Step 1: Define Geospatial Entities
Use @GeoPoint with @Latitude and @Longitude to define a location on a record:
@Proto
@Indexed
@GeoPoint(fieldName = "location", projectable = true, sortable = true)
public record Restaurant(
@Keyword(normalizer = "lowercase", projectable = true, sortable = true) String name,
@Text String description,
@Text String address,
@Latitude(fieldName = "location") Double latitude,
@Longitude(fieldName = "location") Double longitude,
@Basic Float score
) {
}
For entities with multiple geo points, use multiple @GeoPoint annotations (see TrainRoute). Alternatively, use @GeoField with LatLng for a simpler mapping:
@Proto
@Indexed
public record Hiking(@Keyword String name, @GeoField LatLng start, @GeoField LatLng end) {
}
Step 2: Create an Indexed Cache and Run Spatial Queries
Configure the cache with indexing enabled for all spatial entities. Then run spatial queries — within a circle, within a bounding box, within a polygon, and with distance projections and ordering:
static QueryResult<Restaurant> withinCircle() {
Query<Restaurant> query = myCache.query("from tutorial.Restaurant r where r.location " +
"within circle(:lat, :lon, :distance)");
query.setParameter("lat", MY_COORDINATES.latitude());
query.setParameter("lon", MY_COORDINATES.longitude());
query.setParameter("distance", 100);
QueryResult<Restaurant> queryResult = query.execute();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(queryResult.list());
return queryResult;
}
static QueryResult<Restaurant> withinBox() {
Query<Restaurant> query = myCache.query("from tutorial.Restaurant r where r.location " +
"within box(41.91, 12.45, 41.90, 12.46)");
QueryResult<Restaurant> queryResult = query.execute();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(queryResult.list());
return queryResult;
}
static QueryResult<Restaurant> withinPolygon() {
Query<Restaurant> query = myCache.query("from tutorial.Restaurant r where r.location " +
"within polygon((41.91, 12.45), (41.91, 12.46), (41.90, 12.46), (41.90, 12.46))");
QueryResult<Restaurant> queryResult = query.execute();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(queryResult.list());
return queryResult;
}
static List<RestaurantDTO> spatialProjection() {
Query<Object[]> query = myCache.query("select r.name, distance(r.location, 41.90847031512531, 12.455633288333539) " +
"from tutorial.Restaurant r");
QueryResult<Object[]> queryResult = query.execute();
List<RestaurantDTO> valueObjects = queryResult.list().stream()
.map(r -> new RestaurantDTO((String) r[0], (Double) r[1]))
.toList();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(valueObjects);
return valueObjects;
}
static QueryResult<Restaurant> spatialOrderBy() {
Query<Restaurant> query = myCache.query("from tutorial.Restaurant r where r.location " +
"order by distance(r.location, 41.90847031512531, 12.455633288333539)");
QueryResult<Restaurant> queryResult = query.execute();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(queryResult.list());
return queryResult;
}
static List<RestaurantDTO> spatialProjection_OrderBy() {
Query<Object[]> query = myCache.query("select r.name, distance(r.location, 41.90847031512531, 12.455633288333539) " +
"from tutorial.Restaurant r where r.location " +
"order by distance(r.location, 41.90847031512531, 12.455633288333539)");
QueryResult<Object[]> queryResult = query.execute();
List<RestaurantDTO> valueObjects = queryResult.list().stream()
.map(r -> new RestaurantDTO((String) r[0], (Double) r[1]))
.toList();
// Print the results
System.out.println("COUNT " + queryResult.count().value());
System.out.println(valueObjects);
return valueObjects;
}
Step 3: Run the Tutorial
mvn package exec:java
What’s Next
-
Query your data with standard Ickle queries
-
Use continuous queries for real-time notifications


