0
votes

I just found the Unwind method on the .NET client from another SO answer. It works like a charm when adding nodes. But how do you add relations using it? I thought it would be straightfoward and wrote this:

client.Cypher
.Unwind(idMap, "idMap")
.Match("n1", "n2")
.Where("n1.Id=idMap.Owner")
.AndWhere("n2.Id=idMap.User")
.Create("n1-[:ONE_RELATION]->n2")
.ExecuteWithoutResults()

idMap is a list where I have a Owner and User as GUIDs. I also tried to change those to string with no luck.

The error I get is

System.Threading.Tasks.TaskCanceledException: A task was canceled.
at Neo4jClient.GraphClient.Neo4jClient.IRawGraphClient.ExecuteCypher(CypherQuery query) in D:\temp\384a765\Neo4jClient\GraphClient.cs:line 1041 at Neo4jClient.Cypher.CypherFluentQuery.ExecuteWithoutResults() in D:\temp\384a765\Neo4jClient\Cypher\CypherFluentQuery.cs:line 361 at [email protected](FSharpList1 x) in C:\dev\git\Sfag\src\Sfag.GraphView\Script.fsx:line 62 at Microsoft.FSharp.Primitives.Basics.List.iter[T](FSharpFunc2 f, FSharpList1 x) at Microsoft.FSharp.Collections.ListModule.Iterate[T](FSharpFunc2 action, FSharpList`1 list) at FSI_0003.saveState(State state) in C:\dev\git\Sfag\src\Sfag.GraphView\Script.fsx:line 250 at .$FSI_0005.main@() in C:\dev\git\Sfag\src\Sfag.GraphView\Script.fsx:line 265

which doesn't help a lot. Anyone that know what I am doing wrong here? What I can read from the docs the actual neo4j API should allow this: http://neo4j.com/docs/stable/cypherdoc-utilizing-data-structures.html, http://neo4j.com/docs/stable/query-unwind.html

UPDATE

With larger batch size I get another error:

System.ApplicationException: Received an unexpected HTTP status when executing the request.

The response status was: 500 Server Error

The response from Neo4j (which might include useful detail!) was:
at Neo4jClient.GraphClient.Neo4jClient.IRawGraphClient.ExecuteCypher(CypherQuery query) in D:\temp\384a765\Neo4jClient\GraphClient.cs:line 1041 at Neo4jClient.Cypher.CypherFluentQuery.ExecuteWithoutResults() in D:\temp\384a765\Neo4jClient\Cypher\CypherFluentQuery.cs:line 361 at [email protected](String tag) in C:\dev\git\Sfag\src\Sfag.GraphView\Script.fsx:line 127

at Microsoft.FSharp.Primitives.Basics.List.mapToFreshConsTail[a,b](FSharpList1 cons, FSharpFunc2 f, FSharpList1 x) at Microsoft.FSharp.Primitives.Basics.List.map[T,TResult](FSharpFunc2 mapping, FSharpList1 x) at Microsoft.FSharp.Collections.ListModule.Map[T,TResult](FSharpFunc2 mapping, FSharpList`1 list) at .$FSI_0003.main@() in C:\dev\git\Sfag\src\Sfag.GraphView\Script.fsx:line 142

1
Hi, my response to the answer here may help you stackoverflow.com/questions/33474497/…Christophe Willemsen
That should do it, but isn't that exactly what I do?Tomas Jansson
Or does it have to be a list of anonymous objects? I'm using F# so I really want things typed :)Tomas Jansson

1 Answers

0
votes

Ok, so it looks like my problem was that I didn't have an index on Id property. I really don't understand why that makes a difference, of course it would on speed, but crash? Keeping this question here for others to see.

I also added tags to the node match to narrow down the set of data to search for a match.

The ending F# code looks something like this:

Create index:

let createIndexes (client:GraphClient) = 
    client.Cypher
        .Create("INDEX ON :Enhet(Id)")
        .ExecuteWithoutResults()

Connect list of id pairs:

let connect2IdNodesList<'T  when 'T:equality> (client:GraphClient) relationType (idsToConnect: TwoIds list) = 
    let batches = List.batchesOf 10000 idsToConnect
    let startNodeType,endNodeType = getNodeTypesForRelation relationType
    let node1Str = sprintf "(n1:%s)" startNodeType
    let node2Str = sprintf "(n2:%s)" endNodeType
    batches |> List.iter (fun x -> 
                    client.Cypher
                        .Unwind(x, "idMap")
                        .Match(node1Str, node2Str)
                        .Where("n1.Id=idMap.Owner AND n2.Id=idMap.User")
                        .Create(sprintf "n1-[:%s]->n2" (relationTypeToString relationType))
                    .ExecuteWithoutResults()
            )

The batchesOf creates batches of the input just in case.