Tinkerpop: Set Label After Creating Vertex - java

Is there a way to set the T.label after the vertex has been created. I have tried the following:
Vertex v = graph.addVertex();
v.property(T.label.name(), "test");
But when I try the following traversal:
graph.traversal().V().hasLabel("test").next
I get
org.apache.tinkerpop.gremlin.process.traversal.util.FastNoSuchElementException
Is there something special about T.label that limits it to being set at the step of constructing the vertex ?

No, labels cannot be changed. If you need this type of functionality, you should use a vertex property instead.
From the TinkerPop documentation: "NOTE: In TinkerPop3, vertices are allowed a single immutable string label (similar to an edge label). This functionality did not exist in TinkerPop2. Likewise, element id’s are immutable as they were in TinkerPop2."

Related

Labels for vertices using Jung library

I started to use the Jung library for my visualization of a graph. Main problem currently is that I don't know how to set labels/metadata for my vertices. Depending on a specific attribute of a vertex, I would like to color the vertices differently. The object of class Node contains an additional Integer-value, I would like to add as an additional attribute (by getGroup()) for the vertices. The following code only visualizes the getId()-String of each node.
Any recommendation?
This is my following code in the main class:
Graph<String,Double> g = new SparseGraph<String,Double>();
List<Link> linkList = new ArrayList<Link>();
List<Node> nodeList = new ArrayList<Node>();
linkList = f.getLinks();
nodeList = f.getNodes();
for(Node nodeElement:nodeList){
g.addVertex(nodeElement.getId());
}
for(Link linkElement:linkList){
g.addEdge(linkElement.getValue(), linkElement.getSource(), linkElement.getTarget());
}
VisualizationImageServer vs =
new VisualizationImageServer(
new SpringLayout(g), new Dimension(500, 500));
vs.getRenderContext().setVertexLabelTransformer(new ToStringLabeller() {
public String transform(Object v) {
return Integer.toString(((Node)v).getGroup());
}
});
JFrame frame = new JFrame("");
frame.getContentPane().add(vs);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setVisible(true);
You didn't specify which version of JUNG you're using, but you've got the right general idea: call setVertexLabelTransformer() with a function that converts nodes to the string that you want to render.
That said, there are a few issues with your code as written and I'm not sure I understand how you're getting the reported behavior with the code as quoted above.
(0) I don't understand why you're adding the node ID as the vertex, rather than just the Node. Are the endpoints of your Links node IDs or Nodes?
In any event, if you don't add the Node, then it's not clear from your code as written how you expect the vertex Group to be available.
(1) The vertices of the graph are node IDs, not Nodes, but you're casting the vertex object passed to transform() to a Node. I would expect this to throw a ClassCastException.
(2) Even supposing that your vertices were actually Node objects,
I'm surprised that you're reporting that the vertex ID (rather than the Group) is what's showing up on the label, because the only thing that you're asking for in the vertex label is the Group; I wouldn't expect the ID to be showing up at all.
That said, if the vertices are Node objects, and you want multiple elements to show up, it's pretty easy; just provide a function that does what you want on the Node object.
* If that function is toString(), then you can use ToStringLabeller (and that should actually be the default, so you shouldn't even need to specify it); more on that below.
* If that function is (say) getLabel(), then this should work (in Java 8):
// either of these should work
setVertexLabelTransformer(Node::getLabel())
setVertexLabelTransformer(v -> v.getLabel())
or you can do the anonymous inner class thing if you're not using Java 8.
If you don't want your vertices to be Node objects, then you'll need to provide a way of mapping vertex objects (node IDs) to nodes, such as a Map<String, Node>, and then supply that map to the function that converts vertices to labels:
setVertexLabelTransformer(v -> labelToNode.get(v).getLabel())
Note: ToStringLabeller() shouldn't generally have its transform() method overridden; it just specifies that you want to use the toString() of the object itself as the label.
// These two are equivalent
setVertexLabelTransformer(v -> v.toString())
setVertexLabelTransformer(new ToStringLabeller())
(Needless to say, ToStringLabeller() predates Java 8. :) )

What data structure should I use for lookup in constant time from a changing pair of values to an object in java?

I have a valueclass (position) with two doubles (x and y) in it.
I also have a class ship that has an attribute with a position object in it.
I need to be able to do do a lookup like: get ship at (5,7) with constant time.
I also want to be able to change the value of a position object because multiple ships can refer to the same position objects and they all have to move together when that position object changes.
I have looked at hashmap, but to be able to do get ship at new Position(5,7) I need to override the hashcode of the position object (so that positions with the same values have the same hash), and I heard you shouldn't change the hashcode of an object in a hashlist.
This might not be exactly what you are looking for but I think what you need is a 2D spatial partitioning data structure like a quad-tree.

