My graph contains nodes called points and lines.
There is a relationship type called "NEXT", which connects two points and has a property called lineID (a long). A line node consists simply of an ID and a reference to a "root" point. To traverse a line is to start with its root node and follow the NEXT relationships whose lineID matches the id of the line being traversed. To clarify, if we're traversing a line with ID 123, whose root point has id 321, the Cypher traversal would be:
START n = node(321)
MATCH (n)-[rel:NEXT*{lineID:123}]->(x)
RETURN collect(rel)
A line, then, is essentially a linked list of Next relationships with matching lineID properties. That said, I don't want to persist this list as a property of lines - I want the list to be constructed by a traversal when a line is loaded.
What are my options for implementing this in spring-data-neo4j? Specifically, should "lines" exist as NodeEntitys, and if so what should they contain?
#NodeEntity
class Line {
#RelatedTo(type="ROOT")
Point root;
#RelatedToVia(type="NEXT")
Iterable<Item> list;
doesn't quite fit, because the line is not related via Next relationships to the item, the root point is. It also fails to address the fact that those NEXT relationships need to have a lineID property matching the line's ID (which becomes important because some points exist on multiple lines - i.e. they have multiple NEXT relationships with different lineID's). I have a hunch that the solution will involve annotating the list as a #GraphTraversal, but I don't understand how that would work.
I'm doing this largely as an exercise to wrap my head around data modeling in SDN, in the context of wrapping my head around Neo4j and graph databases in general. If the question I'm asking reveals a flaw in my understanding of any of these things, I'd be very appreciative if someone could point it out.
This should be a suitable model for your entities:
#NodeEntity
class Point {
#GraphId
protected Long id;
#RelatedToVia(type="NEXT")
Set<Edge> edges;
}
#NodeEntity
class Line {
#GraphId
protected Long id;
#RelatedTo(type="ROOT")
Point root;
}
#RelationshipEntity
public class Edge {
#GraphId
protected Long id;
#StartNode private Point from;
#EndNode private Point to;
#RelatedTo(type="LINE")
Line line;
}
It easily allows both programmatic navigation in Java as in:
Set edges = line.getPoint().getEdges();
for (Edge edge: edges) {
if (edge.getLine().getId() == id) {
...
}
}
or Cypher queries like the one you listed.
Related
I am trying to create a tournament bracket using linked lists where each match of the tournament is a node that has 2 parent nodes. Is this possible?
Not sure about linked list. I think you need a class Team and a class Match. The match will have 2 fields, Team1 and Team2, a field round (top 16, top8 etc) and a field NextMatch that is an instance of Match, which will be the next round. All these Matches could be placed inside an ArrayList. Or this is how I would do it.
The structure you are describing is a tree, not a list.
While it is theoretically possible to use as list to model an array, and then use the array to model an arbitrary data structure, the result would be a complicated, inefficient mess.
A better idea would be model the matches using a custom Match class; e.g. something like this:
public class Match {
private Player player1;
private Player player2;
private Match leadupMatch1; // null in first round
private Match leadupMatch2; // null in first round
private Match winnersMatch;
private Match losersMatch; // if needed
private Result result;
...
}
public class Player {
...
}
public enum Result {
NONE,
PLAYER_1_WINS,
PLAYER_2_WINS
}
I have data as shown as below. Here if Team 1 is parent & having 2 child Team A & Team B. Team A is again a parent & having player names as child. Team B does not have any child.
Again in another scenario, Team A is independent parent & contains some child etc..
If i give Team 1, then it should fetch records of Team A & Team B as a bundle.
If i give Team A, then it should fetch records of Team A containing its child.
I was thinking to implement this using Map or Tree . and I tried this -
public class Node {
private String id;
private List<Node> children = new ArrayList<>();
private Node parent;
..........
//setters and getters
}
but here creating node dynamically is problem because we don't know the levels of parents(in this example there are 2). means "Dhoni" again contains some child like wise.
How to implements this ?. Please guide.
Whatever i understood from problem description i will try to summarize here.You are looking for a data structure which can take parent name(key) and it might have children, and each child also further can be extended.
public class Node {
private String id; // for each level you have key defined.
private List<Node> children = new ArrayList<>(); //using given key you can get children list
}
You can use map here
Map<String, List<Node>> // here key is team name etc., and list represents children.
If you give team1 as key, you get list which contains teamA, teamB. So if you want to check further, check list size, if it is greater than zero, you can get children(Further you can get all the players defined for both teamA,teamB) otherwise you are at last child.
Somewhat new to Java. I have used various Java collections (treeset, hashmap, arraylist) before quite successfully. My problem is similar to a Facebook-like network. I have various users in a membership organization and I want to store in a collection for each individual in our membership other members who are linked to this member by interest. I thought the simplest solution would be to dynamically allocate a new simple collection by name for each member that would have other member names (existing or new) linked, but it appears Java does not allow dynamic allocation of new collections.
I could have a concatenated string in a hashmap listing all the names associated with the key name, but this seems an akward solution. I assume this is a social common network-like problem that has an elegant solution. Suggestions?
Why don't you model it like a graph?
class Node {
private String name;
// TODO: Write your getters / setters.
}
class Edge {
private Edge source, destination;
// TODO: Write your getters / setters.
}
List<Node> nodes = new ArrayList<Node>();
List<Edge> edges = new ArrayList<Edge>();
Then, if you encounter a relationship you can do the following:
Node alice = new Node("Alice Kentucky");
if (!nodes.contains(alice)) { nodes.add(alice); }
edges.add(new Edge(bob, alice)); // where Bob is already in the node list
I have such structure:
// all objects have valid mapping to database
public class Child {
private int id;
private String name;
}
public class Parent {
private int id;
private String name;
private List<Child> chidlren;
}
and I have to update specific child B inside parent A.
There are two ways:
Update child's fields inside collection and update the whole object:
Parent temp = dao.getParent(id);
temp.getChildren.get(0).setName('test');
dao.updateParent(temp);
Update only child object:
Child temp = dao.getChild(id);
temp.setName('test');
dao.updateChild(temp);
Which one is better if I want to get more perfomance?
Thank you
On the surface, I would surmise that the second solution
2.Update only child object
would be more performant.
However, the only way you determine this quantitatively would be to turn on Hibernate's show_sql, capture the SQL for Solution 1 and Solution 2, run an Explain Plan for each of your solutions, and compare the resulting Explain Plans.
You could get differing results depending on what else has changed/not changed in the Parent object and other children in the Parent.children collection. When capturing SQL for Explain Plans, you would want to try different scenarios.
I'm having a bit of trouble mapping the following:
public class Operation {
private Integer id;
private String name;
private List<Item> items = new ArrayList<Item>();
//set/getters/hashcode/etc. omitted
public void addItem(Item i,Operation end) {
i.setOperationStart(this);
i.setOperationEnd(end};
items.add(i);
end.getItems().add(i);
}
public class Item {
private Integer id;
private String name;
private Operation operationStart;
private Operation operationEnd;
//set/getters/hashcode/etc. omitted
}
So basically an Operation have a bunch of Items, and an Item belongs to 2 Operations.
Also, it doesn't make sense for an item to exist if one of the Operations doesn't exist, i.e. if I delete one of the Operations, I want to remove the item from wherever else it's stored as well.
Does anyone have a pointer on how I'd map the above classes, or could point me to some examples showing how to map a child object that has 2 parents ?
From an object oriented point of view what is represented looks like two ManyToOne associations between Item and Operation, one of them being bidirectional. This could be mapped like this:
#Entity
public class Item {
#Id private Integer id;
private String name;
#ManyToOne
private Operation operationStart;
#ManyToOne
private Operation operationEnd;
//set/getters/hashcode/etc. omitted
}
#Entity
public class Operation {
#Id private Integer id;
private String name;
#OneToMany(cascade = CascadeType.REMOVE, mappedBy="operationStart")
private List<Item> items = new ArrayList<Item>();
//set/getters/hashcode/etc. omitted
}
This should result in an [ITEM] table having two FKs pointing on [OPERATION]. And populating the items collection would result in a SELECT restricted to one of them (the ID of the start operation in the above example).
I don't know if this scenario makes sense but this is IMO the only scenario Hibernate can handle. If this is not what you want, then I think you should have two collections on the Operation side (that you could maybe hide behind friendly methods).
Whether you use hbm.xml or annotations doesn't make any difference.
This sounds like a combination of a many-to-many relation between Items and Operations, and a ternary relation between one Item and two Operations.
Assuming that your business logic is fixed on exactly two Operations per Item, and not more than that, I'd tackle this problem as follows:
If you want a clean object model, then create an intermediate object to hold the references to the two operations, and it should hold one item as a component.
Map the items in the hbm. Basically, each Operation should have a list of the intermediate object, and each intermediate object has one Item. When you delete an intermediate object, cascade the delete to the item, but not to the operations.
The tricky part, as you said, is when you delete an operation. Whether you use an intermediate object or not, you need to cascade the delete to the list with all-delete-orphan. However, I suspect that you'll have some issues due to 2nd level cache. The only way I know around that is this:
before deleting an operation op1, traverse the object graph and detach each intermediate object from its other operation op2, and only then flush. Otherwise hibernate will refuse to delete the intermediate objects because they are still held in some sets in other Operations.