2
votes

I have the following simple graph of time based IP->FQDN mappings.

enter image description here

I created this graph as follows

TitanManagement mgmt = graph.getManagementSystem();

VertexLabel ip = mgmt.makeVertexLabel("ip").make();
VertexLabel fqdn = mgmt.makeVertexLabel("fqdn").make();
EdgeLabel bind = mgmt.makeEdgeLabel("bind").make();
final PropertyKey name = mgmt.makePropertyKey("name").dataType(String.class).make();
TitanGraphIndex namei = mgmt.buildIndex("name", Vertex.class).addKey(name).unique().buildCompositeIndex();
mgmt.setConsistency(namei, ConsistencyModifier.LOCK);
final PropertyKey timestamp = mgmt.makePropertyKey("timestamp").dataType(Integer.class).make();
mgmt.buildEdgeIndex(bind, "bindByTime", Direction.BOTH, Order.DESC, timestamp);

mgmt.commit();

TitanTransaction tx = graph.newTransaction();

Vertex ip1 = tx.addVertexWithLabel("ip");
ip1.setProperty("name", "ip1");
Vertex ip2 = tx.addVertexWithLabel("ip");
ip2.setProperty("name", "ip2");
Vertex fqdn1 = tx.addVertexWithLabel("fqdn");
fqdn1.setProperty("name", "fqdn1");
Vertex fqdn2 = tx.addVertexWithLabel("fqdn");
fqdn2.setProperty("name", "fqdn2");
ip1.addEdge("bind", fqdn1).setProperty("timestamp", 1);
ip2.addEdge("bind", fqdn2).setProperty("timestamp", 2);
ip1.addEdge("bind", fqdn2).setProperty("timestamp", 3);

tx.commit();

I am now in the process of writing a query which finds the fqdn that an ip was bound to at a given time. Some examples follow

  • fqdnFor(ip="ip1", timestamp=1) == fqdn1
  • fqdnFor(ip="ip1", timestamp=2) == fqdn1
  • fqdnFor(ip="ip1", timestamp=3) == fqdn2
  • fqdnFor(ip="ip1", timestamp=4) == fqdn2

Here is the gremlin query I have written to compute this, I believe this is correct given for example (ip='ip1', t=4).

g.V.has('name', ip)
    .outE.has('timestamp', LESS_THAN_EQUAL, t)
    .order()
    .last()
    .inV()

My questions are now as follows.

  1. How would I modify this gremlin query to return not just the vertex but also the edge that lead to it.

  2. Is this query optimal given the indexes I have created? If I understand the bindByTime index correctly this query should be as efficient (take the same computation time) even if the graph depicted above contained for example a million bind edges (t1, t2, ... t1000000) outgoing from each ip (ip1, ip2).

  3. How would I execute this query from java instead of from the gremlin console? I was hoping to find something akin to JDBC PreparedStatement.

Something like the following sudo code.

PreparedGremlinQuery query = new PreparedGremlinQuery("V.has('name', :ip).outE.has('timestamp', LESS_THAN_EQUAL, :t).order().last().inV()");
query.put(1, "ip1");
query.put(2, 3);   
Result r = query.execute();
1

1 Answers

1
votes

The answer to Q1 seems to be use a combination of as and select.

g.V.has('name', 'ip1').outE.has('timestamp', LESS_THAN_EQUAL, 3).order().last().as('e').inV().as('v').select(['e', 'v'])

The answer to Q2 seems to be yes if I use orderBy() see quote from the Titan 0.5 docs below.

Mixed indexes support ordering natively and efficiently. However, the property key used in the orderBy method must have been previously added to the mixed indexed for native result ordering support. This is important in cases where the orderBy key is different from the query keys. If the property key is not part of the index, then sorting requires loading all results into memory.

However I cannot seem to use orderBy()

g.V.has('name', 'ip1').outE.has('timestamp', LESS_THAN_EQUAL, 3).orderBy('timestamp', Order.DESC).last().as('e').inV().as('v').select(['e', 'v'])

I get the following exception

No signature of method: com.tinkerpop.gremlin.groovy.GremlinGroovyPipeline.orderBy() is applicable for argument types: (java.lang.String, com.thinkaurelius.titan.core.Order) values: [timestamp, DESC] Possible solutions: order(), order(com.tinkerpop.gremlin.Tokens$T), order(com.tinkerpop.pipes.PipeFunction), order(com.tinkerpop.pipes.transform.TransformPipe$Order), order(groovy.lang.Closure), every()

The answer to Q3 seems to be no not really. Nothing on the following page seems to resemble PreparedStatement which is very readable and protects against query injection.

https://github.com/tinkerpop/gremlin/wiki/Using-Gremlin-through-Java