neo4j reference node obsolete but yet still returned from getAllNodes - neo4j

According to Neo4j documentation the "reference node concept is obsolete - indexes are the canonical way of getting hold of entry points in the graph.".
However if I use GlobalGraphOperations.getAllNodes() I'm still returned a node with id 0 which I didn't create and which has all the looks of a reference node.
I'm trying to implement a method getNode(String uuid)
public Node getNode(String uuid)
{
GlobalGraphOperations globalGraphOperations = GlobalGraphOperations.at(graphDb);
for(Node tmpNode : globalGraphOperations.getAllNodes())
{
if(tmpNode.equals(graphDb.getReferenceNode()))
{ continue;}
String tmpNodeUuid = (String)tmpNode.getProperty("uuid");
if (tmpNodeUuid.equals(uuid))
{
return tmpNode;
}
}
return null;
}
why does getAllNodes return a reference node?
how to implement programmatically getNode() without using deprecated function getReferenceNode()?

The reference node concept is indeed deprecated and will be removed with Neo4j version 2.0. In 1.x the concept still exists and the reference node is created when the database is intially created. If you don't need it, you can just delete the reference node. The method you're writing is gonna get slow as the graph grows as the entire graph is traversed. You should create an index for the UUID property and use that to look up nodes in the graph, which is much faster. As well as being the 'canonical way of getting hold of entry points in the graph' :-)

Related

What is nodeInterface, nodeField and nodeDefinitions in Relay?

I am currently doing the facebook relayjs tutorial and I need help understanding this part of the tutorial, it states
Next, let's define a node interface and type. We need only provide a
way for Relay to map from an object to the GraphQL type associated
with that object, and from a global ID to the object it points to
const {nodeInterface, nodeField} = nodeDefinitions(
(globalId) => {
const {type, id} = fromGlobalId(globalId);
if (type === 'Game') {
return getGame(id);
} else if (type === 'HidingSpot') {
return getHidingSpot(id);
} else {
return null;
}
},
(obj) => {
if (obj instanceof Game) {
return gameType;
} else if (obj instanceof HidingSpot) {
return hidingSpotType;
} else {
return null;
}
}
);
On the first argument on nodeDefinition,where did it get its' globalId? is Game and HidingSpot a name on the GraphQLSchema? What does this 'const {type, id} = fromGlobalId(globalId);' do? and also what is the 2nd argument? I need help understanding nodeDefinitions, somehow I can't find nodeDefinitions on the official documentation. Thank you.
If you were writing a GraphQL server without Relay, you'd define a number of entry points on the Query type, eg:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
}
So when you want to get a User, you can easily get it because user is available as an entry point into the graph. When you build a query for your page/screen, it'll typically be several levels deep, you might go user -> followers -> pictures.
Sometimes you want to be able to refetch only part of your query, perhaps you're paginating over a connection, or you've run a mutation. What Relay's Node interface does is give you a standard way to fetch any type that implements it via a globally unique ID. Relay is capable of recognising such nodes in its queries, and will use them if possible to make refetching and paginating more efficient. We add the node type to the root Query type:
type Query {
picture(id: Int!): Picture
user(id: Int!): User
...etc
node(id: ID!): Node
}
Now for nodeDefinitions. Essentially this function lets us define two things:
How to return an object given its globalId.
How to return a type given an object.
The first is used to take the ID argument of the node field and use it to resolve an object. The second allows your GraphQL server to work out which type of object was returned - this is necessary in order for us to be able to define fragments on specific types when querying node, so that we can actually get the data we want. Without this, we couldn't be able to successfully execute a query such as this:
query Test {
node(id: 'something') {
...fragment on Picture {
url
}
...fragment on User {
username
}
}
}
Relay uses global object identification, which means, in my understanding, if your application ever try to search for an object. In your example, try to look for a game, or try to look for a hidingSpot. Relay will try to fetches objects in the standard node interface. i.e. find by {id: 123} of the Game, or find by {id:abc} of the hidingSpot. If your schema (Game, HidingSpot) doesn't set up the node interface, Relay will not be able to fetch an object.
Therefore, if your application requires a search in a "Game", in the schema, you need to define the node interfaces.
By using graphql-relay helper, use nodeDefinitions function only once in your application to basically map globally defined Ids into actual data objects and their GraphQL types.
The first argument receives the globalId, we map the globalId into its corresponding data object. And the globalId can actually be used to read the type of the object using fromGlobalId function.
The second function receives the result object and Relay uses that to map an object to its GraphQL data type. So if the object is an instance of Game, it will return gameType, etc.
Hope it will help you understand. I am on my way learning, too.

