繁体   English   中英

c#类图到Neo4j

[英]c# class graph to Neo4j

我希望将内存中的普通C#类转换为neo4j数据库。 (类类型是节点类型,并且是从节点派生的,节点具有“ linkedTo”的列表)

我想知道是否还有其他更聪明的方法,而不是编写一系列的密码查询来创建节点和属性,然后将它们与关系链接起来。

例如,我可以将它们序列化为json,然后将其直接导入neo4j吗? 我知道C#neo4j驱动程序中的.unwind函数在这里可能会有所帮助,但看不到其用法的好示例,因此需要分别匹配和创建关系

是否有执行此操作的最佳方法? 我预计大约有5万个节点

好的,首先,我正在为此使用Neo4jClient,并使用以下命令向数据库添加了INDEX

CREATE INDEX ON :MyClass(Id)

这对于它的工作方式非常重要,因为它可以更快地插入数据。

我有一堂课:

public class MyClass
{
    public int Id {get;set;}
    public string AValue {get;set;}
    public ICollection<int> LinkToIds {get;set;} = new List<int>();
}

其中有一个我将要键入的Id和一个string属性-正因为如此。 LinkToIds属性是此实例链接到的ID的集合。

为了生成MyClass实例,我正在使用此方法随机生成它们:

private static ICollection<MyClass> GenerateMyClass(int number = 50000){
    var output = new List<MyClass>();

    Random r = new Random((int) DateTime.Now.Ticks);

    for (int i = 0; i < number; i++)
    {
        var mc = new MyClass { Id = i, AValue = $"Value_{i}" };
        var numberOfLinks = r.Next(1, 10);  
        for(int j = 0; j < numberOfLinks; j++){
            var link = r.Next(0, number-1);
            if(!mc.LinkToIds.Contains(link) && link != mc.Id)
                mc.LinkToIds.Add(link);
        }
        output.Add(mc);
    }

    return output;
}

然后,我使用另一种方法将其拆分为较小的“批次”:

private static ICollection<ICollection<MyClass>> GetBatches(ICollection<MyClass> toBatch, int sizeOfBatch)
{
    var output = new List<ICollection<MyClass>>();

    if(sizeOfBatch > toBatch.Count) sizeOfBatch = toBatch.Count;

    var numBatches = toBatch.Count / sizeOfBatch;
    for(int i = 0; i < numBatches; i++){
        output.Add(toBatch.Skip(i * sizeOfBatch).Take(sizeOfBatch).ToList());
    }

    return output;
}

然后实际添加到数据库中:

void Main()
{
    var gc = new GraphClient(new Uri("http://localhost:7474/db/data"), "neo4j", "neo");
    gc.Connect();

    var batches = GetBatches(GenerateMyClass(), 5000);

    var now = DateTime.Now;
    foreach (var batch in batches)
    {
        DateTime bstart = DateTime.Now;
        var query = gc.Cypher
            .Unwind(batch, "node")
            .Merge($"(n:{nameof(MyClass)} {{Id: node.Id}})")
            .Set("n = node")
            .With("n, node")
            .Unwind("node.LinkToIds", "linkTo")
            .Merge($"(n1:{nameof(MyClass)} {{Id: linkTo}})")
            .With("n, n1")
            .Merge("(n)-[:LINKED_TO]->(n1)");

        query.ExecuteWithoutResults();
        Console.WriteLine($"Batch took: {(DateTime.Now - bstart).TotalMilliseconds} ms");
    }
    Console.WriteLine($"Total took: {(DateTime.Now - now).TotalMilliseconds} ms");
}

在我老化的机器(现在是5-6岁)上,大约需要50秒才能放置50,000个节点以及大约500,000个关系。

让我们进入上面对Neo4j的重要调用。 关键的事情就是您正确建议的UNWIND我在这里UNWIND一批,并为该集合中的每个“行”指定node的标识符。 然后我可以访问属性( node.Id )并用它来MERGE的节点。 在第一开卷-我总是SET新创建的节点( n )是node ,因此所有的属性(本例中仅有AValue )设置。

因此,直到第一个With我们都创建了一个带有MyClass标签的新Node,并设置了其所有属性。 现在。 这确实包括拥有一个LinkToIds数组,如果您是一个整洁的人,则可能希望将其删除。 我会留给自己。

在第二个UNWIND我们利用LinkToIds属性是一个数组这一事实,并使用它来创建一个“占位符”节点,该节点将在以后填充,然后在nn1占位符之间创建一个关系。 注意:如果我们已经创建了一个与n1相同的ID的节点,我们将使用该节点,并且在第一个UNWIND期间获得相同的ID时,将设置占位符的所有属性。

这不是最简单的解释,但是最好看的是Neo4j文档中的MERGEUNWIND

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM