Geospatial Queries

This page describes how to use geospatial queries in Datastore. A geospatial query allows you to retrieve entities containing a GeoPt property whose latitude, longitude coordinates lie within a given geographic region.

Adding a GeoPt to an entity

To add a GeoPt property to an entity, use the GeoPt class, specifying latitude and longitude:

Entity station = new Entity("GasStation");
station.setProperty("brand", "Ocean Ave Shell");
station.setProperty("location", new GeoPt(37.7913156f, -122.3926051f));

Geospatial queries

Use the datastore query filter StContainsFilter to test if a GeoPt is contained in a given GeoRegion, for example:

// Testing for containment within a circle
GeoPt center = new GeoPt(latitude, longitude);
double radius = r; // Value is in meters.
Filter f1 = new StContainsFilter("location", new Circle(center, radius));
Query q1 = new Query("GasStation").setFilter(f1);

// Testing for containment within a rectangle
GeoPt southwest = new GeoPt(swLat, swLon);
GeoPt northeast = new GeoPt(neLat, neLon);
Filter f2 = new StContainsFilter("location", new Rectangle(southwest, northeast));
Query q2 = new Query("GasStation").setFilter(f2);

You can combine geospatial containment terms with equality tests on any type of property:

Filter f =
        new StContainsFilter("location", new Circle(center, radius)),
        new FilterPredicate("brand", FilterOperator.EQUAL, value));

Geospatial queries must follow these rules:

  • The query must include at least one containment term.
  • The query may contain any number of non-geospatial terms, but these other terms may only test for EQUAL (not "less than", "greater than", etc.).
  • The query cannot use an ancestor filter.

Building an Index file

As with other Datastore queries, the recommended development workflow is to rely on the automatic index configuration provided by the dev appserver. You implement queries in your code, and then execute all of them while running tests on the dev appserver. This causes the dev appserver to write an index configuration file defining the necessary indexes.

The form of an index definition that supports geospatial queries is a bit different from traditional composite indexes. For example:

<?xml version="1.0" encoding="utf-8"?>
<datastore-indexes autoGenerate="false">
  <datastore-index kind="GasStation" source="manual">
    <property name="location" mode="geospatial" />
  <datastore-index kind="GasStation" source="manual">
    <property name="brand" />
    <property name="location" mode="geospatial" />

If you build your own search index files to handle geospatial searches, be sure to follow these rules:

  • Add the mode="geospatial" attribute to properties that appear in geo-containment query terms.
  • Do not assign the direction attribute to any property in an index designed to handle geospatial searches.
  • Non-geospatial properties should be listed first, and each of the two groups of properties should appear in increasing alpha order by property name.
  • Do not assign the ancestor attribute to an index that contains a mode="geospatial" property.

One index configuration file can include multiple indexes of any kind.

Recall that "ordinary" (non-geospatial) queries require that an index exists that contains all the properties in the query and no others. This constraint is relaxed for geospatial queries. An index with more than one mode="geospatial" property can be used to perform a geospatial query that only uses a subset of the geospatial properties in that index. If a geospatial query includes other non-geospatial properties, the index must also contain those non-geo properties and no others, as the case with non-geospatial queries.

Known issues

This is an alpha release of geospatial search. It has some limitations that will be removed in future releases:

  • Geospatial search is only available in the Java runtime, Python support is coming soon.
  • Geospatial search is only accessible using App Engine's Datastore API, there is no GQL support at this time.
  • Cursors will not appear in results from geospatial queries. Calls to QueryResultIterator.getCusor() return NULL.
  • In the Google Cloud Platform Console, you can view indexes that support geospatial queries. However, property names with the mode="geospatial" attribute are not labeled as such, and they are (incorrectly) assigned a default descending sort direction.
  • It is not possible to run a geospatial query from the Google Cloud Platform Console.