Modelling Military Grid Reference System

We are in process of trying out Neo4j to see how it fits our product.

As newbie to Neo4j, one thing has caused some questions which is why I would like to ask help from smarter people!

The use case is following: node (vehicle, event) can have a location that is in MGRS format. So for example, a Land Rover Defender has location of 35V LF 72593 90864 (1m precision). You can read about the format here - https://en.wikipedia.org/wiki/Military_Grid_Reference_System

Now, how do we present this with graph model?

The simple answer would be to add property for node. However, we have a use case where we have to find all other vehicles within 100m from Land Rover.

If we could use time-tree like graph, then the graph would look like this:

CREATE (root:LocationRoot),
       (gzd:GridZoneDesignator{designator: '4Q'}),                          // Grid zone designator
       (msq:MeterSquareIdentifier{identifier: 'FJ'}),                       // 100,000 meter square identifier
       (precisionLevelOne:PrecisionLevelOne{easting: 1, northing: 6}),      // Precision level 10 km
       (precisionLevelTwo:PrecisionLevelTwo{easting: 2, northing: 7}),      // Precision level 1 km
       (precisionLevelThree:PrecisionLevelThree{easting: 3, northing: 8}),  // Precision level 100 m
       (precisionLevelFour:PrecisionLevelFour{easting: 4, northing: 9}),    // Precision level 10 m
       (precisionLevelFive:PrecisionLevelFive{easting: 5, northing: 0}),    // Precision level 1 m

       // Relationships
       (root)-[:FIRST]->(gzd),
       (root)-[:LAST]->(gzd),
       (root)-[:CHILD]->(gzd),

       (gzd)-[:FIRST]->(msq),
       (gzd)-[:LAST]->(msq),
       (gzd)-[:CHILD]->(msq),

       (msq)-[:FIRST]->(precisionLevelOne),
       (msq)-[:LAST]->(precisionLevelOne),
       (msq)-[:CHILD]->(precisionLevelOne),

       (precisionLevelOne)-[:FIRST]->(precisionLevelTwo),
       (precisionLevelOne)-[:LAST]->(precisionLevelTwo),
       (precisionLevelOne)-[:CHILD]->(precisionLevelTwo),
       
       (precisionLevelTwo)-[:FIRST]->(precisionLevelThree),
       (precisionLevelTwo)-[:LAST]->(precisionLevelThree),
       (precisionLevelTwo)-[:CHILD]->(precisionLevelThree),

       (precisionLevelThree)-[:FIRST]->(precisionLevelFour),
       (precisionLevelThree)-[:LAST]->(precisionLevelFour),
       (precisionLevelThree)-[:CHILD]->(precisionLevelFour),

       (precisionLevelFour)-[:FIRST]->(precisionLevelFive),
       (precisionLevelFour)-[:LAST]->(precisionLevelFive),
       (precisionLevelFour)-[:CHILD]->(precisionLevelFive);

Or if the create nodes for both easting and northing:

CREATE (root:LocationRoot),
       (gzd:GridZoneDesignator{designator: '35V'}),                                 // Grid zone designator
       (msq:MeterSquareIdentifier{identifier: 'LF'}),                               // 100,000 meter square identifier

       (eastingPrecisionLevelOne:EastingPrecisionLevelOne{easting: 7}),             // Precision level 10 km
       (northingPrecisionLevelOne:NorthingPrecisionLevelOne{northing: 9}),            

       (eastingPrecisionLevelTwo:EastingPrecisionLevelTwo{easting: 2}),             // Precision level 1 km
       (northingPrecisionLevelTwo:NorthingPrecisionLevelTwo{northing: 0}),            

       (eastingPrecisionLevelThree:EastingPrecisionLevelThree{easting: 5}),         // Precision level 100 m
       (northingPrecisionLevelThree:NorthingPrecisionLevelThree{northing: 8}),            

       (eastingPrecisionLevelFour:EastingPrecisionLevelFour{easting: 9}),           // Precision level 10 m
       (northingPrecisionLevelFour:NorthingPrecisionLevelFour{northing: 6}),            

       (eastingPrecisionLevelFive:EastingPrecisionLevelFive{easting: 3}),           // Precision level 1 m
       (northingPrecisionLevelFive:NorthingPrecisionLevelFive{northing: 4}),            

       // Relationships
       (root)-[:FIRST]->(gzd),
       (root)-[:LAST]->(gzd),
       (root)-[:CHILD]->(gzd),

       (gzd)-[:FIRST]->(msq),
       (gzd)-[:LAST]->(msq),
       (gzd)-[:CHILD]->(msq),

       (msq)-[:FIRST]->(eastingPrecisionLevelOne),
       (msq)-[:FIRST]->(northingPrecisionLevelOne),
       (msq)-[:LAST]->(eastingPrecisionLevelOne),
       (msq)-[:LAST]->(northingPrecisionLevelOne),
       (msq)-[:CHILD]->(eastingPrecisionLevelOne),
       (msq)-[:CHILD]->(northingPrecisionLevelOne),

       (eastingPrecisionLevelOne)-[:FIRST]->(eastingPrecisionLevelTwo),
       (northingPrecisionLevelOne)-[:FIRST]->(northingPrecisionLevelTwo),
       (eastingPrecisionLevelOne)-[:LAST]->(eastingPrecisionLevelTwo),
       (northingPrecisionLevelOne)-[:LAST]->(northingPrecisionLevelTwo),
       (eastingPrecisionLevelOne)-[:CHILD]->(eastingPrecisionLevelTwo),
       (northingPrecisionLevelOne)-[:CHILD]->(northingPrecisionLevelTwo),

       (eastingPrecisionLevelTwo)-[:FIRST]->(eastingPrecisionLevelThree),
       (northingPrecisionLevelTwo)-[:FIRST]->(northingPrecisionLevelThree),
       (eastingPrecisionLevelTwo)-[:LAST]->(eastingPrecisionLevelThree),
       (northingPrecisionLevelTwo)-[:LAST]->(northingPrecisionLevelThree),
       (eastingPrecisionLevelTwo)-[:CHILD]->(eastingPrecisionLevelThree),
       (northingPrecisionLevelTwo)-[:CHILD]->(northingPrecisionLevelThree),

       (eastingPrecisionLevelThree)-[:FIRST]->(eastingPrecisionLevelFour),
       (northingPrecisionLevelThree)-[:FIRST]->(northingPrecisionLevelFour),
       (eastingPrecisionLevelThree)-[:LAST]->(eastingPrecisionLevelFour),
       (northingPrecisionLevelThree)-[:LAST]->(northingPrecisionLevelFour),
       (eastingPrecisionLevelThree)-[:CHILD]->(eastingPrecisionLevelFour),
       (northingPrecisionLevelThree)-[:CHILD]->(northingPrecisionLevelFour),

       (eastingPrecisionLevelFour)-[:FIRST]->(eastingPrecisionLevelFive),
       (northingPrecisionLevelFour)-[:FIRST]->(northingPrecisionLevelFive),
       (eastingPrecisionLevelFour)-[:LAST]->(eastingPrecisionLevelFive),
       (northingPrecisionLevelFour)-[:LAST]->(northingPrecisionLevelFive),
       (eastingPrecisionLevelFour)-[:CHILD]->(eastingPrecisionLevelFive),
       (northingPrecisionLevelFour)-[:CHILD]->(northingPrecisionLevelFive);

Then finding vehicles 100m from somewhere would be a matter of traversing the graph.

However, is there simpler solution to this as I feel I am over-engineering simple things...

One idea would be to use Point type, but how accurate is the distance calculation? Can it find with 1m precision?

We have also a use case where a user draws a box on the map and we have to find all vehicles in that area. Are there methods for doing this when using Point?

Hope somebody can share some knowledge on these matters.

Hi @genert,

Point can be used and there-s a library that already helps you with spatial queries in Neo4j (https://github.com/neo4j-contrib/spatial-algorithms). The only small detail is that coordinates should be expressed in WGS 84. Is there any way you can translate them? You can still keep the location in MGRS as a property if you eventually need to give it back in that format but you will need that extra property in WGS84 (https://neo4j.com/docs/cypher-manual/current/syntax/spatial/?_ga=2.251257222.1625359187.1597663660-80783348.1585564639).

Have a nice day!

Harold

1 Like