Gremlin traversal referencing previous edges - gremlin

I have a fairly simple graph, with the caveat that all edges are marked with 'to' and 'from' dates stored as timestamps.
I'm trying to write a traversal that will only follow edges that overlap with the first traversed edge's To and From dates.
Note that the To-date can be non-existent, indicating that the edge is still active.
I've tried various things, but the closest I've come so far is:
g.V('1').outE().as('firstEdge')
.sideEffect(values('To').store('eTo'))
.sideEffect(values('From').store('eFrom'))
.outV()
.repeat(outE().where(
lte('firstEdge')).by('From') // The edge has a from-date less than firstEdge's from-date.
.and(
or(
hasNot('To'), // The edge is still active, OR
has('To', gte('eFrom')) // the edge has a to date after the firstEdge's from-date.
)
)
.and(
or(
select('firstEdge').hasNot('To'), // The first edge does not have a to-date, OR
has('From', lte('eTo')) // The edge has a from date that is less than the first edge's to-date.
)
)
.inV()
)
.emit()
.times(2) // Limit to two edges away.
.where(hasLabel('Person'))
I'm pretty sure the problem is related to the store commands and subsequent usage, as the following query does not return anything either (It should return any inactive edges created after the first edge).
g.V('1').outE('is_board')
.sideEffect(values('From').store('eFrom'))
.outV()
.repeat(outE().has('To', gte('eFrom')).inV())
.emit()
.times(2)
.where(hasLabel('Person'))

Related

Gremlin: How to obtain outgoing edges and their target vertices in a single query

Given a set of vertices (say, for simplicity, that I start with one: G.V().hasId("something")), I want to obtain all outgoing edges and their target vertices. I know that .out() will give me all target vertices, but without the information about the edges (which have properties on them, too). On the other hand, .outE() will give me the edges but not the target vertices. Can I obtain both in a single Gremlin query?
Gremlin is as much about transforming graph data as it is navigating graph data. Typically folks seem to understand the navigation first which got you to:
g.V().hasId("something").outE()
You then need to transform those edges into the result you want - one that includes the edge data and it's adjacent vertex. One way to do that is with project():
g.V().hasId("something").outE()
project('e','v').
by().
by(inV())
Each by()-modulator supplied to project() aligns to the keys supplied as arguments. The first applies to "e" and the second to "v". The first by() is empty and is effectively by(identity()) which returns the same argument given to it (i.e. the current edge in the stream).
Never mind. Figured this out.
G.V().hasId("something").outE().as("E").otherV().as("V").select("E", "V")

Add or update an edge in Gremlin

I have a graph database in Azure CosmoDB that stores how similar vertices are and the edge contains the numeric value of how similar they are.
The complication is that I want to add an edge or update by incrementing the similarity value. This is the current code I have for adding:
g.V('A').addE('similar').to(g.V('B')).property('x', 10)
I need something that will increase X if the edge exists, or create it if not. Pseudo code exemplifying it:
g.V('A').updateE('similar').to(g.V('B')).property('x', currentValue+2).ifNulll({g.V('A').addE('similar').to(g.V('B')).property('x', 10)})
is there an easy way to achieve this ?
There is a known recipe for checking existence by using the pattern fold().coalesce(unfold()...) for vertex and similar pattern for edge. In your case, you want to update a property value as well.
Assuming there are vertices with IDs A and B, and edge goes from A-->B, the query might look like this:
g.withSack(0).V('B').as('toV').V('A').coalesce(
outE('similar').where(inV().as('toV')),
addE('similar').to('toV').property('similarity', 0)
)
.sack(assign).by('similarity').sack(sum).by(constant(2))
.property('similarity', sack())
Explanation:
Get B (target) vertex and save reference, get A (source) vertex.
Using coalesce, check if there is an edge connecting them, otherwise create such edge and set similarity to 0.
Assign the 'similarity' value to the sack, and sum the additional value.
Last, store the new value on the edge property.
Another query without using sack:
g.V('B').as('toV').V('A').coalesce(
outE('similar').where(inV().as('toV')),
addE('similar').to('toV').property('similarity', 0)
).property('similarity', values('similarity').fold(10, sum))

Following edges who's properties match one on the source vertex with Gremlin

