Search This Blog

Tuesday 29 December 2015

Neo4j - Select with parameters

In the previous post we worked on executing a simple select query - one that selected all the Person records in our database. In this post  I decided to work on parameterized retrieval. I decided to
execute the below query:
MATCH (a:Person{name: "Keanu Reeves"})-[:ACTED_IN]->(m:Movie) RETURN a,m
Only instead of hardcoding 'Keanu Reeves', I would like my method to work for different actors.
Accordingly I wrote a modified version of the code, that will fetch Actor, and its associated movies:
public Actor getActor(String actorName) {
    try (Transaction tx = graphDb.beginTx()) {
      Result result = graphDb.execute("MATCH (a:Person{name: '" + actorName + "'})-[:ACTED_IN]->(m:Movie) RETURN a,m");
      if (!result.hasNext()) {
        return null;
      }
      Actor actor = null;
      Set<Movie> movies = new HashSet<>();
      boolean collectedActor = false;
      while (result.hasNext()) {
        Map<String, Object> row = result.next();
        if (!collectedActor) {
          Node nodeProxy = (Node) row.get("a");
          actor = extractActorValues(nodeProxy);
          collectedActor = true;
        }
        Node nodeProxy = (Node) row.get("m");
        Movie movie = extractMovie(nodeProxy);
        movies.add(movie);
      }
      actor.setMovies(movies);
      return actor;
    }
  }
The above code is near identical to our previous example. Every row in the result set returns a Map which has one Node representing the actor and the other the movie. As all records refer the same Actor, we only needed to process one of the rows for it. The movies were processed and placed in a Set.
The same code can be written better when using parameter Maps.
   Map<String, Object> params = new HashMap<>();
   params.put( "_name", actorName );
   Result result = graphDb.execute("MATCH (a:Person{name: {_name}})-[:ACTED_IN]->(m:Movie) RETURN a,m",params);
In this we have placed the params in a Map and then used the parameters in our Cypher query. This will work identical to the code above. I felt using the double brace brackets made the query less readable. There is another way to write the same query:
   Map<String, Object> params = new HashMap<>();
   params.put("_name", actorName);
   Result result = graphDb.execute("MATCH (a:Person)-[:ACTED_IN]->(m:Movie) WHERE a.name={_name} RETURN a,m",
      params);
This works too. Here I have used a where clause to specify the condition.
Some points of note:
  1. Once we start a Neo4j instance by connecting to a Neo4j database, the database gets locked by the server. On my machine I looked in the data folder and found the below files access times had changed when I started the server: 
  2. At this point if I tried to open another connection - like connecting from my code, I get an exception:
    Caused by: org.neo4j.kernel.StoreLockException: Store and its lock file has been 
    locked by another process: E:\neo4jData\21Dec2015\store_lock. Please ensure no 
    other process is using this database, and that the directory is writable 
    (required even for read-only access)
    
    This means that exclusive access is needed.

No comments:

Post a Comment