Search code examples
gremlintinkerpoptinkerpop3gremlin-server

Gremlin: How can I use math() to filter traversal results?


I'm trying to use the number result of math() to filter the traversal results, but I get errors I don't understand. All the examples of the math() step I see online are queries that just returns the number result but none of them do something with it.

This is what I have:

g.V()
.hasLabel("user")
.values("targetDistance")
.is(
    lte(math(`abs(_ - ${searcherUser.locationLat}) * ${GPS_TO_KM}`).by("locationLat"))
)

This is an example of the error I get (I don't understand this type error):

"Cannot compare '51' (Integer) and '[MathStep(abs(_ - 5),[value(locationLat)])]' (DefaultGraphTraversal) as both need to be an instance of Number or Comparable (and of the same type)""

What I want to do:

It's a feature to get the nearby users according to a setting configured: the targetDistance value (in km). But also I want to exclude the users that are too far according to thier own targetDistance. In other words: If one of the users consider the other to be too far they should not be visible to each other.

I have the first part working (finding the close ones to the searcher user):

   /**
    * Is inside the distance range the user wants
    */
   traversal = traversal.has(
      "locationLat",
      P.inside(
         searcherUser.locationLat - searcherUser.targetDistance * KM_TO_GPS,
         searcherUser.locationLat + searcherUser.targetDistance * KM_TO_GPS,
      ),
   );

   traversal = traversal.has(
      "locationLon",
      P.inside(
         searcherUser.locationLon - searcherUser.targetDistance * KM_TO_GPS,
         searcherUser.locationLon + searcherUser.targetDistance * KM_TO_GPS,
      ),
   );

Solution

  • A predicate like lte cannot take a traversal as an argument. You need to reformulate the query a little to something like:

    g.V().
      hasLabel('user').as('a').
      where(lte('a')).
         by('targetDistance').
         by(math(…..))
    

    EDITED to add ...

    By way of a concrete example, using the air-routes data set we might do:

    gremlin>   g.V().
    ......1>   hasLabel('airport').as('a').
    ......2>   where(gte('a')).
    ......3>      by('runways').
    ......4>      by(math('3+3')).
    ......5>   valueMap('city','code','runways')
    
    ==>[code:[BOS],city:[Boston],runways:[6]]
    ==>[code:[DFW],city:[Dallas],runways:[7]]
    ==>[code:[ORD],city:[Chicago],runways:[7]]
    ==>[code:[DEN],city:[Denver],runways:[6]]
    ==>[code:[DTW],city:[Detroit],runways:[6]]
    ==>[code:[AMS],city:[Amsterdam],runways:[6]] 
    

    .