I have a graph, and I want to follow the edges that contain a property that matches one on the vertex. E.g.
vertex -------edge ---------> vertex
vertValue: 123 vert: 123 vertValue: 463
So in the above case, say I'm starting at the first vertex, I want to follow the edges that has the property 'vert' equal to it's 'vertValue'.
I've manage to make a query using where that manages to follow the edge:
g.V(id).as('verts')
.outE().values('vert')
.where(eq('verts'))
.by('vertValue')
Problem, is I want to return the actual edge object. However, as I need to do the 'where' on the 'vert' value of the edge, in the query I'm doing a values('vert') so the result I get is just the value I'm testing, not the edge object. I want to do something like:
g.V(id).as('verts')
.outE()
.where(eq('verts'))
.by('vertValue','vert')
To compare the 'vertValue' on the vertex, to the 'vert' value on the edge. But I can't seem to find a way to specify by on the 'input' values of the where.
Edit: Trying:
g.V("95c4a57a-9262-45b7-a905-8cca95d3ebb6").as('v').
outE().
where(eq('v')).
by('vert').
by('vertValue')
Returns an error:
Gremlin Query Execution Error: Select One: Get Projection: The provided traversal or property name of path() does not map to a value.
g.V("95c4a57a-9262-45b7-a905-8cca95d3ebb6").as('v').
outE().
where(eq('v')).
by('vertValue').
by('vert')
returns an empty array!
You got really close to the solution. It's:
g.V(id).as('v').
outE().
where(eq('v')).
by('vert').
by('vertValue')

Calculate all end points on a graph given n stamina?

I am attempting to create a pathfinding algorithm for a game. Basically, after the player rolls a number, I need to determine all possible locations that the player can end up on a grid. The player cannot move directly backwards after a given step, and the player can only move one grid square per step.
The problem is, right now I am attempting to brute force the solution by recursively navigating along the graph and manually checking each valid move.
Pseudocode:
// Recursive function for navigating one step at a time.
function navigate($stamina, $coords, $coords_previous)
{
// If the movement stamina has not been spent.
if ($stamina != 0)
{
// Note: there may be less than four neighboring
// cells in a given location due to obstacles.
foreach ($neighboring_cells as $coords_neighboring)
{
// If the coordinates of the neighbor are not the same as the
// coordinates of the previous move (we can't move backwards)
if ($coords_neighboring != $coords_previous)
{
$stamina--;
// Recurse.
navigate($stamina, $coords_neighboring, $coords);
}
}
}
else
{
// No more stamina.
// Add $coords to our array of endpoints.
}
}
This works for small rolls (low $stamina values). However, as $stamina increases, this methodology starts to become super redundant. This is due to the fact that the player can move in circles over and over again, exponentially increasing the number of potential endpoints.
My question is, what can be done to decrease redundancy in the above function?
Define a state as a combination of a grid position and a facing (i.e., the direction the player moved in to get there). This is useful because we can define successors of a given state: in particular, those at adjacent grid positions (with appropriate facings) other than the one the player just came from.
Then compute the set of states reachable in n steps. For n=0, this is just the player's initial position (with a special "no facing" value if the first move can be in any direction). To compute it for n+1, generate all valid moves from each of the states in the previous set, discarding any duplicates. When you reach the set for $stamina steps, just discard the facings (and any duplicate positions).
In terms of graph algorithms
This is similar to a breadth-first search on a graph whose vertices are the states and whose edges connect a state to its successor states. However, here we don't disregard new (longer) paths to a state, since some positions might be reachable (in exactly $stamina steps!) only via looping back. One could also include the remaining stamina in the state (and define no edges away from a state with 0 moves left); then you would perform a normal graph search and collect all the leaves.
In either case these would probably be implicit graphs, but the algorithm is clearer implemented directly rather than in terms of a graph.

How to get all Graph Nodes in ArangoDB without Start-Node

Like in OrientDB, for get the All Graph Only use 'Select From v'
So far, I have use AQL in ArangoDB with start node:
for v,e,p IN 2 ANY 'user/188802' graph 'a' return p
And now I want to get all graph nodes in ArangoDB without the start node?
Graphs are a grouping of Edge collections. Each Edge collection references _from and _to documents which are stored in Document collections.
The graph traversal queries expect you to have a starting position and it returns the results for that single starting position.
It is possible to identify all possible starting positions, and then run graph traversals over those positions.
You'll need to know the names of the document collections that make up your graph, you can insert them into an AQL query like this:
FOR vertex IN UNION(
(FOR v IN document_collection_1 RETURN v._id),
(FOR v IN document_collection_2 RETURN v._id),
(FOR v IN document_collection_3 RETURN v._id)
)
FOR v, e IN 1..5 OUTBOUND vertex GRAPH 'my_graph_name' OPTIONS { uniqueVertices: true }
RETURN DISTINCT [
{
_from: e._from,
_to: e._to
}
]
Remember that in ArangoDB it is possible for a document collection to be bound to more than one graph, so you'll need to ensure you identify all document collections that are part of the graph.
This query will then extract an array of objects that contain all links defined in the graph. This query focuses only on vertices with edges that are part of the graph. If the vertex has no edge on it, it won't appear in the output as it is not part of the graph.

Resources