Hi All,
Today, I would like to post a bit of my creation on the data Neo4j traversal. As you know that Neo4j traversal is one of powerful engine which may traverse a million of hops in just milliseconds. I created a class that uses the Neo4j traversal and show the traversed node in the form of table. For some people it is easier to have their data shown in the table such as excel as below
To create this class, I use 3 component which are PathExpander, Traverser and Evaluators. The combination of them are just amazing. To create the data are able to show into table form as shown above, I use library downloaded from google code called BTC-ASCII-Table.
Here are my full class.
package neo4j.mytraversal; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.neo4j.cypher.internal.pipes.matching.MyEvaluator; import org.neo4j.graphdb.Direction; import org.neo4j.graphdb.DynamicRelationshipType; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.Path; import org.neo4j.graphdb.Relationship; import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.traversal.Evaluation; import org.neo4j.graphdb.traversal.Evaluator; import org.neo4j.graphdb.traversal.Evaluators; import org.neo4j.graphdb.traversal.TraversalDescription; import org.neo4j.kernel.StandardExpander; import org.neo4j.kernel.Uniqueness; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.neo4j.support.Neo4jTemplate; import scala.actors.threadpool.Arrays; import com.bethecoder.ascii_table.ASCIITable; public class Runner { @Autowired Neo4jTemplate template; Iterator<Path> path; final MeExpander expander; Map<Integer, List<String>> level; public Runner() { // TODO Auto-generated constructor stub expander = new MeExpander(); level = new HashMap<Integer, List<String>>(); } public void addRealtionshipSequence(String relationsipName, Direction direction, Integer depth) { expander.addRelationName(new NodeSequence(relationsipName, direction), depth); } public void showField(int depth, String[] fields) { level.put(depth, Arrays.asList(fields)); } public void print() { List<Map<String, String>> valuList = new ArrayList<Map<String, String>>(); while (path.hasNext()) { Path temp = path.next(); Iterator<Node> nodeIterator = temp.nodes().iterator(); int itCount = 0; Map<String, String> tempValue = new HashMap<String, String>(); while (nodeIterator.hasNext()) { Node node = nodeIterator.next(); Iterator<Integer> i = level.keySet().iterator(); while (i.hasNext()) { int key = i.next(); if (itCount == key) { List<String> val = level.get(key); List<String> newVal = new ArrayList<String>(); newVal.addAll(val); String firstItem = newVal.get(0); if (firstItem.equals("*")) { Iterator<String> itProp = node.getPropertyKeys() .iterator(); while (itProp.hasNext()) { String fieldExtract = itProp.next(); if (!newVal.contains(itCount + "-" + fieldExtract)) { newVal.add(itCount + "-" + fieldExtract); } tempValue.put(itCount + "-" + fieldExtract, node.getProperty(fieldExtract) .toString()); } } else { for (int checkfieldit = 0; checkfieldit < newVal .size(); checkfieldit++) { if (node.hasProperty(newVal.get(checkfieldit))) { tempValue.put( itCount + "-" + newVal.get(checkfieldit), node.getProperty( newVal.get(checkfieldit)) .toString()); if (!newVal.contains(itCount + "-" + newVal.get(checkfieldit))) { newVal.add(itCount + "-" + newVal.get(checkfieldit)); } if (!path.hasNext()) { newVal.remove(newVal.get(checkfieldit)); } } } } if (!path.hasNext()) { newVal.remove("*"); } level.put(key, newVal); } } itCount++; } valuList.add(tempValue); } List<String> Header = upHeader(level); printTable(Header, valuList); } public void traverse(Long nodeID) { if (template != null) { TraversalDescription desc = template.traversalDescription() .breadthFirst().evaluator(new Evaluator() { public Evaluation evaluate(Path path) { return Evaluation.INCLUDE_AND_CONTINUE; } }).expand(expander).evaluator(Evaluators.excludeStartPosition()); path = desc.traverse(template.getNode(nodeID)).iterator(); } } public List<String> upHeader(Map<Integer, List<String>> level) { List<String> temp = new ArrayList<String>(); Iterator<Integer> ii = level.keySet().iterator(); while (ii.hasNext()) { List<String> a = level.get(ii.next()); for (int i = 0; i < a.size(); i++) { if (!temp.contains(a.get(i))) { temp.add(a.get(i)); } } } return temp; } public void printTable(List<String> header, List<Map<String, String>> row) { String newHeader[] = new String[header.size()]; String[][] result = new String[row.size()][header.size()]; for (int i = 0; i < header.size(); i++) { newHeader[i] = header.get(i); } for (int i = 0; i < row.size(); i++) { for (int ii = 0; ii < header.size(); ii++) { result[i][ii] = ""; } } for (int i = 0; i < row.size(); i++) { Map<String, String> valueRow = row.get(i); for (int ii = 0; ii < header.size(); ii++) { if (valueRow.containsKey(header.get(ii))) { result[i][ii] = valueRow.get(header.get(ii)); System.out.println(result[i][ii] + header.get(ii)); } } } ASCIITable.getInstance().printTable(newHeader, result); } }
The above class is the main class which do the trick which do the traversal and print the data into table. In order to use the application correctly here is sample
public class Runner { @Autowired Neo4jTemplate template; Iterator<Path> path; final MeExpander expander; Map<Integer, List<String>> level; public Runner() { expander = new MeExpander(); level = new HashMap<Integer, List<String>>(); } public void addRealtionshipSequence(String relationsipName, Direction direction, Integer depth) { expander.addRelationName(new NodeSequence(relationsipName, direction), depth); } public void showField(int depth, String[] fields) { level.put(depth, Arrays.asList(fields)); } public void print() { List<Map<String, String>> valuList = new ArrayList<Map<String, String>>(); while (path.hasNext()) { Path temp = path.next(); Iterator<Node> nodeIterator = temp.nodes().iterator(); int itCount = 0; Map<String, String> tempValue = new HashMap<String, String>(); while (nodeIterator.hasNext()) { Node node = nodeIterator.next(); Iterator<Integer> i = level.keySet().iterator(); while (i.hasNext()) { int key = i.next(); if (itCount == key) { List<String> val = level.get(key); List<String> newVal = new ArrayList<String>(); newVal.addAll(val); String firstItem = newVal.get(0); if (firstItem.equals("*")) { Iterator<String> itProp = node.getPropertyKeys().iterator(); while (itProp.hasNext()) { String fieldExtract = itProp.next(); if (!newVal.contains(itCount + "-"+ fieldExtract)) { newVal.add(itCount + "-" + fieldExtract); } tempValue.put(itCount + "-" + fieldExtract, node.getProperty(fieldExtract).toString()); } } else { for (int checkfieldit = 0; checkfieldit < newVal.size(); checkfieldit++) { if (node.hasProperty(newVal.get(checkfieldit))) { tempValue.put(itCount + "-"+ newVal.get(checkfieldit),node.getProperty(newVal.get(checkfieldit)).toString()); if (!newVal.contains(itCount + "-"+ newVal.get(checkfieldit))) { newVal.add(itCount + "-" + newVal.get(checkfieldit)); } if (!path.hasNext()) { newVal.remove(newVal.get(checkfieldit)); } } } } if (!path.hasNext()) { newVal.remove("*"); } level.put(key, newVal); } } itCount++; } valuList.add(tempValue); } List<String> Header = upHeader(level); printTable(Header, valuList); } public void traverse(Long nodeID) { if (template != null) { TraversalDescription desc = template.traversalDescription().breadthFirst().evaluator(new Evaluator() { public Evaluation evaluate(Path path) { return Evaluation.INCLUDE_AND_CONTINUE; } }).expand(expander).evaluator(Evaluators.excludeStartPosition()); path = desc.traverse(template.getNode(nodeID)).iterator(); } } public List<String> upHeader(Map<Integer, List<String>> level) { List<String> temp = new ArrayList<String>(); Iterator<Integer> ii = level.keySet().iterator(); while (ii.hasNext()) { List<String> a = level.get(ii.next()); for (int i = 0; i < a.size(); i++) { if (!temp.contains(a.get(i))) { temp.add(a.get(i)); } } } return temp; } public void printTable(List<String> header, List<Map<String, String>> row) { String newHeader[] = new String[header.size()]; String[][] result = new String[row.size()][header.size()]; for (int i = 0; i < header.size(); i++) { newHeader[i] = header.get(i); } for (int i = 0; i < row.size(); i++) { for (int ii = 0; ii < header.size(); ii++) { result[i][ii] = ""; } } for (int i = 0; i < row.size(); i++) { Map<String, String> valueRow = row.get(i); for (int ii = 0; ii < header.size(); ii++) { if (valueRow.containsKey(header.get(ii))) { result[i][ii] = valueRow.get(header.get(ii)); } } } ASCIITable.getInstance().printTable(newHeader, result); } }
The above code will show the table as below
But if you wanted to change only viewing dome of the column then you may be able to change the * to the field name you want to show. As example below
<br />runner.showField(2, new String[]{"*"});<br />runner.showField(1, new String[]{"*"});<br />runner.showField(0, new String[]{"name"});<br />