Hello Tobias,Thanks very much for your help, to be clear I want to find the
path that has the least cost, in this case length is the determinator for doing
this. The total number of nodes are roughly around a 100 but not much more. I
am attaching my heap dump,my code for parsing the google earth data as well as
the actual xml file I use to parse and load the data, managing the Graph and
the relationships.
My project does the following:1) Create a physical graph based on google earth
with a set of nodes and paths2) Load the contents of the google earth file into
neo4j using regular expressions to parse the xml3) Run the dijkstra algorithm
on this graph
Your help is much appreciated, let me know if there's anything else I can
provide.Regards
> From: tobias.ivars...@neotechnology.com
> Date: Sun, 30 Jan 2011 16:22:42 +0100
> To: user@lists.neo4j.org
> Subject: Re: [Neo4j] Calculating shortest paths in a large graph
>
> Hi Saikat,
>
> This was a strange one.
>
> Are you sure you only have 100 nodes? That is really tiny, and your title
> said "large graph". How many relationships?
>
> I really cant see a way this could run into heap space issues, what does
> your heap configuration look like?
>
> 1) Batch insertion will not help you, since you aren't inserting, you are
> reading from the graph.
> 2) Granted, Dijkstra isn't the best algorithm for finding the cheapest path
> (that's what it finds, not shortest path), but with a small graph it should
> still terminate quickly.
> 3) Unless you are running this on a machine with only 8MB of RAM (or
> something equally silly), hardware should not be your problem.
>
> If the specifications you've specified are in fact correct, and your graph
> only contains 100 nodes, then could you please provide me with a heap dump
> so that I can analyze where heap is being wasted, because OOM on such a
> small graph would be a bug.
>
> To get a heap dump when the program throws OOME, provide the following
> startup parameter to the JVM:
> -XX:+HeapDumpOnOutOfMemoryError
> You can send the resulting .hprof-file to me directly, the mailing list is a
> bit restrictive about attachments.
> If the graph is larger, and the "100 nodes" part was a typo, then switching
> algorithm might be a good solution, Dijkstra is not optimal for large
> graphs.
>
> I'd love to help, but I need some more details, because this seems strange
> to me.
> Cheers,
> Tobias
>
> On Sun, Jan 30, 2011 at 3:19 PM, Saikat Kanjilal <sxk1...@hotmail.com>wrote:
>
> >
> > Hi Folks,I'm working on a little route planning spring based neo4j service
> > where I initially load up all my data into neo4j and have about a 100
> > nodes, however it seems that I am running into heap space issues when
> > running the Dijkstra Algorithm for any traversals that are relatively far
> > apart (i.e. opposite ends of the graph). I have tried to increase the heap
> > space but that didn't seem to make a difference. Note that I am not
> > currently using batch insertion and am using neo4j's transaction manager
> > with spring with the @Transactional annotation to perform all transactions.
> > I was wondering what the areas are that I can look at to get past this.
> > The things that are coming to mind include:
> > 1) Adding batch insertion2) Trying the other algorithms like AStar3)
> > Running this on more powerful hardware
> >
> > Number 3 seems unlikely based on all I've read on neo4j and its performance
> > characteristics. I can attach my code if needed but being a newbie to neo4j
> > I wanted to understand what I'm missing conceptually that could be causing
> > these issues.
> > Best Regards
> >
> >
> >
> > _______________________________________________
> > Neo4j mailing list
> > User@lists.neo4j.org
> > https://lists.neo4j.org/mailman/listinfo/user
> >
>
>
>
> --
> Tobias Ivarsson <tobias.ivars...@neotechnology.com>
> Hacker, Neo Technology
> www.neotechnology.com
> Cellphone: +46 706 534857
> _______________________________________________
> Neo4j mailing list
> User@lists.neo4j.org
> https://lists.neo4j.org/mailman/listinfo/user
package com.hbc.locationservices.graph;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.concurrent.ConcurrentHashMap;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.neo4j.graphalgo.GraphAlgoFactory;
import org.neo4j.graphalgo.PathFinder;
import org.neo4j.graphalgo.WeightedPath;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.DynamicRelationshipType;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Path;
import org.neo4j.graphdb.PropertyContainer;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.RelationshipType;
import org.neo4j.index.lucene.LuceneIndexService;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.kernel.Traversal;
import org.springframework.transaction.annotation.Transactional;
/* This graph manager object is the abstraction over neo4j that allows
* the creation of nodes each containing a lat and long
* as well as paths between nodes that are representative
* of the data extracted from google earth, drive all
* the transactions through Spring which internally will
* use neo4j's transaction manager
*/
public class GraphManager {
private static final String NAME_KEY = "name";
private static final String LATITUDE_KEY = "latitude";
private static final String LONGITUDE_KEY = "longitude";
private static final String LENGTH_KEY = "length";
//nodetype is based on metadata
//and is an enumeration with the
//following choices
//1)TRAIN_WAYPOINT
//2)WAYPOINT
//3)BOAT_WAYPOINT
private static final String NODE_TYPE_KEY = "nodetype";
private static final String KNOWS_KEY = "KNOWS";
private static RelationshipType KNOWS = DynamicRelationshipType.withName(
KNOWS_KEY );
//exact earth radius in miles
private static final Log logger = LogFactory.getLog(GraphManager.class);
private static final String errorString = "ERR";
//The following classes are wired with
//spring as properties
//through the methods below
private EmbeddedGraphDatabase curGraphDb;
private LuceneIndexService curIndexService;
public void setCurGraphDb(EmbeddedGraphDatabase curGraphDb)
{
this.curGraphDb=curGraphDb;
}
public EmbeddedGraphDatabase getCurGraphDb()
{
return curGraphDb;
}
public void setCurIndexService(LuceneIndexService curIndexService)
{
this.curIndexService=curIndexService;
}
public LuceneIndexService getCurIndexService()
{
return curIndexService;
}
/* Given a train route figure out
* whether the current path of
* interest is a train route by
* examining a set of nodes
* and then checking the node type
* attribute
* @param curPath the path to iterate over
* @return a boolean that determines whether we're on a train route
*/
@Transactional
public boolean isPathATrainRoute(Path curPath)
{
Iterator<Node> curNodeList=curPath.nodes().iterator();
boolean result=false;
while (curNodeList.hasNext())
{
Node curNode=curNodeList.next();
NodeType
curNodeType=(NodeType)curNode.getProperty(NODE_TYPE_KEY);
if (curNode!=null)
{
if (curNodeType.equals(NodeType.TRAIN_WAYPOINT))
{
result=true;
break;
}
}
}
return result;
}
/* Calculate an array of paths corresponding
* to the simple paths between the node
* at the begining and end
* @param startNode the node at the begining
* @param endNode the node at the end
* @param maxDepth the max depth returned paths are allowed to have
* @return the list of iterable paths from the start node
* to the end node
*/
public Iterable<Path> findAllSimplePaths(String startNode,String
endNode,int maxDepth)
{
PathFinder<Path> finder = GraphAlgoFactory.allSimplePaths(
Traversal.expanderForAllTypes(), maxDepth );
Iterable<Path> paths = finder.findAllPaths( findNode( startNode ),
findNode( endNode ) );
return paths;
}
/* Create a node based on a set of properties
* associated with that node, the properties
* include the lat long coordinates and the length
* relationship from this node to another node
* also index this node as we are creating the node
* @param the property list for this node
* @return the node associated with these properties
* @throws generic Exception
*/
@Transactional
public Node createNode( ConcurrentHashMap<String,Object> properties )
{
Node result=null;
try
{
result=findNode((String)properties.get(NAME_KEY));
if (result==null)
{
result=curGraphDb.createNode();
setProperties( result, properties );
if (curIndexService!=null)
{
curIndexService.index( result,
NAME_KEY, properties.get(NAME_KEY) );
}
}
}
catch (Exception e)
{}
finally {
}
return result;
}
/* Given a node id, return the node's properties
* which currently includes its id, lat, long
* and its relationships
* @param id the id of the node
* @return a hashmap consisting of all the relevant properties
* @throws none
*/
@Transactional
public Node getNodeForID(String id)
{
Node node = null;
try
{
node = curIndexService.getSingleNode( NAME_KEY, id );
}
catch (Exception e) {}
finally {
}
return node;
}
/* Find a node based on its ID using the
* Lucene indexing service
* @param id the id of the node
* @return the node associated with the id if this
* currently exists
*/
@Transactional
public Node findNode(String id)
{
Node node = curIndexService.getSingleNode( NAME_KEY, id );
return node;
}
/* A helper function that sets the properties
* of the start node by iterating
* over the map passed in
* @entity The node which we want to create a relationship to
* @properties a list of properties associated with the node in question
* @properties the properties associated with this object
*/
private <T extends PropertyContainer> T setProperties( T entity,
ConcurrentHashMap<String,Object> properties )
{
//obtain an Iterator for Collection
Iterator<?> itr = properties.keySet().iterator();
//iterate through HashMap extracting and setting
//values for the entity
String key;
Object valueObj;
while(itr.hasNext()) {
key=(String) itr.next();
valueObj=properties.get(key);
if (valueObj!=null)
{
((PropertyContainer) entity).setProperty( key,
(Object)valueObj );
valueObj=null;
}
}
return entity;
}
/* Create a relationship between two nodes
* based on a set of properties, in this
* case the properties include distance
* and other configurable parameters specified
* later
* @param start the beginning node
* @param end the node we want to create a relationship to
* @return the relationship object between the start and the end node
*/
@Transactional
public Relationship createRelationshipBetween( Node start, Node
end,ConcurrentHashMap<String,Object> props )
{
Relationship curRelObj=null;
try
{
curRelObj=setProperties( start.createRelationshipTo(
end, KNOWS ),props );
}
catch (Exception e)
{}
finally {
}
return curRelObj;
}
/* This is the brains behind the graph operations manager
* we specify a start and an end node and then
* calculate the shortest distance between the
* two using the dijkstra algorithm, this algorithm
* As dijkstra traverses the graph, it follows a path of the lowest
known cost,
* keeping a sorted priority queue of alternate path segments along the
way.
* If, at any point, a segment of the path being traversed has a higher
cost than
* another encountered path segment, it abandons the higher-cost path
segment and
* traverses the lower-cost path segment instead. This process
continues until the goal is reached
* @param startNode the name of the starting node
* @param endNode the name of the ending node
* @return the distance between the start and the end nodes as a double
* stored in a hashmap
* @throws none (TBD: add exceptions associated with the neo4j API)
*/
@Transactional
public ConcurrentHashMap<String,Object> calculatePath(String
startNode,String endNode)
{
WeightedPath path = null;
ConcurrentHashMap<String,Object> resultMap = null;
try
{
resultMap=new ConcurrentHashMap<String,Object>();
if (startNode!=null &&!startNode.isEmpty() && endNode!=null &&
!endNode.isEmpty())
path=findCheapestPathWithDijkstra( startNode, endNode );
}
catch (Exception e)
{}
finally {
}
if (path!=null)
{
resultMap.put("length", path.weight());
return (resultMap);
}
else {
return null;
}
}
/* A private helper method
* to use the dijkstra algorithm to find the cheapest
* path based on walking distance
* @param start node
* @param end node
* @return the weighted path containing the least cost which in this case
is length
*/
public WeightedPath findCheapestPathWithDijkstra( String startNode, String
endNode )
{
Node start=findNode(startNode);
Node end=findNode(endNode);
PathFinder<WeightedPath> finder;
WeightedPath path=null;
if (start!=null && end!=null)
{
finder =
GraphAlgoFactory.dijkstra(Traversal.expanderForTypes( KNOWS, Direction.BOTH ),
"length" );
path = finder.findSinglePath( start, end );
}
// Get the weight for the found path
return path;
}
/* Given a path list and the current path
* figure out whether this path is the shortest
* path, do this by sorting the cost for
* all the paths and then checking to see
* if the current path's cost matches the minimum
* for the array
* @param passedInPathList the list of possible simple paths
* @param curPath the potential shortest path
*/
public boolean isPathOfLeastCost(Iterable<WeightedPath>
passedInPathList,WeightedPath curPath)
{
ArrayList<Double> curCostList=new ArrayList<Double>();
Iterator<WeightedPath> curPathItr=passedInPathList.iterator();
while (curPathItr.hasNext())
{
WeightedPath localPath=(WeightedPath)curPathItr.next();
if (localPath!=null)
{
curCostList.add(localPath.weight());
}
}
return (isPathOfLeastCostHelper(curCostList,curPath.weight()));
}
/* Given an arraylist of doubles, sort these and figure
* out the minimum by using a comparator
* @param curCostList the list of costs
* @param curPathCost the cost of the current path
* @return true or false depending on whether the path is of the least cost
*/
private boolean isPathOfLeastCostHelper(ArrayList<Double>
curCostList,Double curPathCost)
{
Collections.sort(curCostList, new Comparator<Double>() {
public int compare(Double o1, Double o2) {
return o1.compareTo(o2);
}
});
Double curMinCost=(Double)curCostList.get(0);
return (curMinCost==curPathCost);
}
/* Given a start node and an end node
* retrieve each of the nodes along the path
* for each node extract the name, latitude
* and the longitude, finally concatenate
* each of these data sets together and then
* return the final result
* @param startNode
* @param endNode
* @return the overall concatenated string in a linkedhashmap
* @throws TBD
*/
@Transactional
public LinkedHashMap<String,Object> getNodesInCheapestPath(String
startNode,String endNode)
{
String result="|";
LinkedHashMap<String,Object> finalMap=new
LinkedHashMap<String,Object>();
WeightedPath curPath=findCheapestPathWithDijkstra(startNode,endNode);
if (curPath!=null)
finalMap.put("length",curPath.length());
Iterator<Node> nodePathItr=null;
if (startNode!=null && !startNode.isEmpty() && endNode!=null &&
!endNode.isEmpty())
{
nodePathItr=curPath.nodes().iterator();
while (nodePathItr.hasNext())
{
Node curNode=nodePathItr.next();
if (curNode!=null)
{
result+=assembleData(curNode);
finalMap.put((String)curNode.getProperty("name"), result);
result="";
}
}
}
return finalMap;
}
/* Given the current result thats obtained as a result of concatenating
* the string of data attach the current node information to this result
* and return this overall string
* hardcoding delimiters for now, will need to change to put
* inside a properties file
* @param curNode the current node
* @return the overall string concatenated with the name/lat/long of the
current node
*/
private String assembleData(Node curNode)
{
Double latitude;
Double longitude;
String name;
String tmpResult="";
//first check the error condition and return this
if (curNode==null)
return errorString;
else
{
name=(String)curNode.getProperty("name");
latitude=(Double)curNode.getProperty("latitude");
longitude=(Double)curNode.getProperty("longitude");
if (name==null || latitude==null || longitude==null)
return errorString;
tmpResult+=latitude.toString()+","+longitude.toString()+"|";
}
//logger.error("GraphManager::assembleData got result="+tmpResult);
return tmpResult;
}
}
package com.hbc.locationservices.data.parser;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.neo4j.graphalgo.WeightedPath;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.springframework.beans.factory.annotation.Autowired;
import com.hbc.locationservices.graph.GraphManager;
import com.hbc.locationservices.graph.NodeType;
/* The responsibility of this class is to parse the data
* contained in the google earth xml file, we wont
* load the xml dom into memory
* due to performance issues, for now we'll use regular
* expressions to read through all of the data
* and extract the lat/long coordinates as well
* as distances between each of the markers
* The eventual goal is to feed this data into
* a dijkstra like algorithm that will calculate
* shortest distance between the user's current
* position and a set of attractions inside
* the theme park
*/
public class DataParser
{
private File curFile;
private FileInputStream fis;
private DataInputStream dis;
private BufferedInputStream bis;
private final String LATITUDE_KEY="latitude";
private final String NODETYPE_KEY="nodetype";
private final String LONGITUDE_KEY="longitude";
private final String LENGTH_KEY="length";
private final String NAME_KEY="name";
private final Pattern latPattern =
Pattern.compile(".*<latitude>(-?[0-9]+\\.[0-9]+)\\</latitude>.*");
private final Pattern longPattern =
Pattern.compile(".*<longitude>(-?[0-9]+\\.[0-9]+)\\</longitude>.*");
private final Pattern valuePattern =
Pattern.compile(".*<value>(poi|tr|ts)</value>");
private final Pattern routeMarkerPattern =
Pattern.compile(".*<name>((RM[0-9]+|\\w+))</name>.*");
private final Pattern pathMarkerPattern =
Pattern.compile(".*<name>(\\w?+[0-9]+|\\w+)\\<\\-\\>(\\w?+[0-9]+|\\w+)</name>");
private final Pattern distancePattern =
Pattern.compile(".*<description>([0-9]+\\.?[0-9]+)\\s?+(meters|Meters)\\</description>.*");
private final Pattern
placemarkBeginPattern=Pattern.compile(".*<Placemark>.*");
private final Pattern
placemarkEndPattern=Pattern.compile(".*</Placemark>.*");
private static final Log logger = LogFactory.getLog(DataParser.class);
private String sourceNode;
private String destinationNode;
private GraphManager curGraphManager;
private ConcurrentHashMap<String,Object> nodeProps;
public void setCurGraphManager(GraphManager curGraphManager)
{
this.curGraphManager=curGraphManager;
}
public GraphManager getCurGraphManager()
{
return curGraphManager;
}
public void setCurFile(File curFile)
{
this.curFile=curFile;
}
public File getCurFile()
{
return curFile;
}
/* This is where the bulk of the work happens
* Parse the xml google earth file line by line
* and create regular expressions to match
* each type of data encountered
* Data Expressions include:
* 1) RM3 , this symbolizes a route marker
* when we encounter the following regular expression
* <name>RM30</name>
* this we then need to read lat long coordinates
* symbolized by the regular expressions shown below
* Longitude=><longitude>-81.55063111362659</longitude>
* Latitude=><latitude>28.37394755841926</latitude>
* 2)66<->31, this type of marker is indicated by the regular expression
* below:
* <name>66&lt;-&gt;31</name>
* In this scenario we need to do the following:
* 1) we need to read the distance from the following expression
* Description=><description>31.7 meters</description>
* 2) If the source node already exists in the list of markers
* already read we need to get the source node's neighbors
* and add this neighbor and the distance
* we stick to text parsing for now since
* reading an object model from a large xml file
* will incur performance overhead
* @param none
* @return none
* @throws none
*/
public void parseFile()
{
Matcher beginPlacemarkerMatcherObj;
try {
fis = new FileInputStream(curFile);
// Here BufferedInputStream is added for fast reading.
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
// dis.available() returns 0 if the file does not have
more lines.
String line;
while (dis.available() != 0) {
// this statement reads the line from the file and
print it to
// the console.
//System.out.println(dis.readLine());
line=dis.readLine();
//logger.error("the outer level line read="+line);
beginPlacemarkerMatcherObj=placemarkBeginPattern.matcher(line);
if (beginPlacemarkerMatcherObj.matches())
{
createAllNodes(dis);
}
}
// dispose all the resources after using them.
fis.close();
bis.close();
dis.close();
parseFileForRelationships();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/* This is where the bulk of the work happens
* Parse the xml google earth file line by line
* and create regular expressions to match
* each type of data encountered
* Data Expressions include:
* 1) RM3 , this symbolizes a route marker
* when we encounter the following regular expression
* <name>RM30</name>
* this we then need to read lat long coordinates
* symbolized by the regular expressions shown below
* Longitude=><longitude>-81.55063111362659</longitude>
* Latitude=><latitude>28.37394755841926</latitude>
* 2)66<->31, this type of marker is indicated by the regular expression
* below:
* <name>66&lt;-&gt;31</name>
* In this scenario we need to do the following:
* 1) we need to read the distance from the following expression
* Description=><description>31.7 meters</description>
* 2) If the source node already exists in the list of markers
* already read we need to get the source node's neighbors
* and add this neighbor and the distance
* we stick to text parsing for now since
* reading an object model from a large xml file
* will incur performance overhead
* @param none
* @return none
* @throws none
*/
public void parseFileForRelationships()
{
Matcher beginPlacemarkerMatcherObj;
try {
fis = new FileInputStream(curFile);
// Here BufferedInputStream is added for fast reading.
bis = new BufferedInputStream(fis);
dis = new DataInputStream(bis);
// dis.available() returns 0 if the file does not have
more lines.
String line;
while (dis.available() != 0) {
// this statement reads the line from the file and
print it to
// the console.
//System.out.println(dis.readLine());
line=dis.readLine();
//logger.error("the outer level line read="+line);
beginPlacemarkerMatcherObj=placemarkBeginPattern.matcher(line);
if (beginPlacemarkerMatcherObj.matches())
{
createRelationshipsBetweenNodes(dis);
}
}
// dispose all the resources after using them.
fis.close();
bis.close();
dis.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/* Given a datainputstream and a line check to see
* if we've read placemarker information, if so read
* the entire contents, we want to match for each of the
* characteristics of the node including the name, latitude
* longitude but potentially more in the future
* @param line the line read in
* @param dis the datainputstream
*/
private void createAllNodes(DataInputStream dis)
{
String line=" ";
try {
while (dis.available()!=0)
{
//if we are here we want to keep reading lines
//till we have extracted all the characteristics
//of the node
line=dis.readLine();
matchLat(line);
matchLong(line);
matchRouteMarker(line);
matchValue(line);
if (matchPlacemarkerEnd(line))
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* Given a datainputstream and a line check to see
* if we've read placemarker information, if so read
* the entire contents, we want to match for each of the
* characteristics of the node including the name, latitude
* longitude but potentially more in the future
* @param line the line read in
* @param dis the datainputstream
*/
private void createRelationshipsBetweenNodes(DataInputStream dis)
{
String line=" ";
try {
while (dis.available()!=0)
{
//if we are here we want to keep reading lines
//till we have extracted all the characteristics
//of the node
line=dis.readLine();
matchPathMarker(line);
matchDistanceMarker(line);
if (matchPlacemarkerEnd(line))
break;
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
/* A method to figure out whether the current
* regular expression matches a route marker pattern
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchRouteMarker(String str) {
Matcher curMatcher=routeMarkerPattern.matcher(str);
String tmpStr;
if (curMatcher.matches())
{
nodeProps=new ConcurrentHashMap<String,Object>();
tmpStr=curMatcher.group(1);
if (tmpStr!=null && !tmpStr.isEmpty())
{
nodeProps.put(NAME_KEY, tmpStr);
}
}
return routeMarkerPattern.matcher(str).matches();
}
/* A method to figure out whether the current
* regular expression matches a place marker end pattern
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchPlacemarkerEnd(String str) {
Matcher placemarkerEndMatcher=placemarkEndPattern.matcher(str);
String name=(String)nodeProps.get(NAME_KEY);
Node tmpNode=null;
if (placemarkerEndMatcher.matches())
{
if (name!=null && !name.isEmpty())
{
tmpNode=curGraphManager.createNode(nodeProps);
nodeProps.clear();
//logger.error("Just created a node called
"+name);
}
}
return placemarkEndPattern.matcher(str).matches();
}
/* A method to figure out whether the current
* regular expression matches a latitude pattern
* Longitude=><longitude>-81.55063111362659</longitude>
* Latitude=><latitude>28.37394755841926</latitude>
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchLat(String str) {
Matcher tmpObj=latPattern.matcher(str);
Double val;
if (nodeProps==null)
nodeProps=new ConcurrentHashMap<String,Object>();
if (tmpObj.matches())
{
val= new Double(tmpObj.group(1));
nodeProps.put(LATITUDE_KEY, val);
}
return latPattern.matcher(str).matches();
}
/* A method to figure out whether the current
* regular expression matches a Value pattern
* Value=><Value>[poi|wr|ts|tr]*
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchValue(String str) {
Matcher tmpObj=valuePattern.matcher(str);
String val="";
if (nodeProps==null)
nodeProps=new ConcurrentHashMap<String,Object>();
if (tmpObj.matches())
{
val=(String)tmpObj.group(1);
if (val.equalsIgnoreCase("tr"))
nodeProps.put(NODETYPE_KEY,
NodeType.TRAIN_WAYPOINT.ordinal());
else if (val.equalsIgnoreCase("ts"))
nodeProps.put(NODETYPE_KEY,
NodeType.TRAIN_STOP.ordinal());
else if (val.equalsIgnoreCase("wr"))
nodeProps.put(NODETYPE_KEY,
NodeType.WAYPOINT.ordinal());
else
nodeProps.put(NODETYPE_KEY,
NodeType.POINT_OF_INTEREST.ordinal());
}
return latPattern.matcher(str).matches();
}
/* A method to figure out whether the current
* regular expression matches a longitude pattern
* Longitude=><longitude>-81.55063111362659</longitude>
* Latitude=><latitude>28.37394755841926</latitude>
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchLong(String str) {
Matcher tmpObj=longPattern.matcher(str);
Double val;
if (nodeProps==null)
nodeProps=new ConcurrentHashMap<String,Object>();
if (tmpObj.matches())
{
val= new Double(tmpObj.group(1));
nodeProps.put(LONGITUDE_KEY, val);
}
return longPattern.matcher(str).matches();
}
/* A method to figure out whether the current
* regular expression matches a path marker pattern
* <name>66&lt;-&gt;31</name>
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchPathMarker(String str) {
Matcher curMatcherObj=pathMarkerPattern.matcher(str);
String group2Str;
String group1Str;
if (curMatcherObj.matches())
{
group1Str=curMatcherObj.group(1);
if (containsOnlyNumbers(group1Str))
{
sourceNode="RM"+group1Str;
}
else
sourceNode=group1Str;
group2Str=curMatcherObj.group(2);
if (containsOnlyNumbers(group2Str))
{
destinationNode="RM"+group2Str;
}
else
destinationNode=group2Str;
}
return pathMarkerPattern.matcher(str).matches();
}
/**
* This method checks if a String contains only numbers
* @param str the string to be processed
* @return true or false depending on whether a string only contains numbers
* @throws none
*/
private boolean containsOnlyNumbers(String str) {
//It can't contain only numbers if it's null or empty...
if (str == null || str.length() == 0)
return false;
for (int i = 0; i < str.length(); i++) {
//If we find a non-digit character we return false.
if (!Character.isDigit(str.charAt(i)))
return false;
}
return true;
}
/* A method to figure out whether the current
* regular expression matches a distance pattern
* Description=><description>31.7 meters</description>
* if so we retrieve the source and destination nodes
* and create a relationship between them
* @str the string to be passed in
* @return true or false depending on whether the pattern is a match
* @throws None
*/
private boolean matchDistanceMarker(String str) {
Node sourceNodeEntry;
Node destNodeEntry;
Double distance;
ConcurrentHashMap<String,Object> relProps;
Matcher distanceMatcher = distancePattern.matcher(str);
Boolean result=distanceMatcher.matches();
if (result)
{
sourceNodeEntry=curGraphManager.findNode(sourceNode);
destNodeEntry=curGraphManager.findNode(destinationNode);
relProps = new ConcurrentHashMap<String,Object>();
distance=Double.parseDouble(distanceMatcher.group(1));
relProps.put(LENGTH_KEY, distance);
if (sourceNodeEntry!=null && destNodeEntry!=null)
{
Relationship
curRelObj=curGraphManager.createRelationshipBetween(sourceNodeEntry,
destNodeEntry, relProps);
//logger.error("Created a relationship between
"+sourceNodeEntry.getProperty("name")+" and dest
node="+destNodeEntry.getProperty("name")+" with
distance="+curRelObj.getProperty("length"));
sourceNode="";
destinationNode="";
sourceNodeEntry=null;
destNodeEntry=null;
}
}
return distancePattern.matcher(str).matches();
}
}
_______________________________________________
Neo4j mailing list
User@lists.neo4j.org
https://lists.neo4j.org/mailman/listinfo/user