【Neo4j】第 12 章:Neo4j at Scale
🔎大家好,我是Sonhhxg_柒,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流🔎
📝个人主页-Sonhhxg_柒的博客_CSDN博客 📃
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝
📣系列专栏 - 机器学习【ML】 自然语言处理【NLP】 深度学习【DL】
🖍foreword
✔说明⇢本人讲解主要包括Python、机器学习(ML)、深度学习(DL)、自然语言处理(NLP)等内容。
如果你对这个系列感兴趣的话,可以关注订阅哟👋
文章目录
技术要求
衡量 GDS 性能
使用估算程序估算内存使用量
估计预计的图形内存使用情况
估计算法内存使用情况
统计运行模式
测量一些算法的时间性能
为大数据配置 Neo4j 4.0
Neo4j 4.0 之前的情况
内存设置
Neo4j in the cloud
使用 Neo4j 4.0 进行分片
定义分片
查询分片图
概括
现在我们可以使用 Neo4j 和图算法来回答许多问题,是时候关注 Neo4j 如何管理不同大小的数据了。Neo4j 4.0 之前的版本已经能够处理大量数据(数十亿个节点和关系),仅受磁盘大小的限制。但是 Neo4j 4.0 通过引入分片(一种跨越多台机器的图的技术)克服了这些限制(几乎)。本章将介绍分片,包括分片定义和专门用于查询此类图的新 Cypher 语句。在最后一节中,我们将研究大图的 GDS 性能。
本章将涵盖以下主题:
- 衡量 GDS 性能
- 为大数据配置 Neo4j 4.0
让我们开始吧!
技术要求
虽然本章的第一部分仍然可以使用 Neo4j 3.x 完成,但最后一部分将使用分片,它仅在 Neo4j 版本 4 中引入。因此,本节需要以下配置:
- Neo4j ≥ 4.0
- GDS≥1.2
衡量 GDS 性能
图形数据科学库是为大数据集构建的;图表示和算法针对大图进行了优化。但是,为了提高效率,所有操作都在堆中执行,这就是为什么估计在给定投影图上运行给定算法的内存需求可能很重要的原因。
使用估算程序估算内存使用量
GDS 算法在内存中的投影图上运行。该库提供了帮助程序,可用于预测存储投影图和运行给定算法所需的内存使用情况。这些估计是通过estimate执行模式执行的,可以附加到图创建或算法执行过程中。
估计预计的图形内存使用情况
投影图完全存储在内存中(在堆中)。为了知道存储具有给定节点、关系和属性的投影图需要多少内存,我们可以使用以下过程:
gds.graph.create.estimate(...)
// or
gds.graph.create.cypher.estimate(...)
有几种方法可以使用此过程,但在所有情况下,它都会返回以下参数:
- requiredMemory:所需的总内存
- mapView:关于哪些实体在节点、关系和属性之间需要更多内存的详细描述
- nodeCount: 投影图中的节点总数
- relationshipCount:投影图中的关系总数
让我们研究几个例子。
虚构图表
投影图存储以下内容:
- 一个节点作为 Neo4j 内部标识符 ( id(n))
- 作为一对节点 ID 的关系
- 属性,如果请求,作为浮点数(8 字节)
这意味着,只要我们知道投影图将包含多少个节点、关系和属性,就可以使用以下查询来估计内存需求:
CALL gds.graph.create.estimate('*', '*', {
nodeCount: 10000,
relationshipCount: 2000
})
该mapView字段如下所示:
{
"name": "HugeGraph",
"components": [
{
"name": "this.instance",
"memoryUsage": "72 Bytes"
},
{
"name": "nodeIdMap",
"components": [
...
],
"memoryUsage": "175 KiB"
},
{
"name": "adjacency list for 'RelationshipType{name='__ALL__'}'",
"components": [
...
],
"memoryUsage": "256 KiB"
},
{
"name": "adjacency offsets for 'RelationshipType{name='__ALL__'}'",
"components": [
...
],
"memoryUsage": "80 KiB"
}
],
"memoryUsage": "511 KiB"
}
这告诉您图表的总内存使用量将在511KB(最后一行)左右。它还可以帮助您确定哪些部分占用了大部分内存,以便最终您可以根据需要将图形的大小减少到最低限度。
由原生或 Cypher 投影定义的图
由于以下语法,可以估计使用 Cypher 投影定义的投影图的内存需求:
CALL gds.graph.create.cypher.estimate(
"MATCH (n) RETURN id(n)",
"MATCH (u)--(v) RETURN id(u) as source, id(v) as target"
)
请注意与使用 Cypher 投影创建实际图形相比的差异,如下所示:
CALL gds.graph.create.cypher(
"projGraphName",
"MATCH (n) RETURN id(n) as id",
"MATCH (u)--(v) RETURN id(u) as source, id(v) as target"
)
知道投影图需要多少内存是一回事。但通常,我们创建投影图以在其上运行一些算法。因此,能够估计算法的内存消耗对于确定我们需要使用的机器的大小也是至关重要的。
估计算法内存使用情况
对于生产质量层中的每个算法,GDS 实施的估计过程类似于上一段中为投影图研究的过程。它可以通过附加estimate到任何算法执行模式来使用:
CALL gds.<ALGO>.<MODE>.estimate(graphNameOrConfig: String|Map, configuration: Map)
返回的参数如下:
YIELD
requiredMemory,
treeView,
mapView,
bytesMin,
bytesMax,
heapPercentageMin,
heapPercentageMax,
nodeCount,
relationshipCount
参数名称是不言自明的,类似于投影图估计过程。通过估计投影图和要在其上运行的算法的内存使用情况,您可以获得对所需堆的相当好的估计,并使用大小合适的服务器进行分析。
统计运行模式
GDS 引入的另一个有趣的特性(与其前身图形算法库相比)是stats模式。它在不更改图形的情况下运行算法,但返回有关投影图形和算法结果的一些信息。返回的参数列表与模式中的参数列表相同write。
在下一节中,我们将研究图和算法内存 ( estimate) 和执行 ( stats) 估计的示例。
测量一些算法的时间性能
当使用算法写入过程时,也就是将结果写回 Neo4j 主图中,该过程将返回一些关于其执行时间的信息:
- createMillis:创建投影图的时间
- computeMillis: 运行算法的时间
- writeMillis: 是时候写回结果了
让我们使用这些参数来检查 PageRank 或 Louvain 算法的性能,与我们目前使用的相比,使用稍微大一点的图表。为此,我们将使用 Facebook 在招聘 Kaggle 比赛期间提供的社交网络图。数据集可以从Facebook Recruiting Competition | Kaggle下载。它包含1,867,425 个节点和 9,437,519 个关系。您可以使用您最喜欢的导入工具(LOAD CSV、APOC 或 Neo4j 命令行导入工具)将其导入 Neo4j。在本示例的其余部分中,我将Node用作节点标签和IS_FRIEND_WITH关系类型。
为了使用 GDS,我们需要创建一个包含所有节点和无向关系的投影图:
CALL gds.graph.create(
"graph",
"*",
{
IS_FRIEND_WITH: {
type: "IS_FRIEND_WITH",
orientation: "UNDIRECTED"
}
}
)
然后,我们可以使用以下命令执行 Louvain 算法:
CALL gds.louvain.write.estimate("graph", {writeProperty: "pr"})
这告诉我们运行算法只需要大约 56 MB 的堆空间。
现在,运行以下命令:
CALL gds.louvain.stats("graph)
这将为我们提供有关运行 Louvain 算法所需时间的估计。
现在,您应该能够估计您的图形需要多少内存来执行给定的算法。您还应该能够估计算法收敛到您的数据需要多长时间。
在下一节中,我们将回到 Neo4j 和 Cypher 并了解 4.0 版中针对超大图引入的新功能。
为大数据配置 Neo4j 4.0
Neo4j 4.0 于 2020 年 2 月发布。在其他新功能中,它是第一个支持分片以将图拆分到多个服务器的版本。我们将在下一节进一步讨论这个问题。首先,在考虑复杂的解决方案之前,让我们回顾一下可以提高 Neo4j 性能的一些基本设置。
Neo4j 4.0 之前的情况
Neo4j 3.x 已经是一个非常强大的数据库,可以管理数十亿个节点和关系。在获得 Neo4j 认证时,您学习调整的第一个设置是分配的内存。
内存设置
内存由文件中的几个设置配置neo4j.conf。默认值非常低,通常建议根据您的数据和使用情况增加它们。Neo4j 有一个实用程序脚本,用于估计图形实例所需的内存。该脚本位于您的路径bin目录中。$NEO4J_HOME从 Neo4j Desktop 使用 Neo4j 时,您可以从图形管理选项卡中打开终端,它将自动在该文件夹中打开。然后,您可以memrec使用以下bash命令执行:
./bin/neo4j-admin memrec
此命令的输出包含以下块:
dbms.memory.heap.initial_size=3500m
dbms.memory.heap.max_size=3500m
dbms.memory.pagecache.size=1900m
您可以使用这些指示来更新neo4j.conf(或 Neo4j Desktop 中的图形设置),然后重新启动您的数据库。
Neo4j in the cloud
很长一段时间以来,以完全自动化和托管的方式在云中运行 Neo4j 是可能的。事实上,Neo4j 提供了在谷歌云或 AWS 中使用的图像。
自 2019 年以来,Neo4j 还拥有自己的 Database-as-a-Service 解决方案和 Neo4j Aura,这是一种用于运行 Neo4j 数据库而无需担心基础设施的一体化解决方案。查看部署指南以获取更多信息和链接:https ://neo4j.com/developer/guide-cloud-deployment/ 。
使用 Neo4j 4.0 进行分片
分片是一种技术,当要存储的数据量大于单个服务器的容量时,它涉及将数据库拆分到多个服务器上。这只发生在非常大的数据集上,因为单个服务器的当前硬件容量可以达到数 TB 的数据。应用程序必须每天生成 GB 的数据才能达到这些限制。现在,让我们讨论如何使用 Neo4j 管理这些大数据集。
Neo4j 开发了另一种专门用于此目的的工具,称为fabric.
如果您在 Neo4j Browser 中使用 Neo4j 4.0 创建一个新图表,您会注意到活动数据库现在在查询框旁边突出显示。
定义分片
处理分片时要做的第一件事是定义如何拆分数据。确实,分片很强大,但也不是没有局限性。例如,分片的一个重要限制是无法将关系从一个分片遍历到另一个分片。但是,为了避免这种情况,可以复制一些节点,所以这完全取决于您的数据模型以及您如何查询它。想象一下,我们有来自电子商务网站的数据,该网站正在注册来自世界各地客户的订单。分片可以考虑几个维度:
- 基于空间的:来自同一大陆或国家的所有订单可以组合在同一个分片中。
- 基于时间:在同一天/周/月创建的所有节点都可以保存在同一个分片中。
- 基于产品:包含相同产品的订单可以组合在一起。
最后一种情况假设订购的产品之间有明确的划分;否则,我们将不得不复制几乎所有的产品节点。
一旦我们对如何拆分数据以及需要多少数据库有了更好的了解,我们就可以继续进行neo4j.conf. 例如,我们将使用两个本地数据库,可以通过添加以下行来配置neo4j.conf:
fabric.database.name=fabric
fabric.graph.0.name=gr1
fabric.graph.0.uri=neo4j://localhost:7867
fabric.graph.0.database=db1
fabric.graph.1.name=gr2
fabric.graph.1.uri=neo4j://localhost:7867
fabric.graph.1.database=db2
在继续之前,我们还需要做一件事:创建两个数据库(db1和db2)。
创建数据库
在 Neo4j 浏览器中,从左侧面板导航到Database Information选项卡(请参见以下屏幕截图):
在那里,您可以选择要使用的数据库。虽然默认值为neo4j,但我们将连接到system数据库以便能够创建新数据库。在这里,从下拉菜单中选择系统。Neo4j 浏览器将让您知道以下内容:
“从现在开始的查询将使用数据库系统作为目标。”
在这里,您可以创建本节所需的两个数据库:
CREATE DATABASE db1;
CREATE DATABASE db2
现在,您可以切换到我们集群的主入口点:调用的数据库fabric(同样,从左侧菜单中)。
现在我们已经告诉 Neo4j 数据将被拆分到几个集群中并且我们已经创建了这些集群,让我们学习如何告诉 Cypher 使用哪个集群。
查询分片图
上一个 Cypher 版本引入了一个新关键字 ,USE我们可以使用它来查询分片图。与fabric实用程序一起,这使我们能够使用单个查询来查询来自不同分片的数据。
使用语句
Cypher 语句是在 Neo4j 4.0 中引入的USE,用于告诉 Cypher 使用哪个分片。例如,我们可以使用以下查询将一些数据添加到我们的数据库之一:
USE fabric.gr1
CREATE (c:Country {name: "USA"})
CREATE (u1:User {name: "u1"})
CREATE (u2:User {name: "u2"})
CREATE (u1)-[:LIVES_IN]->(c)
CREATE (u2)-[:LIVES_IN]->(c)
CREATE (o1:Order {name: "o1"})
CREATE (o2:Order {name: "o2"})
CREATE (o3:Order {name: "o3"})
CREATE (u1)-[:ORDERED]->(o1)
CREATE (u2)-[:ORDERED]->(o2)
CREATE (u2)-[:ORDERED]->(o3)
我们可以使用以下代码从该分片中检索数据:
USE fabric.gr1
MATCH (order:Order)<--(:User)-->(country:Country)
RETURN "gr1" as db,
country.name,
count(*) AS nbOrders
前面的查询将仅使用gr1数据库fabric中的节点,如neo4j.conf. 您可以运行相同的查询USE fabric.gr2但没有结果,因为我们还没有创建任何数据gr2。如果您对所有数据感兴趣,而不对特定数据库进行过滤,也可以使用fabric,正如我们现在将看到的那样。
查询所有数据库
要查询所有已知的分片,我们将不得不使用另外两个函数:
- fabric.graphIds(),它返回所有已知的数据库。您可以使用以下命令测试其结果:
RETURN fabric.graphIds()
- fabric.graph(graphId)返回具有给定 ID 的数据库的名称,可在Use语句中直接使用。
这基本上允许我们对所有分片执行循环:
UNWIND fabric.graphIds() AS graphId
CALL {
USE fabric.graph(graphId)
WITH graphId
MATCH (order:Order)<--(:User)-->(country:Country)
RETURN "gr" + graphId as db,
country.name as countryName,
count(*) AS nbOrders
} RETURN db, countryName, sum(nbOrders)
这是前面查询的结果:
╒═════╤═════════════╤═══════════════╕
│"db" │"countryName"│"sum(nbOrders)"│
╞═════╪═════════════╪═══════════════╡
│"gr1"│"USA" │3 │
└─────┴─────────────┴───────────────┘
在这里,我们可以看到我们在本节前面创建的三个来自美国的订单gr1。
现在,假设您向 中添加一些数据gr2,例如:
USE fabric.gr2
CREATE (c:Country {name: "UK"})
CREATE (u1:User {name: "u11"})
CREATE (u2:User {name: "u12"})
CREATE (u1)-[:LIVES_IN]->(c)
CREATE (u2)-[:LIVES_IN]->(c)
CREATE (o1:Order {name: "o11"})
CREATE (o2:Order {name: "o12"})
CREATE (u1)-[:ORDERED]->(o1)
CREATE (u2)-[:ORDERED]->(o2)
通过这样做,前面的MATCH查询返回以下内容:
╒═════╤═════════════╤═══════════════╕
│"db" │"countryName"│"sum(nbOrders)"│
╞═════╪═════════════╪═══════════════╡
│"gr1"│"USA" │3 │
├─────┼─────────────┼───────────────┤
│"gr2"│"UK" │2 │
└─────┴─────────────┴───────────────┘
有了这个,您现在应该明白,分片为数据存储提供了无限的可能性,无论是在容量方面还是在实现方面,后者取决于将对数据库运行的查询。
概括
阅读本章后,您应该能够在单个服务器上或使用集群和分片技术部署 Neo4j 数据库。您还应该了解将 GDS 与大数据一起使用的最佳实践以及此插件的限制。
在本章中,我们结束了我们在第 1 章“图形数据库”中开始的循环,在那里您第一次开始学习图形、图形数据库和 Neo4j。第 2 章,Cypher 查询语言,教您如何将数据插入 Neo4j 并使用称为 Cypher 的可视化查询语言进行查询。第 3 章,用 Pure Cypher 赋能您的业务,让您有机会使用 Cypher 构建知识图谱并使用 Graph Aware 构建的第三方库执行一些自然语言处理( NLP )。
在第 4 章,图形数据科学库和路径查找中,您了解了图形数据科学库的基础知识。该插件由 Neo4j 开发和支持,是使用 Neo4j 进行图形数据科学的起点。在同一章中,您学习了如何执行最短路径操作,而无需从 Neo4j 中提取数据。下一章,第 5 章,空间数据,然后教你如何在 Neo4j 中使用空间数据。在这里,您发现了内置的空间类型Point,并了解了另一个插件,neo4j-spatial。您看到空间数据很好地集成到 Neo4j 中,甚至可以通过 Neo4j 桌面应用程序进行可视化。
在图算法部分的其余章节中,您发现了中心性 (第 6 章,节点重要性)和社区检测(第 7 章,社区检测和中心性度量)算法。您还了解了一些工具,例如neoviz用于创建漂亮的图形可视化的工具。
有了这些新知识,您就学会了如何在机器学习中使用这些图算法。首先,在第 8 章,在机器学习中使用基于图的特征中,您构建了一个简单的分类模型。通过将数据转换为图形并添加基于图形的特征,您能够提高模型的性能。在第 9 章,预测关系,您更熟悉了一个特定于图的机器学习问题:预测时间演化图中节点之间的未来链接。在第 10 章,图嵌入——从图到矩阵中,您通过了解可用的不同类型的算法来进一步进入图分析阶段,以便自动学习用于以向量格式表示节点的特征。
最后,在的最后一节中,您学习了如何使用 Python 或 GraphQL 和 React 将 Neo4j 与 Web 应用程序接口,这要归功于 GRANDstack(第 11 章,在您的 Web 应用程序中使用 Neo4j),以及如何调整 Neo4j 和真正大数据的 GDS。
自开始以来,我们所走过的道路令人印象深刻,但请记住,通往知识的道路没有尽头。继续阅读、学习、试验和创造令人惊奇的事物!