OGM Custom IdStrategy - Cannot merge node using null property value for id

(Kevin Amick) #1

Hi all,

I've been using neo4j for awihle now but just started taking advantage of the awesome ogm java library. Ive been struggling over an issue for the past couple days and I cannot for the life of me figure it out. I've finally decided to break down and seek advice.

Using the Neo4j OGM library, I'm converting json documents into POJOs into Nodes / Relationships. I have nodes with multiple relationships. These connections are many to many.

It was working great until I realized I need RelationshipEntities to be uniquely identified so they are not duplicated. So I decided to use an implementation of IdStrategy to uniquely identify these relationships.

The strategy hashes on unique strings from the start and end node.

public class IdGenerator implements IdStrategy {
    @Override
    public Long generateId(Object o) {
        return Hashing.sha256()
                .newHasher()
                .putString(o.toString(), Charsets.UTF_8)
                .hash().asLong();
    }
}
@RelationshipEntity(label="Relationship")
public class Relationship implements Entity {
    @Id @GeneratedValue(strategy = IdGenerator.class)
    private Long id;
    ...
}

This throws: Cannot merge node using null property for id when executing the following:

DEBUG o.n.o.d.bolt.request.BoltRequest - Request: UNWIND {rows} as row MERGE (n:Query{id: row.props.id}) SET n=row.props RETURN row.nodeRef as ref, ID(n) as id, {type} as type with params ...

I hope this is enough information, please ask for more if necessary and I will do my best to elaborate.

Any help is greatly appreciated.

0 Likes

(Kevin Amick) #2

I've discovered that neo4j doesn't like negatives values for id's. The sha256 algorithm returns negative values due to the overflow. So i've solved this by returning the absolute value of the hash. Im pretty sure this increases the chance of collision, but don't think it's anything to worry about.

0 Likes

(Jiropole) #3

Interesting solution, Kevin. I haven't needed to do anything custom, as the mapping of relationship entities is working fine with the default @Id @GeneratedValue. I wonder why the default behavior (to use the native rel ids) didn't work for you. However, I don't think I've tested it with many:many relationships. Glad you solved it!

0 Likes

(Kevin Amick) #4

Whats happening is I'm consuming a stream of activity. This activity can have events that already exist in the db with updated properties. So I need to be able to identify if a relationship between two nodes exists in order to update or create a new one. Hence hashing on the start and end nodes.

0 Likes

(Jiropole) #5

Ah, you must be using projections, to get those negative ids. Yes, I nearly went down that road myself, and briefly tried the solution of simply concatenating the ids of the nodes at either end (your hash approach is way cooler). However, I backed out and went down a different road, as I found a way to do everything I need with actual objects in the DB (along with a plugin to do some things that would have been incredibly vexing in cypher).

0 Likes