Geospatial traversals
Creating geospatial traversal queries.
inside()
with a circle radius value of
zero. All points or linestrings can be searched within a circle or polygon using
inside()
and a specified radius. (longitude, latitude)
following WKT format.Distance calculations are crucial to proper results. DSE Search indexes can be created for geospatial data in DataStax Graph (DSG), and DSE Search uses the Haversine formula to determine the great-circle distance between two points. DSE Search indexes cannot be created for polygons, but are essential to making geospatial point and linestring queries performant.
Schema and data
schema.vertexLabel('location'). partitionBy('name', Text). property('geo_point', Point). create() schema.vertexLabel('lineLocation'). partitionBy('name', Text). property('geo_line', LineString). create() schema.vertexLabel('polyLocation'). partitionBy('name', Text). property('geo_polygon', Polygon). create() schema.vertexLabel('lineLocation'). searchIndex(). ifNotExists(). by('name').asString(). by('geo_line'). create() schema.vertexLabel('location'). searchIndex(). ifNotExists(). by('name').asString(). by('geo_point'). create() schema.vertexLabel('polyLocation'). searchIndex(). ifNotExists(). by('name').asString(). by('geo_polygon'). create()
g.addV('location'). property('name', 'Paris'). property('geo_point','POINT (2.352222 48.856614)' as Point) g.addV('location'). property('name', 'London'). property('geo_point','POINT (-0.127758 51.507351)' as Point) g.addV('location'). property('name', 'Dublin'). property('geo_point','POINT (-6.26031 53.349805)' as Point) g.addV('location'). property('name', 'Aachen'). property('geo_point','POINT (6.083887 50.775346)' as Point) g.addV('location'). property('name', 'Tokyo'). property('geo_point','POINT (139.691706 35.689487)' as Point)
g.addV('lineLocation'). property('name', 'ParisLondon'). property('geo_line', 'LINESTRING(2.352222 48.856614, -0.127758 51.507351)' as LineString) g.addV('lineLocation'). property('name', 'LondonDublin'). property('geo_line', 'LINESTRING(-0.127758 51.507351, -6.26031 53.349805)' as LineString) g.addV('lineLocation'). property('name', 'ParisAachen'). property('geo_line', 'LINESTRING(2.352222 48.856614, 6.083887 50.775346)' as LineString) g.addV('lineLocation'). property('name', 'AachenTokyo'). property('geo_line', 'LINESTRING(6.083887 50.775346, 139.691706 35.689487)' as LineString)
g.addV('polyLocation'). property('name', 'ParisLondonDublin'). property('geo_polygon', 'POLYGON ((2.352222 48.856614, -0.127758 51.507351, -6.26031 53.349805))' as Polygon) g.addV('polyLocation'). property('name', 'LondonDublinAachen'). property('geo_polygon', 'POLYGON ((-0.127758 51.507351, -6.26031 53.349805, 6.083887 50.775346))' as Polygon) g.addV('polyLocation'). property('name', 'DublinAachenTokyo'). property('geo_polygon', 'POLYGON ((-6.26031 53.349805, 6.083887 50.775346, 139.691706 35.689487))' as Polygon)
// PARIS TO LONDON: 3.08 DEGREES; 344 KM; 214 MI; 344,000 M
// PARIS TO AACHEN: 3.07 DEGREES; 343 KM; 213 MI; 343,000 M
// PARIS TO DUBLIN: 7.02 DEGREES; 781 KM; 485 MI; 781,000 M
// PARIS TO TOYKO: 86.3 DEGREES; 9713 KM; 6035 MI; 9,713,000 M
Find stored geospatial points that match specified information
inside()
step. To find the stored data
that matches a point mapped to the specified (longitude, latitude), set the radius value to
zero:g.V().hasLabel('location'). has('geo_point',Geo.inside(Geo.point(2.352222, 48.856614), 0, Geo.Unit.MILES)). elementMap()results in:
==>{id=dseg:/location/Paris, label=location, name=Paris, geo_point=POINT (2.352222 48.856614)}
Find stored geospatial points, linestrings, or polygons within a specified radius from a specified point
These queries, as well as the queries that use a specified geospatial polygon use a method
Geo.inside()
that specifies a point, a radius, and the units to be
used.
Geo.inside()
method:- DEGREES
- Degrees of distance. One degree of latitude is approximately 111.2 kilometers, whereas one degree of longitude depends on the distance from the equator. At the equator, one degree of longitude equals 111.2 kilometers, but at 45 degrees of latitude, one degree of longitude is 78.6 kilometers. While the physical distance over a single degree of longitude changes with latitude, we calculate only great-circle distances in degrees.
- KILOMETERS
- Kilometers of distance.
- MILES
- Miles of distance.
- METERS
- Meters of distance.
g.V(). has('location', 'geo_point', Geo.inside(Geo.point(2.352222, 48.856614), 4.2, Geo.Unit.DEGREES)). values('name')lists:
==>Paris
==>London
==>Aachen
Centering
the query on Paris and searching within 4.2 degree radius returns three cities: Paris,
London, and Aachen from the dataset.g.V(). has('lineLocation', 'geo_line', Geo.inside(Geo.point(2.352222, 48.856614), 9713, Geo.Unit.KILOMETERS)). values('name')lists:
==>ParisLondon
==>ParisAachen
==>LondonDublin
==>AachenTokyo
Centering
the query on Paris and searching within 9713 kilometers returns four stored linestrings:
Paris to London, London to Dublin, Aachen to Tokyo, and Paris to Aachen.g.V(). has('polyLocation', 'geo_polygon', Geo.inside(Geo.point(2.352222, 48.856614), 138, Geo.Unit.DEGREES)). values('name')lists:
==>ParisLondonDublin
==>DublinAachenTokyo
==>LondonDublinAachen
Centering
the query on Paris and searching within a 138 degree radius returns four stored polygons:
Paris-London-Dublin, Dublin-Aachen-Tokyo, and London-Dublin-Aachen.Find people in cities
person
and location
, as well as an
inverse()
index:schema.edgeLabel('lives_in'). ifNotExists(). from('person').to('location'). create() schema.edgeLabel('lives_in'). from('person'). to('location'). materializedView('person__lives_in__location_by_location_name'). ifNotExists(). inverse(). create()
// START-AllPersonLivesInLocation // person to location edges g.V('dseg:/person/01e22ca6-da10-4cf7-8903-9b7e30c25805').as('a'). V('dseg:/location/London').as('b'). addE('lives_in').from('a').to('b') g.V('dseg:/person/adb8744c-d015-4d78-918a-d7f062c59e8f').as('a'). V('dseg:/location/Paris').as('b'). addE('lives_in').from('a').to('b') g.V('dseg:/person/f092107c-0c5c-47e7-917c-82c7fc2a2493').as('a'). V('dseg:/location/Paris').as('b'). addE('lives_in').from('a').to('b') g.V('dseg:/person/4ce9caf1-25b8-468e-a983-69bad20c017a').as('a'). V('dseg:/location/Dublin').as('b'). addE('lives_in').from('a').to('b') g.V('dseg:/person/888ad970-0efc-4e2c-b234-b6a71c30efb5').as('a'). V('dseg:/location/Aachen').as('b'). addE('lives_in').from('a').to('b')Of course, this data can be loaded using the DataStax Bulk Loader as well, from CSV or other formatted files.
g.V().has('location', 'geo_point',Geo.inside(Geo.point(2.352222,48.856614),50,Geo.Unit.KILOMETERS))results in:
==>Paris
g.V().has('location', 'geo_point', Geo.inside(Geo.point(2.352222,48.856614),50,Geo.Unit.KILOMETERS)). order(). by('name').as('Location'). in('lives_in').as('Author'). select('Location','Author'). by('name'). by('name')results in:
==>{Location=Paris, Author=Louisette BERTHOLIE}
==>{Location=Paris, Author=Simone BECK}
This
query uses some additional methods such as order()
and
select()
that are explained in Simple
Traversals.g.V().has('location', 'geo_point', Geo.inside(Geo.point(2.352222,48.856614),400,Geo.Unit.KILOMETERS)). order(). by('name').as('Location'). in('lives_in').as('Author'). select('Location','Author'). by('name'). by('name')results in:
==>{Location=Paris, Author=Louisette BERTHOLIE}
==>{Location=Aachen, Author=Fritz STREIFF}
==>{Location=Paris, Author=Simone BECK}
==>{Location=London, Author=Kelsie KERR}
Find celery at the store
You are a mathematics teacher writing a simple geospatial 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 stores to their house which have celery in stock.
g.V().hasLabel('store'). as('Store'). out('is_located_at'). has('geo_point', Geo.inside(Geo.point(37.8, -122.25), 5, Geo.Unit.MILES)). in().out(). has('name','celery'). as('Ingred'). select('Store', 'Ingred'). by('name'). by('name')results in:
==>{Store=Zippy Mart, Ingred=celery}
==>{Store=Mamma's Grocery, Ingred=celery}
Mary
has a choice of two markets to visit!g.V().hasLabel('store'). as('Store'). out('is_located_at'). has('geo_point', Geo.inside(Geo.point(37.8, -122.25), 5, Geo.Unit.MILES)). in().out(). has('name',within('celery','beef')). as('Ingred'). select('Store', 'Ingred'). by('name'). by('name')results in:
==>{Store=Zippy Mart, Ingred=beef}
==>{Store=Mamma's Grocery, Ingred=celery}
==>{Store=Zippy Mart, Ingred=celery
Looks
like Mary is headed to Zippy Mart where she can buy both of her ingredients.