0
votes

I have a use case where I create a new relationship every time a user sees a photo like this:

var dateParams = new { Date = DateTime.Now.ToString() };

            graphClient.Cypher
                 .Match("(user:User), (photo:Photo)")
                 .Where((UserEntity user) => user.Id == userId)
                 .AndWhere((PhotoEntity photo) => photo.Id == photoId)
                 .CreateUnique("user-[:USER_SEEN_PHOTO {params}]->photo")
                 .WithParam("params", dateParams)
                 .ExecuteWithoutResults();

With many concurrent users this will happen very very often so I need to be able too queue a number of write operations and execute them together at once. Unfortunately I havn't been able to find good info about how to do this in the most efficient way with Neo4jClient so all suggestions would be very appreciated :)

--- UPDATE ---

So I tried different combinations but I still havn't found anything which works. Below query gives me a "PatternException: Unbound pattern!"?

  var query = graphClient.Cypher;
            for (int i = 0; i < seenPhotosList.Count; i++)
            {
                query = query.CreateUnique("(user" + i + ":User {Id : {userId" + i + "} })-[:USER_SEEN_PHOTO]->(photo" + i + ":Photo {Id : {photoId" + i + "} })")
                    .WithParam("userId" + i, seenPhotosList[i].UserId)
                    .WithParam("photoId" + i, seenPhotosList[i].PhotoId);
            }
            query.ExecuteWithoutResults();

I also tried to change CreateUnique to Merge and that query executes without exception but is creating new nodes instead of connecting the existing ones?

 var query = graphClient.Cypher;
            for (int i = 0; i < seenPhotosList.Count; i++)
            {
                query = query.Merge("(user" + i + ":User {Id : {userId" + i + "} })-[:USER_SEEN_PHOTO]->(photo" + i + ":Photo {Id : {photoId" + i + "} })")
                    .WithParam("userId" + i, seenPhotosList[i].UserId)
                    .WithParam("photoId" + i, seenPhotosList[i].PhotoId);
            }
            query.ExecuteWithoutResults();
2

2 Answers

1
votes

I set up 5 types of relationships using Batch Insert. It runs extremely fast, but not sure how you'd manage the interupt in a multiuser environment. You need to know the nodeIDs in advance and then create a string for the API request that looks like this ...

[{"method":"POST","to":"/node/222/relationships","id":222,"body":{"to":"26045","type":"mother"}},
{"method":"POST","to":"/node/291/relationships","id":291,"body":{"to":"26046","type":"mother"}},
{"method":"POST","to":"/node/389/relationships","id":389,"body":{"to":"26047","type":"mother"}},
{"method":"POST","to":"/node/1031/relationships","id":1031,"body":{"to":"1030","type":"wife"}},
{"method":"POST","to":"/node/1030/relationships","id":1030,"body":{"to":"1031","type":"husband"}},
{"method":"POST","to":"/node/1034/relationships","id":1034,"body":{"to":"26841","type":"father"}},
{"method":"POST","to":"/node/34980/relationships","id":34980,"body":{"to":"26042","type":"child"}}]

I also broke this down into reasonable sized iterative requests to avoid memory challenges. But the iterations run very fast for setting up the strings needed. Getting nodeIDs also required iterations because Neo4j limits the number of nodes returned to 1000. This is a shortcoming of Neo4j that was designed based on visualization concerns (who can study a picture with 10000 nodes?) rather than coding issues such as those we are discussing.

0
votes

I do not believe Neo4j/cypher has any built-in way of performing what you are asking for. What you could do is build something that does this for you with a queueing system. Here's a blog post on doing scalable writes in Ruby which is something that you could implement in your language to handle doing batch inserts/updates.