I'm new in Graph databases, and i can't resolve problem listed below.
How i can implement OrientDb query like
TRAVERSE OUT() FROM (SELECT FROM SomeClassThatExtendsV WHERE name = 'SomeUsefulName')
If i will execute this query via OrientDb java api :
new OSQLSynchQuery<Vertex>("TRAVERSE OUT() FROM (SELECT FROM SomeClassThatExtendsV WHERE name = 'SomeUsefulName')");
The result will be all child verticies with child and child and so on.
I need to implement same logic using gremlin api, that's what i have:
GraphQuery query = framedGraph.getBaseGraph().query().has("#class", "SomeClassThatExtendsV").has("name", "SomeUsefulName");
OrientVertex vertex = (OrientVertex) query.vertices().iterator().next();
Tree tree = new Tree();
new GremlinPipeline(vertex).out().tree(tree).loop("TestLoop", loopBundle -> false).iterate();
Iterator it = tree.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
System.out.println(pair.getKey() + " = " + pair.getValue());
}
As result i have NullPointerException.
java.lang.NullPointerException
at com.tinkerpop.pipes.branch.LoopPipe.getLoops(LoopPipe.java:75)
at com.tinkerpop.pipes.branch.LoopPipe.processNextStart(LoopPipe.java:49)
at com.tinkerpop.pipes.AbstractPipe.next(AbstractPipe.java:89)
at com.tinkerpop.pipes.util.Pipeline.next(Pipeline.java:115)
at com.tinkerpop.pipes.util.PipeHelper.iterate(PipeHelper.java:35)
at com.tinkerpop.gremlin.java.GremlinPipeline.iterate(GremlinPipeline.java:1542)
Maybe i'm doing something wrong in when in GremlinPipeline?
At this point i don't know full graph structure and i need to get something like tree, or something like result in OrientDb studio.
Some update here, i tried to use loop but as i told before i can't setup count of loops and due to this my test application stuck because in some vertices i have in edge and out edge.
Could somebody help me with this problem?
Related
I need to create a mongotemplate database query to get a specific number of elements into a list.
At the moment I just get all the elements with findAll(), and then I modify the obtained data using code that I have writen within the service class.
Initially, I have a Laptop class with fields price::BigDecimal and name::String and I use findAll() to get a list of them.
Then I put those in a HashMap, where key is the name field, sorted from most expensive to cheapest.
Map<String, List<Laptop>> laptopsMap = laptopsFrom.stream()
.collect(Collectors.groupingBy(Laptop::getName,
Collectors.collectingAndThen(Collectors.toList(),
l -> l.stream()
.sorted(Comparator.comparing(Laptop::getPrice).reversed())
.collect(Collectors.toList())
))
);
So the results are like below:
[{"MSI", [2200, 1100, 900]},
{"HP", [3200, 900, 800]},
{"Dell", [2500, 2000, 700]}]
Then, I use the code in the bottom of the question, to create a Laptop list with the following contents:
[{"HP", 3200}, {"Dell", 2500}, {"MSI", 2200},
{"Dell", 2000}, {"MSI", 1100}, {"HP", 900},
{"MSI", 900}, {"HP", 800}, {"Dell", 700}]
So basically, I iterate the map and from each key, I extract the next in line element of the list.
do {
for (Map.Entry<String, List<Laptop>> entry :
laptopsMap.entrySet()) {
String key = entry.getKey();
List<Laptop> value = entry.getValue();
finalResultsList.add(value.get(0));
value.remove(0);
if (value.size() == 0) {
laptopsMap.entrySet()
.removeIf(pr -> pr.getKey().equals(key));
} else {
laptopsMap.replace(key, value);
}
}
} while(!laptopsMap.isEmpty());
I instead of all this in-class code need to use a mongoTemplate database argument, but I cant seem to figure out how to create such a complex query. I have read material about Aggregation but I have not found anything helpful enough. At the moment, I have started putting a query together as shown below:
Query query = new Query();
query.limit(numOfLaptops);
query.addCriteria(Criteria.where(Laptop.PRICE).gte(minPrice));
I have the following code:
Vertex v = g.addV().property("valueStr", "3").next();
Vertex v2 = g.addV().property("valueStr", "4").next();
Vertex v3 = g.addV().property("valueStr", "5").next();
Edge e = g.V(v.id()).as("a").V(v2.id()).as("b").addE("anEdge").from("a").to("b").property("value", "4").as("e").next();
Edge e2 = g.V(v.id()).as("a").V(v3.id()).as("b").addE("anEdge").from("a").to("b").property("value", "5").as("e").next();
List vertices1 = g.V().match(
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v2.id()).as("b"),
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v3.id()).as("c")).toList();
System.out.println(vertices1);
List vertices2 = g.V().match(
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v2.id()).as("b"),
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v3.id()).as("c")).select("a","b").toList();
System.out.println(vertices2);
List vertices3 = g.V().match(
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v2.id()).as("b"),
__.as("a").hasId(v.id()).outE("anEdge").inV().hasId(v3.id()).as("c")).select("a").toList();
System.out.println(vertices3);
It is basically node a connecting to b, and node a connecting to c.
I am doing a match query over this subgraph and each time I return a subset of the elements that were matched..
Here are the outputs:
[{a=v[20], b=v[22], c=v[24]}]
[{a=v[20], b=v[22]}]
[v[20]]
In the first two cases I get a List of Maps.. In the last case I get a List.
How is it possible for the last case to make it also a List of Maps or [{a=v[20}]? I know I can do a hack with select("a","a") but it seems there should be a cleaner way.
Where does the documentation explain in which cases I will be getting a List of Vertices/Edges, a Map or a List of Maps etc?
Thanks!
In place of select("a") use project("a").by(select("a"))
I'm using OrientDB 2.2.0 together with TinkerPop 2.6.0 and Java 8.
I have a sample graph which is set up as follows:
City ---LOCATED_IN---> Country.
Both City and Country implement com.tinkerpop.frames.VertexFrame.
If I create a FramedGraph I can very easily query for a specific Country and get back a typed Iterable, for example like this:
Iterable<Country> countries = framedGraph.getVertices("countryCode", "NL", Country.class);
This works perfectly.
Now I wanted to achieve the same type of thing but then using Gremlin so I can do more complicated queries. So as a simple test I wanted to test and see if I could get the cities of the Country I fetched with the previous statement using Gremlin.
Vertex nl = countries.iterator().next().asVertex();
GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<>();
pipe.start(nl).inE("LOCATED_IN").outV();
for (Vertex v : pipe) {
System.out.println(v.getProperty("name").toString());
}
Now this works, I get back the following output:
Nijmegen
Nieuw-Vennep
Niewegein
Sittard
Sittard
Noordwijk
Lisse
What I would like to achieve however is to get back City objects from the pipeline instead of Vertex objects (as with the FramedGraph query).
It seems the pipeline is returning the correct types, since if I change the code slightly to this:
Vertex nl = countries.iterator().next().asVertex();
GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<>();
pipe.start(nl).inE("LOCATED_IN").outV();
for (Vertex v : pipe) {
System.out.println(v);
}
I get back:
v(City)[#38:3]
v(City)[#40:3]
v(City)[#37:3]
v(City)[#36:3]
v(City)[#33:4]
v(City)[#35:3]
v(City)[#39:3]
So I'm getting back vertices of type City.
But if I try to do this:
Vertex nl = countries.iterator().next().asVertex();
GremlinPipeline<Vertex, City> pipe = new GremlinPipeline<>();
pipe.start(nl).inE("LOCATED_IN").outV();
for (City v : pipe) {
System.out.println(v);
}
I get:
java.lang.ClassCastException: com.tinkerpop.blueprints.impls.orient.OrientVertex cannot be cast to models.City
Also if I try this:
Vertex nl = countries.iterator().next().asVertex();
GremlinPipeline<Vertex, City> pipe = new GremlinPipeline<>();
pipe.start(nl).inE("LOCATED_IN").outV().cast(City.class);
for (City v : pipe) {
System.out.println(v);
}
I get the same class cast exception.
I'm obviously doing something wrong but I can't figure out what. Any pointers would be very welcome!
Thanks in advance, Jonck
Ok, after reading some more I found the answer to my own question. I needed to "frame" the vertices I got back from the pipeline.
So as follows:
Vertex nl = countries.iterator().next().asVertex();
GremlinPipeline<Vertex, Vertex> pipe = new GremlinPipeline<>();
pipe.start(nl).inE("LOCATED_IN").outV();
Iterable<City> cities = framedGraph.frameVertices(pipe, City.class);
for (City city : cities) {
System.out.println(city.getName());
}
And now I get back the output I was expecting. Hope this helps someone.
Say that I have an index named "user". How do I get all the nodes belonging to that index using Neo4j-Java Api?
I tried the code below
val nodeIndex = getNodeIndex("article").get
val nodes = nodeIndex.getGraphDatabase().getAllNodes()
But, I got all the nodes present in the db. How do I solve this?
You should use "get" or "query" on the nodeIndex, like:
IndexHits<Node> allArticles = nodeIndex.query( "*:*" );
... do stuff ...
allArticles.close();
or
Node myArticle = nodeIndex.get( "name", "MyArticle" ).getSingle();
What you did above was to regardless of the index, get the graph database and return all nodes.
I have a movie database (postgreSQL). One of tables contains actors and movie titles. The assignment which I have to solve in java is as follows: two actors (A and B) are connected together when they in the same movie. Further two actors, A and B, are also connected when there is a third actor C, who plays with both of them in different movies (A and B don't play together!) and so on... I hope you get the idea :) Now I have to find the shortest connection (= path) between two actors.
Now to the implementation: fetching the data from the DB (prepared statements) and saving the names (as strings) in a linked list is working. As well as simple connection between actors like A -> B (= both play in the same movie). I'm hitting the wall trying to include more complicated connections (like A -> B -> C).
I am storing the actor names in a HashMap like this:
Map<String, List<String>> actorHashMap = new HashMap<String, List<String>>();
So when I load the first actor (Johnny Depp) I have his name as key, and other actors playing with him in a list referenced by the key. Checking, whether another actor played with him is easy:
List<String> connectedActors = actorHashMap.get(sourceActor);
if(connectedActors.contains(actor)) {
found = true; }
But... what do I do if the actor I'm looking for is not in the HashMap (ie. when I have to go one level deeper to find him)? I assume I would have to pick the first actors' name form the connectedActors list, insert it as new key into the HashMap, and fetch all actors he played with him to insert them to. Then search in this list.But that's exactly the part which i can't figure out. I already tried to store the names in graph nods and using bfs to search for them, but same problem here, just don't know how to go "one level down" without creating an infinite loop... Does anyone have an idea how i can solve this? I am just starting with java as well as programing in general so it's probably simple, but I just can't see it :/
First I would use a Set to store the actors someone played with:
Map<String, Set<String>> actorHashMap = ...
instead of a List to avoid duplicate names.
In order to find how many degrees of separation between 2 actors
I would start with one actor and generate all actors that are separated by
1, 2, 3... degrees. I would fix a maximum search depth, however that might not be necessary if the number of actors is not too large.
String actor = "Johnny Depp";
String targetActor = "John Travolta";
Map<String, Integer> connectedActorsAndDepth = new HashMap<String, Integer>();
Integer depth = 1;
Set<String> actorsAddedAtCurrentDepth = actorHashMap.get(actor);
for (String otherActor : actorsAddedAtPrecedingDepth) {
if (otherActor.equals(targetActor)) return depth;
connectedActorsAndDepth.put(otherActor, depth);
}
Set<String> actorsAddedAtPrecedingDepth = actorAddedAtCurrentDepth;
Integer maxDepth = 10;
while (++depth < maxDepth) {
actorsAddedAtCurrentDepth = new HashSet<String>():
for (String otherActor : actorsAddedAtPrecedingDepth) {
if (otherActor.equals(targetActor)) return depth;
if (!connectedActorsAndDepth.contains(otherActor)) {
actorsAddedAtCurrentDepth.add(otherActor);
connectedActorsAndDepth.put(otherActor, depth);
}
}
actorsAddedAtPrecedingDepth = actorsAddedAtCurrentDepth;
}
I do not claim it is the most efficient algorithm. There might also be bugs in the code above.