c# class 图到 Neo4j
c# class graph to Neo4j
我希望将内存中的普通旧 C# 类 转换为 neo4j 数据库。
(Class 类型是节点类型并派生自,节点具有 "linkedTo" 的列表)
与其编写一长串密码查询来创建节点和属性,然后 link 它们与关系,我想知道我是否可以做一些更聪明的事情。
例如,我可以将它们序列化为 json,然后将其直接导入到 neo4j 中吗?
我知道 C# neo4j 驱动程序中的 .unwind 函数在这里可能会有帮助,但没有看到它的使用示例,因此需要单独匹配和创建关系
是否有最佳方法?我希望有大约 50k 个节点
好的,首先,我为此使用了 Neo4jClient,并且我使用以下方法向数据库添加了一个 INDEX
:
CREATE INDEX ON :MyClass(Id)
这对于它的工作方式很重要,因为它可以更快地插入数据。
我有一个 class:
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;
}
然后我用另一种方法把它分割成更小的'batches':
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,000 个节点放入大约 500,000 个关系中大约需要 20 秒。
让我们进入上面对 Neo4j 的重要调用。关键是你正确地建议 UNWIND
- 在这里我 UNWIND
一个批次并为该集合中的每个 'row' 提供 node
的标识符。然后我可以访问属性 (node.Id
) 并将其用于 MERGE
节点。在第一个展开中 - 我总是 SET
新创建的节点 (n
) 成为 node
所以所有属性(在这种情况下只是 AValue
)被设置。
因此,在第一个 With
之前,我们创建了一个带有 MyClass
标签的新节点,并设置了所有属性。现在。这确实包括拥有一个 LinkToIds
数组,如果您是一个爱整洁的人,您可能想要将其删除。我会把它留给你自己。
在第二个 UNWIND
中,我们利用 LinkToIds
属性 是一个数组这一事实,并使用它来创建一个 'placeholder' 节点稍后填充,然后我们在 n
和 n1
占位符之间创建关系。注意 - 如果我们已经创建了一个与 n1
具有相同 ID 的节点,我们将使用该节点,并且当我们在第一个 UNWIND
期间获得相同的 ID 时,我们将设置所有属性占位符。
这不是最容易解释的,但最好看的是 Neo4j 文档中的 MERGE
和 UNWIND
。
我希望将内存中的普通旧 C# 类 转换为 neo4j 数据库。 (Class 类型是节点类型并派生自,节点具有 "linkedTo" 的列表)
与其编写一长串密码查询来创建节点和属性,然后 link 它们与关系,我想知道我是否可以做一些更聪明的事情。
例如,我可以将它们序列化为 json,然后将其直接导入到 neo4j 中吗? 我知道 C# neo4j 驱动程序中的 .unwind 函数在这里可能会有帮助,但没有看到它的使用示例,因此需要单独匹配和创建关系
是否有最佳方法?我希望有大约 50k 个节点
好的,首先,我为此使用了 Neo4jClient,并且我使用以下方法向数据库添加了一个 INDEX
:
CREATE INDEX ON :MyClass(Id)
这对于它的工作方式很重要,因为它可以更快地插入数据。
我有一个 class:
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;
}
然后我用另一种方法把它分割成更小的'batches':
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,000 个节点放入大约 500,000 个关系中大约需要 20 秒。
让我们进入上面对 Neo4j 的重要调用。关键是你正确地建议 UNWIND
- 在这里我 UNWIND
一个批次并为该集合中的每个 'row' 提供 node
的标识符。然后我可以访问属性 (node.Id
) 并将其用于 MERGE
节点。在第一个展开中 - 我总是 SET
新创建的节点 (n
) 成为 node
所以所有属性(在这种情况下只是 AValue
)被设置。
因此,在第一个 With
之前,我们创建了一个带有 MyClass
标签的新节点,并设置了所有属性。现在。这确实包括拥有一个 LinkToIds
数组,如果您是一个爱整洁的人,您可能想要将其删除。我会把它留给你自己。
在第二个 UNWIND
中,我们利用 LinkToIds
属性 是一个数组这一事实,并使用它来创建一个 'placeholder' 节点稍后填充,然后我们在 n
和 n1
占位符之间创建关系。注意 - 如果我们已经创建了一个与 n1
具有相同 ID 的节点,我们将使用该节点,并且当我们在第一个 UNWIND
期间获得相同的 ID 时,我们将设置所有属性占位符。
这不是最容易解释的,但最好看的是 Neo4j 文档中的 MERGE
和 UNWIND
。