g.V() is usually used to start a traversal. But since this a startup action, why its begin node is a Vertex?
g is the TraversalSource, by specifying V() you're saying that you are going to start at a set of elements that are of type Vertex, just like by specifying E() would specify starting at a set of elements that are of type Edge http://tinkerpop.apache.org/docs/current/reference/#the-graph-process and http://tinkerpop.apache.org/docs/current/reference/#traversal are pretty clear on how traversals are built up.
Related
i want to write a gremlin script,like this:
g.V().out().as('a').[many code].as('b')
.where('a',eq('b').or(eq('a_constant_string'))).by('name')
but a_constant_string is a string constant ,not a vertex or edge
if writing like this,will thrown Exception:
org.apache.tinkerpop.gremlin.driver.exception.ResponseException: Neither the sideEffects, map, nor path has a a_constant_string-key
how to write
When you use where() that way you put the predicate eq() into a mode where it is dealing with labels only so you can't inject a constant in there. In this case, I'd think the easiest thing to do would be to move the "or" outside of the where():
g.V().
out().as('a').as('b').
or(where('a', eq('b')).by('name'),
has('name', 'a_constant_string'))
This query works:
choose(V().hasLabel("user"), V().hasLabel("user").drop())
But is searching 2 times for the vertex "user", I want to optimize it to 1 time, so I changed it for this one:
choose(V().hasLabel("user").fold(), unfold().drop())
If I do that trick multiple times in my query it throws:
Error: ResponseError: Server error: Vertex with id 70 was removed. (500)
I don't understand what that means, maybe fold() does not overwrite previous fold() calls, I don't know.
Is there an alternative to fold() unfold() for this use case? I've tried:
choose(V().hasLabel("user").as("u"), select("u").drop())
but that does not work, it seems .as() don't save anything when is called inside choose()
I also tried:
choose(V().hasLabel("user").store("u"), select("u").drop())
But throws another error I don't understand: The incoming object is not removable
Your first attempt with:
choose(V().hasLabel("user"), V().hasLabel("user").drop())
is not as expensive as you think. The if portion of choose() (i.e. the first child traversal) does not iterate all users. It immediately returns true if one "user" is found". Your then child traversal will iterate all "user" vertices. Also, you don't provide a false value to choose() so in that case, I believe that you will end up calling the drop() traversal for either situation:
gremlin> g.inject(1).choose(V().hasLabel('no-exist'),constant(1))
==>1
gremlin> g.inject(1).choose(V().hasLabel('no-exist'),constant(1),constant(2))
==>2
Of course, I'd wonder why you need to do an if/then here at all because calling V().hasLabel("user").drop() without choose() will remove all "user" vertices found, or if none are found, just do nothing.
For this traversal:
choose(V().hasLabel("user").fold(), unfold().drop())
note that V().hasLabel("user").fold() will always return "true" because you fold() which is a reducing step which will return a List of items in the stream. If the stream is empty you get an empty List and thus choose() will use the true path there. In any event, your unfold() is not unrolling what is returned from the first choose() parameter - it unfolds the same Traverser object handed to the choose() step. You don't have what comes before the choose() so I can't say what that is.
I'm not completely sure but based on your remaining traversal examples, I think you might be misusing choose() in general. You don't seem to have need for an if/then or switch style operation. With Gremlin you don't need to check if something is present in order to remove it and it is in fact cheaper not to do so as mentioned earlier.
I am extending sparql-to-gremlin code to support fully and partially unbound predicate queries that can be used by automated processes to explore the graph structure. The idea being that you could just connect to some graph DB and ask a fully unbound query with some limit and get vertex properties, edge types, edge properties, etc. That can then be explored more.
I can now solve a fully unbound query and can solve one that has the subject bound to a vertex. Now I am trying to put it together into a multi-literal query and finding that the Gremlin MATCH Step would need to reflect on the type of Traversal before it can decide which steps would actually apply. For example if, the Traversal results in a Vertex, asking for out/in edges and properties makes sense; if it’s an Edge though, asking for out/in edges does not make sense and actually results in errors about unexpected type being thrown.
Thus the question, is it possible to write a kind of “switch” statement that would reflect on the type and then only ask for things that makes sense in that context?
Here’s one type of SPARQL query that I am trying to support (based on the Graph of the Gods described here https://old-docs.janusgraph.org/0.1.0/getting-started.html):
https://old-docs.janusgraph.org/0.1.0/images/graph-of-the-gods-2.png
SELECT ?BATTLE ?PRED ?VALUE
WHERE {
vid:6 ep:battled ?BATTLE .
?BATTLE ?PRED ?VALUE .
}
Here we are starting from a vertex with id 6, grabbing the outgoing edge reference with “battled” label, then grabbing all possible properties of the edge along with their values.
Here vertex with id 6 is Hercules, which has 3 outgoing edges with label “battled” going to vertex with id 9 (Nemean), 10 (Hydra) and 11 (Cerberus). I would want to the have ?PRED be bound to v:id (edge id), v:label (edge label), v:time (edge time property value), v:place (edge place property value), eps:battled (an extension to sparql-to-gremlin relating edge to an IN vertex).
I think that I follow your problem and I don't think I have a good answer for you. At the moment, Gremlin isn't terribly good with type detection and the issue remains open on TINKERPOP-2234. The typical workaround for most people when they have a mixed set of elements in a stream is to use a step like coalesce() or choose() to act as a form of switch statement and then figure out some filter than can identify the object type. So here's some mixed results that I've contrived:
gremlin> g.V().union(outE(),__.in())
==>e[9][1-created->3]
==>e[7][1-knows->2]
==>e[8][1-knows->4]
==>v[1]
==>v[1]
==>v[4]
==>v[6]
==>e[10][4-created->5]
==>e[11][4-created->3]
==>v[1]
==>v[4]
==>e[12][6-created->3]
and then I test with hasLabel() for labels I know to belong to vertices only, then everything else must be an edge:
gremlin> g.V().union(outE(),__.in()).choose(hasLabel('person','software'), values('name'), values('weight'))
==>0.4
==>0.5
==>1.0
==>marko
==>marko
==>josh
==>peter
==>1.0
==>0.4
==>marko
==>josh
==>0.2
Not ideal obviously but it typically resolves most people's problems. Hopefully we will see TINKERPOP-2234 solved for 3.5.0.
Another possible workaround is to use a lambda which works well for some use cases though we try to avoid them when possible:
gremlin> g.V().union(outE(),__.in()).choose(filter{it.get() instanceof Vertex}, values('name'), values('weight'))
==>0.4
==>0.5
==>1.0
==>marko
==>marko
==>josh
==>peter
==>1.0
==>0.4
==>marko
==>josh
==>0.2
I'm working on a gremlin query that navigates along several edges and eventually produces a String. Depending on the graph content, this traversal may be empty. In case that the traversal ends up being empty, I want to return a default value instead.
Here's what I am currently doing:
GraphTraversal<?, ?> traversal = g.traversal().V().
// ... fairly complex navigation here...
// eventually, we arrive at the target vertex and use its name
.values("name")
// as we don't know if the target vertex is present, lets add a default
.union(
identity(), // if we found something we want to keep it
constant("") // empty string is our default
)
// to make sure that we do not use the default if we have a value...
.order().by(s -> ((String)s).length(), Order.decr)
.limit(1)
This query works, but it is fairly convoluted - all I want is a default if the traversal ends up not finding anything.
Does anybody have a better proposal? My only restriction is that it has to be done within gremlin itself, i.e. the result must be of type GraphTraversal.
You can probably use coalesce() in some way:
gremlin> g.V().has('person','name','marko').coalesce(has('person','age',29),constant('nope'))
==>v[1]
gremlin> g.V().has('person','name','marko').coalesce(has('person','age',231),constant('nope'))
==>nope
If you have more complex logic in mind for determining if something is found or not then consider choose() step.
Couldn't figure from the documentation and the source code what do they represent?
http://tinkerpop.apache.org/javadocs/3.2.5/full/org/apache/tinkerpop/gremlin/process/traversal/dsl/graph/DefaultGraphTraversal.html
In Apache TinkerPop/Gremlin a Traversal is analogous to a query and a query can return more than just vertices.
<S,E> are type variables that form the Java generic definition for the DefaultGraphTraversal class. They aren't specific classes, but represent the "start" (for S) and "end" (for E) types that will go into and come out of the traversal respectively. In a sense, those types become defined when you form the traversal you want to execute. g.V().count() returns a GraphTraversal<Vertex,Long> where the S is defined as Vertex and the E is defined as a Long - the start to the traversal is a Vertex and the end to the traversal is a Long.