Odysseus has built-in features in the spatial package with which spatio-temporal and especially moving objects data can be processed. Here we describe how to use these features and give a few example scenarios.
Starting Odysseus Spatial
Accessing Example Data
For this example, we use vessel AIS data from the San Francisco bay, which is provided by ais.exploratorium.edu (you can open this in a browser and see the raw AIS data). You use this query to access the data. Just create a new Odysseus Script file within Odysseus Studio and run this query (with the "green arrow down"-button). The query does access the raw AIS data, converts it into key-value objects, filters some data, converts it to a tuple and finally uses latitude and longitude data to create an geo-object. The latter can be used by Odysseus for spatial functionality. If you want to see the data, do the following: after running the query, you should see "System.SanFranciscoAIS" in the Sources-view. Right click and choose "Query source" to view the data.
#PARSER PQL #RUNQUERY /// Access the data from San Francisco input = ACCESS({ source='SanFranciscoAIS', wrapper='GenericPush', transport='TCPClient', protocol='NMEA', datahandler='keyValueObject', options=[ ['host', 'ais.exploratorium.edu'], ['port', '80'] ] } ) /// Filter the AIS messages to those from vessels vesselsOnly = SELECT({ predicate = 'isNull(rateOfTurn) = false' }, input ) /// Convert the key-value object to a tuple tuple = TOTUPLE({ schema = [ ['rateOfTurn','Integer'], ['navigationStatus','String'], ['maneuverIndicator','String'], ['trueHeading','Integer'], ['positionAccurate','Boolean'], ['latitude','Double'], ['courseOverGround','Double'], ['speedOverGround','Double'], ['sourceMmsi','Integer'], ['longitude','Double'], ['second','Integer'], ['raimFlag','Boolean'] ] }, vesselsOnly ) /// Create a geoObject from lat/lng SanFranciscoAIS := MAP({ expressions = [ ['FromWKT("POINT (" + toString(latitude) + " " + toString(longitude) + ") ")', 'SpatialPoint'] ], keepinput = true, removeattributes = ['latitude','longitude'], name = 'geo_object' }, tuple )
A message you receive could look similar to the following:
{"rateOfTurn":0,"navigationStatus":"UnderwayUsingEngine","maneuverIndicator":"NotAvailable","trueHeading":274,"positionAccurate":false,"latitude":37.56334666666667,"courseOverGround":272.3,"speedOverGround":13.4,"sourceMmsi":367134000,"longitude":-123.107605,"second":18,"raimFlag":false};1488537437230|oo
Filling a Spatio-Temporal Index
This data can now be used to fill a spatio-temporal index for moving objects. To do this, create another Odysseus Script file and run the following query.
#PARSER PQL /// The index structure #DEFINE dataStructureName 'sanFranciscoStore' #DEFINE dataStructureType 'mo_geohash' #RUNQUERY /// Store the data in an index structure movingObjectIndex = MOVINGOBJECTSTORE({ /// distance of the trajectory in meters that we keep for every moving object distancepermo = 100.0, geometryattribute = 'SpatialPoint', datastructurename = ${dataStructureName}, idattribute = 'sourceMmsi', datastructuretype = ${dataStructureType} }, System.SanFranciscoAIS )
Running a Range-Query on the Index
Now we can use this index to run a continuous range query for the vessels. We could reduce the number of vessels where we do the
#PARSER PQL #DEFINE dataStructureName 'sanFranciscoStore' #ADDQUERY /// For every vessel we want to know which vessels are near them all the time range = MOVINGOBJECTRANGE({ geometryattribute = 'SpatialPoint', datastructurename = ${dataStructureName}, range = 300 }, System.SanFranciscoAIS )
Show data on a map
Future Work
The work on this topic is not finished. Here list of things that we want to add in future releases.
- Providing a web-based map view to visualize the queries, e.g. with Spring Boot + Leaflet (or OpenLayers). Can be a bit inspired by the demonstration visualization by Tile38 (e.g. http://tile38.com/ or https://roam.sh/)
- Adding interpolation functionality to calculate in-between-measurements locations and near-future locations