I have a graph structure like this-
Node1(Console) <----Uses--- Node2(Name, Age) -----plays----> Node3(Game)
So, i have three nodes -
Node1 is console like a PS3/ Nintendo.
Node2 is a person with properties name and Age.
Node3 is game node which holds game name like 'warcraft'.
Now I want to have a gremlin query which tells me that.
How many users (Node2) who has the console like PS3, plays a game like 'warcraft'
I think i need to start the traverse from Node2 , filter it based on Node1 property i.e console as as 'PS3' and plays game like 'warcraft'
I am new to gremlin and using some thing like this -
g.V().hasLabel('user').outE('uses').inV().has('console', 'ps3').count()
the above query only answers half of my required result. How do i filter Node2 based on plays relationship as well.
Any help is appreciated.
There are multiple ways to write the query.
Option 1: Start from console
g.V().has('console', 'ps3').in('uses').where(out('plays').has('game', 'warcraft')).valueMap('name')
Let me explain the structure here:
g.V().has('console', 'ps3') --> Select all vertices which have a property with key as console and value as ps3
in('uses') --> From the set of previous vertices, jump to incoming vertices via an edge that has the label uses. At this stage, we would have player vertices in our solution.
where(out('plays').has('game', 'warcraft')) --> Apply a filter on existing solutions. Since we are using where we would not jump/traverse to the next step of vertices.
valueMap('name') --> Project one or more properties if existing solutions which are player vertices.
Option 2: Another way to write above query
g.V().has('console', 'ps3').in('uses').as('myusers').out('plays').has('game', 'warcraft').select('myusers').by('name')
as('myusers') --> Provides a reference/alias to the vertices at this stage. Note that it does not store all the results at this stage instead it just provides a reference to the type of vertices at this point in the query.
out('plays').has('game', 'warcraft') --> Unlike previous time when we did not jump since we were using where, this time we jump onto the game vertices.
select('myusers').by('name') --> since we want to project the users but the current solutions are game vertices, we need to select the user vertices which we do using the reference we stored earlier.
Option 3: Start from user
g.V().hasLabel('user').where(out('plays').has('game','warcraft')).where(out('uses').has('console','ps3')).valueMap('name')
There are more ways to write this query such as using path() but I won't go into details here.
Since you are beginning to learn Gremlin, I would recommend that you start with https://kelvinlawrence.net/book/Gremlin-Graph-Guide.html
Related
I have person vertex, has_vehicle edge and vehicle vertex which models vehicle ownership use case. The graph path is person -> has_vehicle -> vehicle.
I want to implement a Gremlin query which associates a vehicle to a person only if
The person does not have a vehicle
AND
The input vehicle is not associated with a person yet.
I followed the fold-coalesce-unfold pattern and came out with following Gremlin query with nested coalesce
g.V().hasLabel('person').has('name', 'Tom').as('Tom').outE('has_vehicle').fold().coalesce(
__.unfold(), // check if Tom already have a vehicle
g.V().has('vehicle', 123).as('Vehicle').inE('has_vehicle').fold().coalesce(
__.unfold(), // check if vehicle 123 is already associated with a person
__.addE('has_vehicle').from('Tom').to('Vehicle') // associate the vehicle to Tom
)
)
Is there a way to eliminate the nested coalesce? If I have multiple criteria, it would be too complex to write the query.
This might be a case where a couple of where(not(...)) patterns, rather than nesting coalesce steps works well. For example, we might change the query as shown below.
g.V().hasLabel('person').has('name', 'Tom').as('Tom').
where(not(outE('has_vehicle'))).
V().has('vehicle', 123).as('Vehicle').
where(not(inE('has_vehicle'))).
addE('has_vehicle').from('Tom').to('Vehicle')
So long as the V steps do not fan out and yield multiple Tom or Vehicle nodes that should work and is easy to extend by adding more to the where filters as needed.
As as a side note, the not steps used above should work even if not wrapped by where steps, but I tend to find it just reads better as written.
This rewrite does make an assumption that you are able to tolerate the case where Tom already has a car and the query just ends there. In that case no vertex or edge will be returned. If you did a toList to run the query you would get an empty list back in that case however to indicate nothing was done.
here is my problem:
I've got a graph where I have :Item with one relationship :CRAFTED_WITH to one :RECIPE and those :RECIPEhave one or more relationship :COMPOSED_OF{quantity} to ingredients that are :Item.
As you can imagine you can have several level of relationship to get from a high tier :Item to the most basic of components.
I want to be able to find all nodes that are reachable from a specific node while following only one direction. That part was easy I used the apoc procedure apoc.path.subgraphAll.
But now my next step is to have the result display as a tree and not a graph. In a graph I will ended up with multiple :Item on the receiving end of :COMPOSED_OF relationship. I want :Item to be "duplicated" so they are linked by a single :COMPOSED_OF relationship.
Is it even feasible only in cypher ? Or will I have to use another language to handle a graph to turn it into that "tree" structure ?
There is an apoc function to do that. The cypher below illustrates what is does.
MATCH treePath=(root:Thing)-[:CHILD*0..]->(leaf:Thing)
WHERE NOT (leaf)-[:CHILD]->()
AND NOT ()-[:CHILD]->(root)
WITH COLLECT(treePath) AS treePaths
CALL apoc.convert.toTree(treePaths) yield value AS tree
RETURN tree
I'm new to the Janusgraph Database. I have a requirement where I need to hide the relation (edge) between two vertices without dropping them and later I should able retrieve / establish the same relation again between those vertices based on condition.
I only know how to drop the edges but I don't know how to retrieve/restore the relation again. Could you please help me out here.
Thanks a lot for your time.
If you want to 'restore' the connections I think you shouldn't drop them at all.
Just keep a property on the edge that indicates the edge state (active/inactive) or maybe keep a start and end date on the edge.
This way when you traverse your graph you need to makes sure to use only the active edges, but the old ones can still easily found if you want to restore them.
for example:
g.addV('person').property('id', 'bob').property('name', 'Bob')
g.addV('person').property('id', 'alice').property('name', 'Alice')
g.addV('person').property('id', 'eve').property('name', 'Eve')
g.V('bob').addE('friend').to(g.V('alice'))
g.V('bob').addE('friend').to(g.V('eve'))
So Bob friends with Alice and Eve:
g.V('bob').out('friend').values("name")
==>Alice
==>Eve
Let say Bob and Alice had a fallout, and they are no longer friends:
g.V('bob').outE('friend').where(inV().hasId('alice')).property('status', 'inactive')
now you can query only Bob active friends, without dropping the old edges:
g.V('bob').outE('friend').not(has('status', 'inactive')).inV().values("name")
==> Eve
i have a following graph in neo4j graph database and by using the cypher query language, i want to retrieve the whole data with is connected to root node and their child node.
For example :
kindly find the below graph image.
[As per the image, node 1 has two child and their child also have too many child with the same relationship. now what i want, using Cypher, i hit the node 1 and it should response with the whole data of child node and there child node and so on, relationship between nodes are "Parent_of" relationship.]
can anyone help me on this.
start n=node(1) // use the id, or find it using an index
match n-[:parent_of*0..]->m
return m
will get you all the graph nodes in m. You could also take m.some_property instead of m if you don't want the node itself, but some property that is stored in your nodes.
Careful though, as the path has no limit, this query could become pretty huge in a large graph.
You can see an example of *0.. here: http://gist.neo4j.org/?6608600
When looking at the Tinkerpop-Blueprints API it is quite straight forward to use one type of vertices but how can I store two? E.g. Users and their interests?
And how can I get a Vertex by id? I mean, there could be a user named 'timetabling' as well as the interests 'timetabling' - how to handle that id conflict?
-
I know that the first problem could be solved via introducing an index for a type-property and for the second problem I could auto generate the id and create another index for the name-property. BUT why would I then need the vertex id at all? E.g. for the in-memory there is a HashMap for all vertices which would be of no use and wasting memory! (I could solve the problem differently via combining type and name as the id but then it would inefficient if I e.g. list all users.)
Hmmh, ok. I'm just using the vertices for the combined id (name+type) and a separate index for type. Better solutions?
In general it is best to rely on the automatic ID system of the underlying graph database (e.g. Neo4j, InfiniteGraph, OrientDB, etc.). The way in which you would add the information you want is as follows:
Vertex v = graph.addVertex(null)
v.setProperty("name","timetabling")
Vertex marko = graph.addVertex(null)
graph.addEdge(null, marko, v, "hasInterest")
Verte aType = graph.addVertex(null)
graph.addEdge(null, aType, v, "hasType")
In short, the ID of a vertex/edge is a non-domain-specific way of retrieving vertices/edges. Generally, it is best to use properties in your domain model for indexing.
Hope that speaks to your question,
Marko.
http://markorodriguez.com