Cartesian spatial traversals
Creating Cartesian spatial traversal queries.
Cartesian spatial queries are used to discover Cartesian (graphable) information. All Cartesian data types (points, linestrings, and polygons) can be searched for specified values with simple queries. More interesting traversal queries discover points or linestrings within a radius from a specified point or within a specified spatial polygon.
DSE Search indexes can be created to decrease the latency in response time, but are not
required. Create schema to use a search index for point
and
linestring
properties in the Cartesian
schema.
Schema and data
// SCHEMA
// POINT
schema.propertyKey('name').Text().create()
schema.propertyKey('point').Point().withBounds(-3, -3, 3, 3).create()
schema.vertexLabel('location').properties('name','point').create()
// LINESTRING
schema.propertyKey('line').Linestring().withBounds(-3, -3, 3, 3).create()
schema.vertexLabel('lineLocation').properties('name','line').create()
// POLYGON
schema.propertyKey('polygon').Polygon().withBounds(-3, -3, 3, 3).create()
schema.vertexLabel('polyLocation').properties('name','polygon').create()
// MATERIALIZED VIEW INDEXES
schema.vertexLabel('location').index('byname').materialized().by('name').add()
schema.vertexLabel('lineLocation').index('byname').materialized().by('name').add()
schema.vertexLabel('polyLocation').index('byname').materialized().by('name').add()
//SEARCH INDEX - ONLY WORKS FOR POINT AND LINESTRING
schema.vertexLabel('location').index('search').search().by('point').add()
schema.vertexLabel('lineLocation').index('search').search().by('line').add()
/// Create a point
graph.addVertex(label,'location','name','p0','point',Geo.point(0.5,0.5))
graph.addVertex(label,'location','name','p1','point',Geo.point(1,1))
graph.addVertex(label,'location','name','p2','point',Geo.point(-1,1))
graph.addVertex(label,'location','name','p3','point',Geo.point(-2,-2))
graph.addVertex(label,'location','name','p4','point',Geo.point(2,2))
// Create a linestring
graph.addVertex(label, 'lineLocation', 'name', 'l1', 'line', "LINESTRING(0 0, 1 1)")
graph.addVertex(label, 'lineLocation', 'name', 'l2', 'line', "LINESTRING(0 0, -1 1)")
graph.addVertex(label, 'lineLocation', 'name', 'l3', 'line', "LINESTRING(0 0, -2 -2)")
graph.addVertex(label, 'lineLocation', 'name', 'l4', 'line', "LINESTRING(0 0, 2 -2)")
// Create a polygon
graph.addVertex(label, 'polyLocation','name', 'g1', 'polygon',Geo.polygon(0,0,1,1,0,1,0,0))
graph.addVertex(label, 'polyLocation','name', 'g2', 'polygon',Geo.polygon(0,0,0,1,-1,1,0,0))
graph.addVertex(label, 'polyLocation','name', 'g3', 'polygon',Geo.polygon(0,0,-2,0,-2,-2,0,0))
graph.addVertex(label, 'polyLocation','name', 'g4', 'polygon',Geo.polygon(0,0,2,0,2,-2,0,0))
Find stored Cartesian spatial data that matches specified information
g.V().
has('location','point', Geo.point(0.5, 0.5)).
valueMap()
results
in:{name=[p0], point=[POINT (0.5 0.5)]}
g.V().
has('lineLocation','line',Geo.lineString(0, 0, 1, 1)).
valueMap()
results
in:{line=[LINESTRING (0 0, 1 1)], name=[l1]}
g.V().
has('polyLocation', 'polygon',Geo.polygon(0,0,1,1,0,1,0,0)).
valueMap()
results
in:{polygon=[POLYGON ((0 0, 1 1, 0 1, 0 0))], name=[g1]}
Find stored Cartesian spatial points or linestrings within a specified radius from a specified point
These queries, as well as the queries that use a specified Cartesian spatial polygon use a
method Geo.inside()
that specifies a point and a radius.
g.V().
has('location', 'point', Geo.inside(Geo.point(0, 0), 1)).
values('name')
lists:==>p0
Centering
the query on (0, 0) and searching within 1 unit returns one point, p0, from the
dataset. g.V().has('lineLocation', 'line', Geo.inside(Geo.point(0.0, 0.0), 1.415)).valueMap()
lists:==>{line=[LINESTRING (0 0, 1 1)], name=[l1]}
==>{line=[LINESTRING (0 0, -1 1)], name=[l2]}
Centering the query on (0,0) and searching within 1.415 units returns two stored
linestrings: l1 and l2.Find stored Cartesian spatial points or linestrings within a specified Cartesian spatial polygon
Polygons may be used in these queries to find points with a polygon.
g.V().
has('location', 'point', Geo.inside(Geo.polygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0))).
values('name')
lists:==>p0
g.V().
has('lineLocation', 'line', Geo.inside(Geo.polygon(0, 0, 1, 0, 1, 1, 0, 1, 0, 0))).
values('name')
lists:==>l1
Schema and data
///SCHEMA
// PROPERTY KEYS
// Check for previous creation of property key with ifNotExists()
schema.propertyKey('name').Text().ifNotExists().create()
schema.propertyKey('address').Text().ifNotExists().create()
schema.propertyKey('location').Point().withBounds(-100,-100,100,100).ifNotExists().create()
// VERTEX LABELS
schema.vertexLabel('person').properties('name').ifNotExists().create()
schema.vertexLabel('home').properties('address','location').ifNotExists().create()
schema.vertexLabel('store').properties('name','location').ifNotExists().create()
schema.vertexLabel('ingredient').properties('name').ifNotExists().create()
// EEDGE LABELS
schema.edgeLabel('livesIn').connection('person','home').ifNotExists().create()
schema.edgeLabel('isStockedWith').connection('store','ingredient').multiple().ifNotExists().create()
// SEARCH INDEXES
schema.vertexLabel('person').index('search').search().by('name').asString().ifNotExists().add()
schema.vertexLabel('home').index('search').search().by('name').by('location').add();
schema.vertexLabel('store').index('search').search().by('name').by('location').add();
schema.vertexLabel('ingredient').index('search').search().by('name').add();
//VERTICES
// PERSON VERTICES
pam = graph.addVertex(label, 'person', 'name','Pam')
les = graph.addVertex(label, 'person', 'name','Les')
paul = graph.addVertex(label, 'person', 'name','Paul')
victoria = graph.addVertex(label, 'person', 'name','Victoria')
terri = graph.addVertex(label, 'person', 'name','Terri')
// HOME VERTICES
home1 = graph.addVertex(label, 'home', 'address', '555 4th St', 'location', Geo.point(7,2));
home2 = graph.addVertex(label, 'home', 'address', '1700 Coyote Rd', 'location', Geo.point(-2,1));
home3 = graph.addVertex(label, 'home', 'address', '99 Mountain Pass Hwy', 'location', Geo.point(0,0));
// STORE VERTICES
store1 = graph.addVertex(label, 'store', 'name', 'ZippyMart', 'location', Geo.point(1,5));
store2 = graph.addVertex(label, 'store', 'name', 'Quik Station', 'location', Geo.point(7,-1));
store3 = graph.addVertex(label, 'store', 'name', 'Mamma's Grocery', 'location', Geo.point(-3,-3));
// INGREDIENT VERTICES
celery = graph.addVertex(label, 'ingredient','name', 'celery');
milk = graph.addVertex(label, 'ingredient','name', 'milk');
bokChoy = graph.addVertex(label, 'ingredient','name', 'bok choy');
steak = graph.addVertex(label, 'ingredient','name', 'steak');
carrots = graph.addVertex(label, 'ingredient','name', 'carrots');
porkChops = graph.addVertex(label, 'ingredient','name', 'pork chops');
// PERSON - HOME EDGES
pam.addEdge('livesIn', home1);
les.addEdge('livesIn', home1);
paul.addEdge('livesIn',home3);
victoria.addEdge('livesIn',home3);
terri.addEdge('livesIn',home2);
// STORE - INGREDIENT EDGES
store1.addEdge('isStockedWith', milk);
store1.addEdge('isStockedWith', bokChoy);
store1.addEdge('isStockedWith', steak);
store2.addEdge('isStockedWith', steak);
store2.addEdge('isStockedWith', carrots);
store2.addEdge('isStockedWith', porkChops);
store3.addEdge('isStockedWith', milk);
store3.addEdge('isStockedWith', carrots);
store3.addEdge('isStockedWith', celery);
Finding celery
You are a mathematics teacher writing simple Cartesian problem for your students. They are great fans of ants on a log, a snack made with celery, cream cheese, and raisins. So, you decide to help them find the nearest store to their house which has celery in stock.
g.V().has('store', 'location', Geo.inside(Geo.point(0,0),10)).
values('name')
results
in:==>ZippyMart
==>Quik Station
==>Mamma's Grocery
Note that this
exercise is using Cartesian coordinates and distances calculated between Cartesian points,
but a similar exercises can use geospatial
data.g.V().has('store', 'location', Geo.inside(Geo.point(0,0),10)).as('Store').
out().has('name','celery').as('Ingred').
select('Store', 'Ingred').
by('name').
by('name')
finds:==>{Store=ZippyMart, Ingred=celery}
==>{Store=Quik Station, Ingred=celery}
==>{Store=Mamma's Grocery, Ingred=celery}
This query uses methods that are common, such as as()
,
out()
, and select()
that are explained in Simple Traversals to narrow the query. // List store name, location, and ingredient in order by distance from the store
g.V().has('store', 'location', Geo.inside(Geo.point(0,0),25)).as('Store').
order().by{it.value('location').getOgcGeometry().distance(Geo.point(0,0).getOgcGeometry())}.
as('Location').
out().has('name','celery').as('Ingred').
select('Store', 'Location','Ingred').
by('name').
by('location').
by('name')
==>{Store=Mamma's Grocery, Location=POINT (-3 -3), Ingred=celery}
==>{Store=ZippyMart, Location=POINT (1 5), Ingred=celery}
==>{Store=Quik Station, Location=POINT (7 -1), Ingred=celery}
This
query adds the method order()
to sort the results; it is also explained in
Simple Traversals. The query must also use a method that
must be imported in order for the query to succeed: getOgcGeometry()
and
distance()
. Importing the library is accomplished in the original script
using:import com.esri.core.geometry.ogc.OGCGeometry;
The students working on this problem now know that Mamma's Grocery is the place to head to get the celery they need to make their favorite snack!