Spatial Queries with the Go Client

Tip
The source code for this tutorial is available on GitHub.

This tutorial demonstrates how to run geospatial queries on indexed Infinispan caches using the Go Hot Rod client.

Prerequisites

  • A running Infinispan server.

  • Go 1.25 or later.

Running the Example

go run ./spatial-queries

Code Walkthrough

Schema and Code Generation

The example uses proto/restaurant.proto and proto/trainroute.proto to generate Go structs at build time with protoc. The same schemas — with Infinispan spatial annotations — are registered on the server.

The Restaurant schema uses @GeoPoint with @Latitude and @Longitude annotations to create a composite spatial field called location.

/**
 * @Indexed
 * @GeoPoint(fieldName = "location", projectable = true, sortable = true)
 */
message Restaurant {
    /** @Keyword(normalizer = "lowercase", projectable = true, sortable = true) */
    string name = 1;
    /** @Latitude(fieldName = "location") */
    double latitude = 4;
    /** @Longitude(fieldName = "location") */
    double longitude = 5;
}

The TrainRoute schema demonstrates multiple geo points on a single entity.

/**
 * @Indexed
 * @GeoPoint(fieldName = "departure", projectable = true, sortable = true)
 * @GeoPoint(fieldName = "arrival", projectable = true, sortable = true)
 */
message TrainRoute {
    /** @Latitude(fieldName = "departure") */
    double departureLat = 2;
    /** @Longitude(fieldName = "departure") */
    double departureLon = 3;
    /** @Latitude(fieldName = "arrival") */
    double arrivalLat = 4;
    /** @Longitude(fieldName = "arrival") */
    double arrivalLon = 5;
}

Creating Typed Caches

Two TypedCache instances point to the same cache — one per entity type.

restaurantCache := hotrod.NewTypedCache[string, *pb.Restaurant](client, "spatialCache").Build()
trainRouteCache := hotrod.NewTypedCache[string, *pb.TrainRoute](client, "spatialCache").Build()

Within Circle (Typed)

Find restaurants within a 100-meter radius. Query() returns typed *pb.Restaurant values.

results, err := cache.Query(ctx,
    "from tutorial.Restaurant r where r.location within circle(41.908470, 12.455633, 100)")
for _, r := range results {
    fmt.Printf("  %s\n", r.Name)
}

Distance Projection

Projection queries use QueryProjection() which returns raw column values.

result, err := cache.QueryProjection(ctx,
    "select r.name, distance(r.location, 41.908470, 12.455633) from tutorial.Restaurant r")

Expected Output

Registered Restaurant and TrainRoute schemas.
Cache 'spatialCache' ready.
Added 7 restaurants in Rome.
Added 4 train routes.

=== Within circle (100m radius) ===
Found <n> restaurants:
  La Locanda di Pietro
  ...

=== Within box ===
Found <n> restaurants:
  ...

=== Within polygon ===
Found <n> restaurants:
  ...

=== Distance projection ===
  La Locanda di Pietro: <n>m
  ...

=== Order by distance ===
  ...

=== Train routes departing near Bologna (300km) ===
Found 2 routes:
  Bologna-Selva
  Bologna-Venice

Cache removed.