图对象
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
也会加速。