Wednesday, May 9, 2012

Neo4J and Geospatial APIs (Killer)

If anyone looking for any kinda solutions to their searches(any kinda) that involves huge amount of data based on geographic locations, i would suggest to have a look at neo4j's geospatial APIs.It has some awesome APIs which are both efficient and easy to use..Below i am gonna provide a lil bit about Neo4j and its geospatial API example.

Neo4j :- Its a graph database, which is based on the basic graph algorithms.It really makes the complex stuffs more efficient and easily maintain as well. Below are some Examples that describes Neo4j more pro-grammatically.


Using Neo4j in Java application (APIs) – IMDB Example

 

Two most basic concepts to create a Graph – Node (Vertex) and Relationships (Edge).

Nodes:-
Nodes are often used to represent entities (Have Properties).

Relationships:-
Relationships are the relation between two entities (Nodes).
public enum RelTypes implements RelationshipType
{
    ACTS_IN
}
 

1)      Starting and stopping Graph Database :
      Start the Database:
      GraphDatabaseService graphDb = new EmbeddedGraphDatabase( DB_PATH );
Make sure Database is shutdown after use (define a shutdown hook):
registerShutdownHook(graphDb);
private static void registerShutdownHook( final GraphDatabaseService graphDb )
{
    Runtime.getRuntime().addShutdownHook( new Thread()
    {
        @Override
        public void run()
        {
            graphDb.shutdown();
        }
    } );
}

2)      Creating a Node :

Node neo = graphDb.createNode();
neo.setProperty("name", "Neo Anderson");
neo.setProperty("age", 29);
  index.add(neo, "name", neo.getProperty("name")); // Indexing for search
Node movieNode = graphDb.createNode();
movieNode.setProperty("title", "Matrix");
  movieNode.setProperty("year", 1999);
  index.add(movieNode, "title", movieNode.getProperty("title"));


  Creating Relationship:-
  //Role
  Relationship rel = neo.createRelationshipTo(movieNode, RelTypes.ACTS_IN);
  rel.setProperty("rating", "box office");

3)      Searching a Node :
private static Node getSingleNode(String key, String value) {
      IndexHits hits = index.get(key, value);//key = name,value = “Neo”
           for (Node node : hits) {
               System.out.println("node ----->"+node.getId());
               return node;
           }
           return null;
   }



Geo-spatial Code

This example is based on a requirement that i had to search a business in any particular location using Latitude and Longitude of this Business location.

I have attached the work code fully below, please go though its APIs from neo4j.org website else lemme know in case you find any difficulties.



Example :

public class searchBusiness {

    private static GraphDatabaseService graphdb;
    private static Index index;
    private static Index searchIndex;
    private static SpatialDatabaseService sdb;
    private static Layer layer;
    public static final double earthRadiusInKm = 6371;
   
    public static void main(String[] mainStr){

        System.out.println("start ------------main----------->");
        graphdb = new EmbeddedGraphDatabase("target/neo-4j");
        GlobalGraphOperations globalDB = GlobalGraphOperations.at(graphdb);       
        Iterable nodeList = globalDB.getAllNodes();
        for(Node nodeDB : nodeList){
            System.out.println("nodeDB id ------>"+nodeDB.getId());
            for(String propName : nodeDB.getPropertyKeys()){
                System.out.print("propName : value =>>"+propName+":"+nodeDB.getProperty(propName) + " : ");
            }
        }
       
        //Get Data
        run("KFC 13.67", 13.67, 55.6, 2.0);
       
    }
   
    static void run(String bName, double lon, double lat, double distance )
    {
       
        Coordinate coord = new Coordinate(lon, lat);

        com.vividsolutions.jts.geom.Envelope createEnv = OrthodromicDistance.suggestSearchWindow(coord, distance);
        //Envelope createEnv = suggestSearchWindow(coord, distance);
       
        ExecutionEngine engine = new ExecutionEngine( graphdb );   

        System.out.println("start ---------search-------------->");
        long currentTimeInMills = System.currentTimeMillis();
        Map params = new HashMap();
        params.put( "name", bName );
        params.put( "minlong", createEnv.getMinX() );
        params.put( "maxlong", createEnv.getMaxX() );
        params.put( "minlat", createEnv.getMinY() );
        params.put( "maxlat", createEnv.getMaxY() );
       
        String strQuery = "start n=node:coordinate(business_name= {name})" +
                          " where (n.latitude >= {minlat} and n.latitude <= {maxlat}) and (n.longitude >= {minlong} and n.longitude <= {maxlong})" +
                          " return n";//"start n=node(*) return n";
       
        ExecutionResult result = engine.execute( strQuery, params );

        System.out.println("total time taken for search ----------->"+(System.currentTimeMillis()-currentTimeInMills));
        System.out.println( result );

        List columns = result.columns();
        System.out.println( columns );
       
        Iterator n_column = result.columnAs( "n" );
        for ( Node node : asIterable( n_column ) )
        {
            for(String propName : node.getPropertyKeys()){
                System.out.print("propName =>>"+node.getProperty(propName) + " : ");
            }
            System.out.println();
        }       
        graphdb.shutdown();
    }
   

    public static double calculateDistance(Coordinate reference, Coordinate point) {
        // TODO use org.geotools.referencing.GeodeticCalculator?
       
        // d = acos(sin(lat1) * sin(lat2) + cos(lat1) * cos(lat2) * cos(lon2 - lon1)) * R
        double distanceInKm = Math.acos(Math.sin(Math.toRadians(reference.y)) * Math.sin(Math.toRadians(point.y))
                + Math.cos(Math.toRadians(reference.y)) * Math.cos(Math.toRadians(point.y))
                * Math.cos(Math.toRadians(point.x) - Math.toRadians(reference.x)))
                * earthRadiusInKm;
        return distanceInKm;
    }
   
   
    private static Coordinate[] makeCoordinateDataFromTextFile(String textFile) {
        CoordinateList data = new CoordinateList();
        try {
            BufferedReader reader = new BufferedReader(new FileReader(textFile));
            Coordinate origin = new Coordinate(13.0, 55.6);
            String line;
            int row = 0;
            while ((line = reader.readLine()) != null) {
                int col = 0;
                for (String character : line.split("")) {
                    if (col > 0 && !character.matches("\\s")) {
                        //System.out.println((origin.x + (double) col / 100.0) +":"+ (origin.y - (double) row / 100.0));
                        Coordinate coordinate = new Coordinate(origin.x + (double) col / 100.0, origin.y - (double) row / 100.0);
                        data.add(coordinate);
                    }
                    col++;
                }
                row++;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return data.toCoordinateArray();
    }
   
   
}