Geospatial Index
Geospatial indexes can be defined by using the @SpaceSpatialIndex
and @SpaceSpatialIndexes
annotations.
Lets assume we have a class called GasStation
that has a Point
property that describes its location and we want to execute geospatial queries
against this property:
public class GasStation {
private Point location;
@SpaceSpatialIndex
public Point getLocation() {
return location;
}
public void setLocation(Point location) {
this.location = location;
}
}
Here is a query that will trigger the usage of this index:
SQLQuery<GasStation> query = new SQLQuery<GasStation>(GasStation.class, "location spatial:within ?")
.setParameter(1, ShapeFactory.circle(p, 4.5d));
When using the Geospatial Index feature, complex geographic features may require an increase in the com.gs.replication.replicaProgressTimeout parameter.
See Geospatial Queries for more information on how geospatial queries work.
Nested Index
An index can be defined on a nested property to improve performance of nested queries. Nested properties indexing uses an additional attribute - path()
.
This attribute represents the path of the property within the nested object.
In the example below, the Point
is a property of the class Location
which is a property of GasStation
:
import org.openspaces.spatial.SpaceSpatialIndex;
import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
@SpaceClass
public class GasStation {
private Long id;
private Location location;
...
@SpaceSpatialIndex(path = "point")
public Location getLocation() {
return location;
}
}
import org.openspaces.spatial.shapes.Point;
public class Location {
private String address;
private Point point;
}
import org.openspaces.spatial.SpaceSpatialIndex;
import com.gigaspaces.annotation.pojo.SpaceClass;
import com.gigaspaces.annotation.pojo.SpaceId;
@SpaceClass
public class GasStation {
private Long id;
private Location location;
...
@SpaceSpatialIndexes({ @SpaceSpatialIndex(path = "point"), @SpaceSpatialIndex(path = "circle")})
public Location getLocation() {
return location;
}
}
import org.openspaces.spatial.shapes.Point;
public class Location {
private String address;
private Point point;
private Circle circle;
}
The following is an example of a query that triggers this index:
SQLQuery<GasStation> query = new SQLQuery<GasStation>(GasStation.class, "location.point spatial:within ?")
.setParameter(1, ShapeFactory.circle(p, 4.5d));
GasStation station = gigaSpace.read(query);
Combining Spatial and Standard Predicates
Suppose our GasStation
class contains a price
property as well, and we want to enhance our query and find nearby gas stations whose price is lower than a certain threshold. We can simply add the relevant predicate to the query's criteria:
public GasStation findNearbyGasStation(Point location, int radius, double maxPrice) {
SQLQuery<GasStation> query = new SQLQuery(GasStation.class, "location spatial:within ? AND price < ?")
.setParameter(1, ShapeFactory.circle(location, radius))
.setParameter(2, maxPrice);
return gigaSpace.read(query);
}
You should make an effort to choose the optimal index. For example, If both location
and price
are indexed, the index which appears first in the query is the one that will be used. This may significantly affect the performance of your query, so it's recommended to estimate which index is most efficient for each query and put it first.
PU Example
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:os-core="http://www.openspaces.org/schema/core"
xsi:schemaLocation="Index of /schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.openspaces.org/schema/core http://www.openspaces.org/schema/core/openspaces-core.xsd">
<bean id="propertiesConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="properties">
<props>
<prop key="dataGridName">dataGrid</prop>
<prop key="strategy">BBox</prop>
<prop key="directoryType">RAMDirectory</prop>
<prop key="spatialContext">Spatial4J</prop>
<prop key="spatialContextGeo">true</prop>
</props>
</property>
</bean>
<bean id="luceneSpatialQueryExtensionProvider" class="org.openspaces.spatial.spi.LuceneSpatialQueryExtensionProvider">
<constructor-arg name="customProperties">
<props>
<prop key="lucene.strategy">${strategy}</prop>
<prop key="lucene.storage.directory-type">${directoryType}</prop>
<prop key="context">${spatialContext}</prop>
<prop key="context.geo">${spatialContextGeo}</prop>
</props>
</constructor-arg>
</bean>
<os-core:space id="space" url="/./${dataGridName}">
<os-core:query-extension-provider ref="luceneSpatialQueryExtensionProvider"/>
</os-core:space>
</beans>