IBM Integration Bus: How to read user defined node (Java) complex (table) property in Java extension code

I created Java user defined node in IntegrationToolkit (9.0.0.1) and assigned it with several properties. Two of the node properties are simple (of String type) and one property is complex (table property with predefined type of User-defined) that is consisted of another two simple properties.
By following the documentation I was able to read two simple properties in my Java extension class (that extends MbNode and implements MbNodeInterface) by making getters and setters that match the names of the two simple properties. Documentation also states that getters and setters should return and set String values whatever the real simple type of a property may be. Obviously, this would not work for my complex node property.
I was also able to read User Defined Properties that are defined on the message flow level, by using CMP (Integration Buss API) classes, which was another impossible thing to do from user defined node without CMP. At one point I began to think that my complex property would be among User Defined Properties, (although UDPs are defined on the flow level and my property is defined on the custom node level) based on some other random documentation and some other forum discussion.
I finally deduced that the complex property should map to MbTable type (as it is so stated in that type's description), but I was not able to use that.
Does anyone know how to access user defined node's complex(table) property value from Java?
I recently started working with WebSphere Message Broker v 8.0.0.5 for one of my projects and I was going to ask the same question until SO suggested your question which answered my question. It might be a little late for this question but it may help others having similar questions.
After many frustrating hours consulting IBM documentation this is what I found following your thread:
You're correct about the properties being available as user-defined properties (UDP) but only at the node level.
According to the JavaDoc for MbTable class (emphasis added to call out the relevant parts):
MbTable is a complex data type which contains one or more rows of simple data types. It structure is very similar to a * standard java record set. It can not be constructed in a node but instead is returned by the getUserDefinedAttribute() on the MbNode class. Its primary use is in allowing complex attributes to be defined on nodes instead of the normal static simple types. It can only be used in the runtime if a version of the toolkit that supports complex properties is being used.
You have to call com.ibm.broker.plugin.MbNode.getUserDefinedAttribute which will return an instance of com.ibm.broker.plugin.MbTable. However, the broker runtime doesn't call any setter methods for the complex attributes during the node initialization process like it does for simple properties. Also, you cannot access the complex attributes in either the constructor or the setter methods of other simple properties in the node class. These are available only in the run or evaluate method.
The following is the decompiled method definition of com.ibm.broker.plugin.MbNode.getUserDefinedAttribute.
public Object getUserDefinedAttribute(String string) {
Object object;
String string2 = "addDynamicTerminals";
if (Trace.isOn) {
Trace.logNamedEntry((Object)this, (String)string2);
}
if ((object = this.getUDA(string)) != null && object.getClass() == MbElement.class) {
try {
MbTable mbTable;
MbElement mbElement = (MbElement)object;
object = mbTable = new MbTable(mbElement);
}
catch (MbException var4_5) {
if (Trace.isOn) {
Trace.logStackTrace((Object)this, (String)string2, (Throwable)var4_5);
}
object = null;
}
}
if (Trace.isOn) {
Trace.logNamedExit((Object)this, (String)string2);
}
return object;
}
As you can see it always returns an instance of MbTable if the attribute is found.
I was able to access the complex attributes with the following code in my node definition:
#Override
public void evaluate(MbMessageAssembly inAssembly, MbInputTerminal inTerminal) throws MbException {
checkUserDefinedProperties();
}
/**
* #throws MbException
*/
private void checkUserDefinedProperties() throws MbException {
Object obj = getUserDefinedAttribute("geoLocations");
if (obj instanceof MbTable) {
MbTable table = (MbTable) obj;
int size = table.size();
int i = 0;
table.moveToRow(i);
for (; i < size; i++, table.next()) {
String latitude = (String) table.getValue("latitube");
String longitude = (String) table.getValue("longitude");
}
}
}
The documentation for declaring attributes for user-defined extensions in Java is surprisingly silent on this little bit of detail.
Please note that all the references and code are for WebSphere Message Broker v 8.0.0 and should be relevant for IBM Integration Bus 9.0.0.1 too.

Not able to access iterator() from RestTraverser, it gives exception java.lang.IllegalAccessError

I am implementing traversal framework using neo4j java-rest-binding project.
Code is as follows:
RestAPI db = new RestAPIFacade("http://localhost:7474/db/data");
RestNode n21 = db.getNodeById(21);
Map<String,Object> traversalDesc = new HashMap<String, Object>();
traversalDesc.put("order", "breadth_first");
traversalDesc.put("uniqueness", "node_global");
traversalDesc.put("uniqueness", "relationship_global");
traversalDesc.put("returnType", "fullpath");
traversalDesc.put("max_depth", 2);
RestTraverser traverser = db.traverse(n21, traversalDesc);
Iterable<Node> nodes = traverser.nodes();
System.out.println("All Nodes:"); // First Task
for(Node n:nodes){
System.out.println(n.getId());
}
Iterable<Relationship> rels = traverser.relationships();
System.out.println("All Relations:"); // Second Task
for(Relationship r:rels){
System.out.println(r.getId());
}
Iterator<Path> paths = traverser.iterator(); // Third Task
while(paths.hasNext()){
System.out.println(paths.next());
}
I need to do 3 tasks as commented in the code:
Print all the node IDs related to node no. 21
Print all the relation IDs related to node no. 21
Traverse all the paths related to node no. 21
Tasks 1 & 2 are working fine.
But when I try to do traverser.iterator() in 3rd task it throws an Exception saying:
java.lang.IllegalAccessError: tried to access class org.neo4j.helpers.collection.WrappingResourceIterator from class org.neo4j.rest.graphdb.traversal.RestTraverser
Can anyone please check why this is happening or if I am doing wrong then what is the right method to do it.
Thanks in Advance.
I don't believe using the Neo4j Traversal Framework via the REST DB binding is properly supported, nor is it advisable. If you traverse via REST, each node and each relationship will be retrieved over the network as the traversal proceeds, incurring a tremendous overhead for the traversal.
Edit: The above is not true, the REST traverser is smarter than I thought.
In general, it will be faster to use Cypher, and access the Neo4j Server using JDBC. Read more about JDBC here: https://github.com/neo4j-contrib/neo4j-jdbc
If you really want to use the Traversal Framework, you should use Server Extensions, which allow you to design a traversal to run on the server itself, and then only move the result of the traversal over the network. Read more about server extensions here: http://docs.neo4j.org/chunked/stable/server-unmanaged-extensions.html

How can I find the Neo4J Index Key's for Indexes created on nodes using Spring Data?

I have created nodes using Spring using the following basic process (see below). I have a POJO for my Concepts and using this object and a Neo4J template to create nodes with indexes. I am still unable to discover what the 'KEY' for the created index is. I know the name of the index is 'CID' but assumed the 'KEY' would be 'conceptId'. However, when I use the following query (see below), no data is returned. It is confirmed that the Index does exist, but I am unable to find out what the proper 'KEY' for said index is so I can utilize it to improve query performance. I am able to query a specified node using WHERE clause searching for a specific value for a property of said node. However, when I try to find the node using the Index 'CID' with Key 'conceptId' no nodes are returned.
// Concept POJO
#NodeEntity
public class Concept {
#GraphId
private Long nodeId;
#Indexed(indexName="CID", fieldName="conceptId")
private Long conceptId;
...
// service where code to create Concept Nodes exists
#Repository
public class ConceptService {
#Autowired
private Neo4jTemplate n4jTemplate;
#Autowired
private ConceptRepository cr;
// Call to create node in a 'service'
public void addConceptNode(Concept concept) {
concept = n4jTemplate.save(concept);
}
...
//Cypher Queries used to retrieve nodes using index
START a=node:CID( conceptId = "66573009")
RETURN a;
// this returns 0 nodes quickly
START a=node:CID( conceptid = "66573009")
RETURN a;
// this returns 0 nodes quickly
START a=node:CID( CID = "66573009")
RETURN a;
// this returns 0 nodes quickly
START a=node:CID( cid = "66573009")
RETURN a;
// this returns 0 nodes quickly
START a=node:CID( CONCEPTID = "66573009")
RETURN a;
// this returns 0 nodes quickly
// Cypher query not using index to retrieve same node
START a=node(*)
WHERE HAS(a.conceptId) AND a.conceptId = 66573009
RETURN a;
// this returns 1 node in 77365ms
//'quickly' = approx.(43-87ms).
There is more to the code than what is shown, but this gives you the basic gist of how I am creating nodes with indexes in a Neo4J DB. There are more properties and more indexes. When using Spring to retrieve the nodes it seems to 'auto' use (I am assuming it is using the index) the index created because it returns the results faster than using the Neo4J data browser.
Any help would be greatly appreciated.
Thanks!

Using Neo4jTemplate to save data in Rest configuration is too slow

I am working on the project with Spring and Neo4j database. I configured my Neo4j database to be rest neo4j. This is the configuration:
<neo4j:config graphDatabaseService="graphDatabaseService" />
<bean id="graphDatabaseService" class="org.springframework.data.neo4j.rest.SpringRestGraphDatabase">
<constructor-arg index="0" value="http://localhost:7474/db/data" />
</bean>
At the beginning I was using notations on my domain objects (#NodeEntity, #RelatedTo, etc.) and repositories to save nodes and relationships. My domain objects are User(id, name), Item(id, name, description, list of terms), Term(content, count). So there not so many properties out there, but even so, saving the object through repository, for example a User with defined id and name lasted for 25 seconds.
I read that this kind of communication with neo4j database is not yet well optimized, so I switched on using the Neo4jTemplate.
This is a example of saving the user (constraints in User are Strings ("id", "name", "USER"):
public Node saveUser(User user) {
Node node = template.createNode();
node.setProperty(User.ID, user.getId());
node.setProperty(User.NAME, user.getName());
node.setProperty("_type", User.LABEL);
template.index(INDEX_ID, node, User.ID, user.getId());
return node;
}
And this is a example of saving the item with relationships to its terms. So each term is a node which is connected to the item:
public Node saveItem(Item item) {
Node node = template.createNode();
node.setProperty(Item.ID, item.getId());
node.setProperty(Item.NAME, item.getName());
node.setProperty(Item.DESCRIPTION, item.getDescription());
node.setProperty("_type", Item.LABEL);
template.index(INDEX_ID, node, Item.ID, item.getId());
for(String termContent : item.getTerms()) {
Node term = termRepository.getNodeByContent(termContent);
if(term == null) {
term = termRepository.saveTerm(new Term(termContent));
} else {
termRepository.addCountToTerm(term);
}
int frequency = 1;
Relationship contains = node.createRelationshipTo(term, RelationshipTypes.CONTAINS);
contains.setProperty(Term.FREQUENCY, frequency);
}
return node;
}
The object termRepository (it isn't extending GraphRespository<Term>) has methods which are similar to the method of saving the user. Fetching the term is done like this:
public Node getNodeByContent(String content) {
if(!template.getGraphDatabaseService().index().existsForNodes(INDEX_ID))
return null;
return template.lookup(INDEX_ID, Term.CONTENT, content).to(Node.class).singleOrNull();
}
And, finally what is my problem. Even now it is still slow, inserting user (only parameters id and name) and indexing it takes for 3 seconds, and inserting item where it is being connected to terms takes for 30 seconds (for 4 terms - which is very small ammount according to the number of 60-70 which I will have in real situation).
Please, can you give me some hint or anything else that could help me with this kind of issue?
Thanks in advance.
This is really strage, where does your server run? Seems to be something with the network setup.
I mean SDN over REST is not fast, but it is also not that slow.
Can you share your classes too?
You should not do the individual property updates over the wire. Use cypher statements that create all the properties in one go.
There is also neo4jTemplate.createNode(map of properties) which does it as one operation.

Resources