Type-Filter Step in Gremlin 3?

I would like to know how to apply a type filter in a Gremlin 3.x GraphTraversal. For example, let's consider the Graph of the Gods as an example graph.
Here, we can do the following:
Set<Element> set = graph.V().has("name", "jupiter").toSet()
... and get a Set<Element>. What I would like to have is an Iterable<Vertex> instead (or a subclass of Iterable). From the traversal declaration, the result can only consist of vertices, because of the .V() operator. Due to the Java type system, it is needlessly generalized to Element. Is there a way to type filter this? What I would like to do is something along these lines...
Set<Vertex> vertices = graph.V().has("name", "jupiter").cast(Vertex.class).toSet();
... but there is no cast operator. Ultimately, the reason why I want to do this is because I need to iterate over the resulting vertices in a foreach-loop, and having to down-cast the loop variable as the first statement in the loop is annoying.
I'm open for alternatives, I'm still new to Gremlin 3 and there may be many things I'm not aware of yet.
Against Tinkerpop3 M6/ titan0.9 M1, the following should work:
Set<Vertex> vertices = graph.V().<Vertex>has("name", "jupiter").toSet();
Most of the M6 type issues can be resolved in a similar manner (parameterizing the method that produces the element by the expected type).

cypher indexing common property on all nodes

As per new indexing rules, the auto_index will go away in future and its expected to create indexes using cypher. According to this new way, to index a node property, you MUST provide a Node Label.
I have a 'nodeId' property present on all types of Node Labels - User, Employee, Bank, Car, etc. I used to auto-index this property to retrieve any type of node if its nodeId is known. Please note that since auto-index did not require me to give a Node Label, it was possible for me to do what I did.
ReadableIndex<Node> readableIndex = this.graphDatabaseService.index().getNodeAutoIndexer().getAutoIndex();
readableIndex.get("nodeId", "0").getSingle();
But with new style, I have to create index on nodeId property for each and every Node Label. So I have to do this:
create index on :User(nodeId)
create index on :Employee(nodeId)
...
Moreover, my method getByNodeId(String nodeId) is useless now because this cypher query IMHO will not be able to use the index anymore since I am not passing any node label.
match (node) where node.nodeId = {nodeId} return node;
Since the whole point of my getByNodeId() method was to be generic across all nodes, I cannot give this cypher query a node label. So what should I do here. My 2 questions are:
How do I tell neo4j via cypher to index on all node labels
How do I write a cypher query which uses index not based on node label, but based on node property.
Note:
It is essential for me to use cypher because I am using neo4j-jdbc
and they have no method to create auto-index or access the
auto-indexer (atleast not that I know of).
Some might suggest me to change the neo4j.properties to enable
auto-indexing there, but I dont like changing configuration files. I
want to do it in my program. Anyway, that would have only solved the
first issue. Second issue is still there.
A node can have multiple labels.
Thus, if you make all your nodes share a common label, say Base (in addition to whatever labels they currently have), you can just have a single index that covers all your nodes:
CREATE INDEX ON :Base(nodeId)

should the adjacency information be stored in the graph object or in the vertex itself?

For purpose of the demonstrating the concept of adjacency list, I would assume that it is easy to represent the list as a list of lists and put the vertices as numbers and put them in an array where we can reference them by index directly in a graph. Once we get the index of a vertex, we can just get the respective list array.
However, for actual objects, where the vertex can't be just referenced by an array index, I would assume a separate vertex object would need to be created. In this case, my question is where should the edge information be implemented.
In OO based programming languages, such as java, I have see implementations of the adjacency list based graph implementation where the adjacency information is stored in the vertex object itself with a data member of some type of data structure, such as arrays, list, and etc. However, I have also seen people implement the adjacency edge information in the graph object itself by maintaining a list of edges.
Is it more of a personal preference as to where the edge information should be stored?
I think it depends on how you want the graph API to look like.
Suppose for example that the graph works with an arbitrary generic type representing a vertex. In this case, instead of defining a vertex wrapper for internal use (and managing adjacency in it), you can simply have an adjacency data structure as a member of the graph class:
public class Graph<V> {
private Map<V, Set<V>> adjacencies;
..
}
If on the other hand you do wish to expose a Vertex object together with its adjacencies (I don't find a good reason why), then you should be careful about the data consistency. The adjacency data must be read only for the caller (or defensively copied), otherwise the caller may alter an edge in such way that it's not symmetric anymore.
To conclude, the adjacency data maintained by the graph class seems a better option to me. It simplifies the API and the implementation, and it doesn't require special measures to protect the class invariants if you decide to expose the vertex object.

Categories