图对象
1. 投影图对象
投影图对象有几种方法。最简单的方法是进行 原生投影
# We put this simple graph in our database
gds.run_cypher(
"""
CREATE
(m: City {name: "Malmö"}),
(l: City {name: "London"}),
(s: City {name: "San Mateo"}),
(m)-[:FLY_TO]->(l),
(l)-[:FLY_TO]->(m),
(l)-[:FLY_TO]->(s),
(s)-[:FLY_TO]->(l)
"""
)
# We estimate required memory of the operation
res = gds.graph.project.estimate(
["City"], # Node projection
"FLY_TO", # Relationship projection
readConcurrency=4 # Configuration parameters
)
assert res["bytesMax"] < 1e12
G, result = gds.graph.project(
"offices", # Graph name
["City"], # Node projection
"FLY_TO", # Relationship projection
readConcurrency=4 # Configuration parameters
)
assert G.node_count() == result["nodeCount"]
其中 G 是一个 Graph 对象,而 result 是一个 pandas Series,其中包含来自底层过程调用的元数据。
请注意,所有投影语法变体都通过为节点和关系投影参数指定 Python dict 或 list 来支持。为了指定与过程的 configuration 映射的键相对应的配置参数,我们提供了命名关键字参数,例如上述的 readConcurrency=4。有关语法的更多信息,请参阅 GDS 手册。
与 Cypher 类似,还有一个相应的 gds.graph.project.estimate 方法,可以以类似的方式调用。
要获取一个表示已投影到图目录中的图的图对象,可以调用仅限客户端的 get 方法并传递名称
G = gds.graph.get("offices")
对于 GDS 管理员,即使提供的名称指向另一个用户的图投影,gds.graph.get 也会将图名称解析为 Graph 对象。
除了上述方法,还有五种创建图对象的方法
-
gds.graph.project.cypher(这是旧版 Cypher 投影,请参阅 使用 Cypher 投影图 以了解新的 Cypher 投影) -
gds.graph.filter -
gds.graph.generate -
gds.graph.sample.rwr -
gds.graph.sample.cnarw
它们的 Cypher 签名映射到 Python 的方式与上述 gds.graph.project 类似。
2. 使用 Cypher 投影图
方法 gds.graph.cypher.project 允许使用 Cypher 投影图。Cypher 投影不是一个专用的过程;它需要编写一个调用 gds.graph.project 聚合函数的 Cypher 查询。
在 GDS 手册 中阅读更多关于 Cypher 投影的信息。
方法 gds.graph.cypher.project 弥合了 gds.run_cypher 与后续调用 gds.graph.get 之间的差距。
2.1. 语法
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
|
|
|
要执行的 Cypher 查询。必须以 |
|
|
|
覆盖目标数据库。默认使用连接中的数据库。 |
|
|
|
查询参数作为关键字参数。 |
与 gds.run_cypher 不同,但与 gds.graph.project 非常相似的是,它返回一个由 Graph 对象和包含 Cypher 执行元数据的 pandas Series 组成的元组。
该方法不会以任何方式修改 Cypher 查询,所有投影配置都必须在查询本身中完成。但是,该方法会验证查询是否只包含一个 RETURN gds.graph.project(…) 子句,并且该子句出现在查询的末尾。这意味着此方法不能用于将图与 Cypher 中的其他聚合一起投影,也不能重命名结果行。如果提供的查询未能通过验证,则回退方案是结合使用 gds.run_cypher 和 gds.graph.get 以达到相同的结果。
# We put this simple graph in our database
gds.run_cypher(
"""
CREATE
(m: City {name: "Malmö"}),
(l: City {name: "London"}),
(s: City {name: "San Mateo"}),
(m)-[:FLY_TO]->(l),
(l)-[:FLY_TO]->(m),
(l)-[:FLY_TO]->(s),
(s)-[:FLY_TO]->(l)
"""
)
G, result = gds.graph.cypher.project(
"""
MATCH (n)-->(m)
RETURN gds.graph.project($graph_name, n, m, {
sourceNodeLabels: $label,
targetNodeLabels: $label,
relationshipType: $rel_type
})
""", # Cypher query
database="neo4j", # Target database
graph_name="offices", # Query parameter
label="City", # Query parameter
rel_type="FLY_TO" # Query parameter
)
assert G.node_count() == result["nodeCount"]
3. 从 DataFrames 构建图
除了从 Neo4j 数据库投影图之外,还可以直接从 pandas DataFrame 对象创建图。
3.1. 语法
| 名称 | 类型 | 默认值 | 描述 |
|---|---|---|---|
|
|
|
要构建的图的名称。 |
|
|
|
包含节点数据的一个或多个数据帧。 |
|
|
|
包含关系数据的一个或多个数据帧。 |
|
|
|
用于构建图的线程数。 |
|
|
|
要投影为无向的关系类型列表。 |
3.2. 示例
nodes = pandas.DataFrame(
{
"nodeId": [0, 1, 2, 3],
"labels": ["A", "B", "C", "A"],
"prop1": [42, 1337, 8, 0],
"otherProperty": [0.1, 0.2, 0.3, 0.4]
}
)
relationships = pandas.DataFrame(
{
"sourceNodeId": [0, 1, 2, 3],
"targetNodeId": [1, 2, 3, 0],
"relationshipType": ["REL", "REL", "REL", "REL"],
"weight": [0.0, 0.0, 0.1, 42.0]
}
)
G = gds.graph.construct(
"my-graph", # Graph name
nodes, # One or more dataframes containing node data
relationships # One or more dataframes containing relationship data
)
assert "REL" in G.relationship_types()
上面的示例从两个 DataFrame 对象创建了一个图,一个用于节点,一个用于关系。投影的图等同于以下 Cypher 查询将在 Neo4j 数据库中创建的图
CREATE
(a:A {prop1: 42, otherProperty: 0.1),
(b:B {prop1: 1337, otherProperty: 0.2),
(c:C {prop1: 8, otherProperty: 0.3),
(d:A {prop1: 0, otherProperty: 0.4),
(a)-[:REL {weight: 0.0}]->(b),
(b)-[:REL {weight: 0.0}]->(c),
(c)-[:REL {weight: 0.1}]->(d),
(d)-[:REL {weight: 42.0}]->(a),
节点数据帧支持的格式在 Arrow 节点模式 中描述,关系数据帧的格式在 Arrow 关系模式 中描述。
3.3. Apache Arrow Flight 服务器支持
construct 方法如果启用,可以利用 GDS 的 Apache Arrow Flight 服务器。这尤其意味着
-
图的构建速度大大加快,
-
可以提供多个数据帧,包括节点和关系的数据帧。如果使用多个节点数据帧,它们需要包含所有节点数据帧中不同的节点 ID。
-
在调用
construct之前,必须调用GraphDataScience.set_database来显式指定应针对哪个 Neo4j 数据库。
3.4. 社区版的限制
对于 GDS 社区版用户,大型图的性能可能会受到影响。与数据库的套接字连接可能会超时。如果发生这种情况,一个可能的解决方案是修改服务器配置 server.bolt.connection_keep_alive 或 server.bolt.connection_keep_alive_probes。但是,请注意其副作用,例如真正的连接问题现在需要更长时间才能被检测到。
4. 加载 NetworkX 图
从客户端数据构建图的另一种方法是使用库的便捷 NetworkX 加载方法。为了使用此方法,必须为 graphdatascience 库安装 NetworkX 支持
pip install graphdatascience[networkx]
公开 NetworkX 数据集加载功能的方法称为 gds.graph.networkx.load。它返回一个 Graph 对象,并接受三个参数
| 名称 | 类型 | |
|---|---|---|
|
|
NetworkX 格式的图 |
|
|
创建的 GDS 图的名称 |
|
|
可选的线程数 |
networkx.Graph nx_G 如何精确映射到 GDS Graph 投影,详细说明请参见 下文。
4.1. 示例
我们来看一个加载最小异构玩具 NetworkX 图的示例。
import networkx as nx
# Construct a directed NetworkX graph
nx_G = nx.DiGraph()
nx_G.add_node(1, labels=["Person"], age=52)
nx_G.add_node(42, labels=["Product", "Item"], cost=17.2)
nx_G.add_edge(1, 42, relationshipType="BUYS", quantity=4)
# Load the graph into GDS
G = gds.graph.networkx.load(nx_G, "purchases")
# Verify that the projection is what we expect
assert G.name() == "purchases"
assert G.node_count() == 2
assert set(G.node_labels()) == {"Person", "Product", "Item"}
assert G.node_properties("Person") == ["age"]
assert G.node_properties("Product") == ["cost"]
# Count rel not being = 2 indicates the graph is indeed directed
assert G.relationship_count() == 1
assert G.relationship_types() == ["BUYS"]
assert G.relationship_properties("BUYS") == ["quantity"]
|
结合 NetworkX 读取各种图格式的功能,可以轻松将边列表和 GML 等常用图格式加载到 GDS 中。 |
|
结合 NetworkX 生成各种图的功能,可以轻松将文献中流行的图类型加载到 GDS 中,例如扩展图、棒棒糖图、完全图等。 |
4.2. NetworkX 模式到 GDS 模式
NetworkX 图如何映射到 GDS 中的投影 Graph 有一些规则。它们遵循与 从 DataFrames 构建图 类似的原则,并将在本节中详细概述。
4.2.1. 节点标签
投影 GDS 图的节点标签取自 networkx.Graph 节点上的属性。节点属性键 labels 的值将决定投影中节点的标签。这些值应为字符串或字符串列表。
networkx.Graph 的所有节点必须具有有效的 labels 属性,或者它们可以从图中完全省略。也就是说,一个根本没有 labels 节点属性的 networx.Graph 也是允许的。在后一种情况下,投影的 Graph 中的所有节点都将具有节点标签 N。
4.2.2. 节点属性
投影 GDS 图的节点属性取自 networkx.Graph 节点上的属性。属性的键将映射到属性名称,允许的值必须遵循 GDS 中节点属性值的常规准则。但请注意,节点属性键 labels 保留用于节点标签(上一节),并且不会转换为投影中的节点属性。
4.2.3. 关系类型
投影 GDS 图的关系类型取自 networkx.Graph 边上的属性。边属性键 relationshipType 的值将决定投影中关系的类型。这些值应为字符串或省略。
networkx.Graph 的所有边必须具有有效的 relationshipType 属性,或者它们可以从图中完全省略。也就是说,一个根本没有 relationshipType 边属性的 networx.Graph 也是允许的。在后一种情况下,投影的 Graph 中的关系都将具有关系类型 R。
4.3. 社区版的限制
对于 GDS 社区版用户,大型图的性能可能会受到影响。与数据库的套接字连接可能会超时。如果发生这种情况,一个可能的解决方案是修改服务器配置 server.bolt.connection_keep_alive 或 server.bolt.connection_keep_alive_probes。但是,请注意其副作用,例如真正的连接问题现在需要更长时间才能被检测到。
5. 检查图对象
图对象上有一些便捷方法,可以让我们提取有关投影图的信息。
| 名称 | 参数 | 返回类型 | 描述 |
|---|---|---|---|
|
|
|
投影图的名称。 |
|
|
|
图已投影到的数据库名称。 |
|
|
|
投影图的节点计数。 |
|
|
|
投影图的关系计数。 |
|
|
|
图中存在的节点标签列表。 |
|
|
|
图中存在的关系类型列表。 |
|
|
|
如果提供了标签参数,则返回具有给定节点标签的节点上存在的属性列表。否则,返回一个 |
|
|
|
如果提供了类型参数,则返回具有给定关系类型的关系上存在的属性列表。否则,返回一个 |
|
|
|
生成节点的平均出度。 |
|
|
|
图的密度。 |
|
|
|
用于在 Java 堆中存储图的字节数。 |
|
|
|
|
|
|
|
如果图存在于 GDS 图目录中,则返回 |
|
|
|
|
|
|
|
用于将图投影到内存中的配置。 |
|
|
|
图投影的时间。 |
|
|
|
图上次修改的时间。 |
例如,要获取图 G 的节点计数和节点属性,我们可以这样做
n = G.node_count()
props = G.node_properties("City")
6. 上下文管理
图对象还实现了上下文管理协议,即可以在 with 子句中使用。退出 with 块时,图投影将在服务器端自动删除。
# We use the example graph from the `Projecting a graph object` section
with gds.graph.project(
"tmp_offices", # Graph name
["City"], # Node projection
"FLY_TO", # Relationship projection
readConcurrency=4 # Configuration parameters
)[0] as G_tmp:
assert G_tmp.exists()
# Outside of the with block the Graph does not exist
assert not gds.graph.exists("tmp_offices")["exists"]
7. 使用图对象
图对象的主要用例是将其传递给算法,但它也是 GDS 图目录 的大多数方法的输入。
7.1. 算法输入
Python 客户端使用 Graph 作为算法输入的语法遵循 GDS Cypher 过程 API,其中图是传递给算法的第一个参数。
result = gds[.<tier>].<algorithm>.<execution-mode>[.<estimate>](
G: Graph,
**configuration: dict[str, any]
)
在此示例中,我们在图 G 上运行度中心性算法
result = gds.degree.mutate(G, mutateProperty="degree")
assert "centralityDistribution" in result
7.2. 图目录
GDS 图目录 的所有过程在客户端中都有相应的 Python 方法。在那些以图名称字符串作为输入的目录过程中,其 Python 客户端等效方法改为接受一个 Graph 对象,但 gds.graph.exists 例外,它仍然接受图名称字符串。
以下是一些通过客户端使用 GDS 图目录的示例,假设我们检查了图 G,该图来自 上面的示例
# List graphs in the catalog
list_result = gds.graph.list()
# Check for existence of a graph in the catalog
exists_result = gds.graph.exists("offices")
assert exists_result["exists"]
# Stream the node property 'degree'
result = gds.graph.nodeProperty.stream(G, node_property="degree")
# Drop a graph; same as G.drop()
gds.graph.drop(G)
7.2.1. 流式传输属性
客户端方法
-
gds.graph.nodeProperty.stream(以前是gds.graph.streamNodeProperty) -
gds.graph.nodeProperties.stream(以前是gds.graph.streamNodeProperties) -
gds.graph.relationshipProperty.stream(以前是gds.graph.streamRelationshipProperty) -
gds.graph.relationshipProperties.stream(以前是gds.graph.streamRelationshipProperties)
如果启用了 GDS 的 Apache Arrow Flight 服务器,速度会大大加快。
此外,为 gds.graph.streamNodeProperties 和 gds.graph.streamRelationshipProperties 设置仅客户端可选关键字参数 separate_property_columns=True(默认为 False)会返回一个 pandas DataFrame,其中每个请求的属性都有自己的列。请注意,这与默认行为不同,默认行为只有一个名为 propertyValue 的列,其中包含每个节点或关系的交叉请求的所有属性。
7.2.2. 包含来自 Neo4j 的节点属性
节点属性(例如名称和描述)有助于理解算法的输出,即使运行算法本身不需要它们。要直接从 Neo4j 数据库获取额外的节点属性,可以使用 db_node_properties 客户端专用参数 gds.graph.nodeProperty.stream 和 gds.graph.nodeProperties.stream 方法。
在以下示例中,City 节点同时具有数字属性和 String 属性。stream 方法检索仅数据库的 name 属性的值以及投影的 population 属性的值。
gds.run_cypher(
"""
CREATE
(m: City {name: "Malmö", population: 360000}),
(l: City {name: "London", population: 8800000}),
(s: City {name: "San Mateo", population: 105000}),
(m)-[:FLY_TO]->(l),
(l)-[:FLY_TO]->(m),
(l)-[:FLY_TO]->(s),
(s)-[:FLY_TO]->(l)
"""
)
G, result = gds.graph.project(
"offices",
{
"City": {
"properties": ["population"]
}
},
"FLY_TO"
)
gds.graph.nodeProperties.stream(G, node_properties=["population"], db_node_properties=["name"])
7.2.3. 按关系类型流式传输拓扑
Python 客户端方法 gds.beta.graph.relationships.stream 返回的类型名为 TopologyDataFrame,它继承自标准的 pandas DataFrame。TopologyDataFrame 附带了一个名为 by_rel_type 的额外便捷方法,该方法不带任何参数,并返回一个形式为 Dict[str, List[List[int]]] 的字典。此字典将字符串形式的关系类型映射到 2 x m 矩阵,其中 m 表示给定类型的关系数量。每个此类矩阵的第一行是关系的源节点 ID,第二行是相应的目标节点 ID。
我们可以使用我们的图 G,以 上面的构建示例 来演示此转换
topology_by_rel_type = gds.beta.graph.relationships.stream(G).by_rel_type()
assert list(topology_by_rel_type.keys()) == ["REL"]
assert topology_by_rel_type["REL"][0] == [0, 1, 2, 3]
assert topology_by_rel_type["REL"][1] == [1, 2, 3, 0]
与 流式传输属性 方法类似,如果启用了 GDS Apache Arrow Flight 服务器,则 gds.beta.graph.relationships.stream 也会加速。