Search This Blog

Saturday 5 May 2018

Neo4j - Extracting relationship properties

Neo4j relations can also have their own properties. In the sample movie database, the ACTED_IN relationship has a roles property, which can take multiple values (An actor may play multiple roles in a Movie).
Here I take a look at accessing these values from Java.
Consider the below java code:
public Map<String, Actor> getActorRolesInMovie(String movieName, int released) {
    try (Transaction tx = graphDb.beginTx()) {
      Map<String, Object> params = new HashMap<>();
      params.put("mName", movieName);
      params.put("releasedYear", released);
      Result result = graphDb.execute(
          "MATCH (a:Person)-[r:ACTED_IN]->(m:Movie) WHERE m.title={mName} and m.released={releasedYear} RETURN a,r",
          params);
      if (!result.hasNext()) {
        return null;
      }
      Map<String, Actor> actorsRoles = new HashMap<>();
      while (result.hasNext()) {
        Map<String, Object> record = result.next();
        Actor extractActor = extractActor((Node) record.get("a"));
        Relationship relationshipProxy = (Relationship) record.get("r");
        String[] roles = (String[]) relationshipProxy.getProperty("roles");
        for (String role : roles) {
          actorsRoles.put(role, extractActor);
        }
      }
      return actorsRoles;
    }
  }
In this code,
  1. the Cypher query retrieves the relation and the person node. In Java the relation is cast to a Relationship instance. (What we have is an instance of RelationshipProxy). 
  2. On that instance we execute the getProperty method to return the roles property values. 
  3. As it is a string array, we iterate over it and retrieve all the values for that Actor.
The output when tested for movie "Cloud Atlas" is as below:
Jim Broadbent acted as Timothy Cavendish
Tom Hanks acted as Isaac Sachs
Jim Broadbent acted as Captain Molyneux
Hugo Weaving acted as Nurse Noakes
Halle Berry acted as Jocasta Ayrs
Halle Berry acted as Ovid
Tom Hanks acted as Zachry
Hugo Weaving acted as Haskell Moore
Jim Broadbent acted as Vyvyan Ayrs
Hugo Weaving acted as Boardman Mephi
Hugo Weaving acted as Tadeusz Kesselring
Tom Hanks acted as Dermot Hoggins
Hugo Weaving acted as Bill Smoke
Halle Berry acted as Luisa Rey
Hugo Weaving acted as Old Georgie
Halle Berry acted as Meronym
Tom Hanks acted as Dr. Henry Goose
As seen several actors have multiple roles in the movie. The getProperty method throws a NotFoundException when the roles value is not provided. To avoid this
        String[] roles = (String[]) relationshipProxy.getProperty("roles", null);
        if (roles != null) {
          for (String role : roles) {
            actorsRoles.put(role, extractActor);
          }
        }
Here the method takes a default value, which is returned if the Relation does not have any value for the property. There is also a way to find all the properties present
public void displayAllProperties() {
    try (Transaction tx = graphDb.beginTx()) {
      Result result = graphDb.execute(
          "MATCH (a:Person)-[r:REVIEWED]->(m:Movie) "
          + "WHERE a.name= 'Jessica Thompson' and m.title='Jerry Maguire' "
          + "RETURN r "
          + "LIMIT 1");
      if(result.hasNext()) {
        Relationship relationshipProxy = (Relationship) result.next().get("r");
        Map<String, Object> values = relationshipProxy.getAllProperties();
        values.entrySet().forEach(value -> System.out.println(value.getKey() + " has value " + value.getValue()));
      }
    }
      
  }
The above code will return all the properties:
summary has value You had me at Jerry
rating has value 92

2 comments: