GDS 会话 (适用于 AuraDB)

Open In Colab

此 Jupyter 笔记本托管在 Neo4j 图数据科学客户端 Github 存储库中的此处

该笔记本演示了如何使用 graphdatascience Python 库创建、管理和使用 GDS 会话。

我们考虑一个人员和水果的图,我们将其用作一个简单的示例,以展示如何将您的 AuraDB 实例连接到 GDS 会话、运行算法,并最终将您的分析结果写回 AuraDB 数据库。我们将涵盖所有管理操作:创建、列出和删除。

如果您使用的是自管理数据库,请遵循此示例

1. 先决条件

此笔记本需要有一个可用的 AuraDB 实例,并且您的租户已启用 GDS 会话功能。请联系您的客户经理以启用这些功能。

我们还需要安装 graphdatascience Python 库,版本 1.12a1 或更高版本。

%pip install "graphdatascience>=1.12a1"

2. Aura API 凭据

GDS 会话通过 Aura API 进行管理。为了使用 Aura API,我们需要拥有Aura API 凭据

使用这些凭据,我们可以创建我们的 GdsSessions 对象,它是管理 GDS 会话的主要入口点。

import os
from graphdatascience.session import GdsSessions, AuraAPICredentials

client_id = os.environ["AURA_API_CLIENT_ID"]
client_secret = os.environ["AURA_API_CLIENT_SECRET"]

# If your account is a member of several tenants, you must also specify the tenant ID to use
tenant_id = os.environ.get("AURA_API_TENANT_ID", None)

sessions = GdsSessions(api_credentials=AuraAPICredentials(client_id, client_secret, tenant_id=tenant_id))

3. 创建新会话

通过调用 sessions.get_or_create() 创建新会话。作为数据源,我们在此假设已创建 AuraDB 实例并可供访问。我们需要将数据库地址、用户名和密码传递给 DbmsConnectionInfo 类。

我们还需要指定会话的大小。请参阅 API 参考文档或手册以获取完整列表。

最后,我们需要为我们的会话命名。我们将我们的会话命名为 people-and-fruits。可以通过使用相同的会话名称和配置调用 get_or_create 来重新连接到现有会话。

我们还将为会话设置生存时间 (TTL)。这可确保在会话未使用 5 小时后自动删除。如果您忘记自行删除会话,这是一个避免产生费用的好习惯。

import os
from datetime import timedelta
from graphdatascience.session import DbmsConnectionInfo, AlgorithmCategory

# Identify the AuraDB instance
db_connection = DbmsConnectionInfo(uri=os.environ["AURA_DB_ADDRESS"], username=os.environ["AURA_DB_USER"], password=os.environ["AURA_DB_PW"])
# Create a GDS session!
memory = sessions.estimate(
    node_count=20,
    relationship_count=50,
    algorithm_categories=[AlgorithmCategory.CENTRALITY, AlgorithmCategory.NODE_EMBEDDING],
)
gds = sessions.get_or_create(
    # we give it a representative name
    session_name="people-and-fruits",
    memory=memory,
    db_connection=db_connection,
    ttl=timedelta(hours=5),
)

4. 列出会话

现在我们已经创建了一个会话,让我们列出所有会话以查看其外观。

sessions.list()

5. 添加数据集

我们假设已配置的 AuraDB 实例为空。我们将使用标准 Cypher 添加我们的数据集。

在更实际的场景中,此步骤已完成,我们只需连接到现有的数据库即可。

data_query = """
  CREATE
    (dan:Person {name: 'Dan',     age: 18, experience: 63, hipster: 0}),
    (annie:Person {name: 'Annie', age: 12, experience: 5, hipster: 0}),
    (matt:Person {name: 'Matt',   age: 22, experience: 42, hipster: 0}),
    (jeff:Person {name: 'Jeff',   age: 51, experience: 12, hipster: 0}),
    (brie:Person {name: 'Brie',   age: 31, experience: 6, hipster: 0}),
    (elsa:Person {name: 'Elsa',   age: 65, experience: 23, hipster: 1}),
    (john:Person {name: 'John',   age: 4, experience: 100, hipster: 0}),

    (apple:Fruit {name: 'Apple',   tropical: 0, sourness: 0.3, sweetness: 0.6}),
    (banana:Fruit {name: 'Banana', tropical: 1, sourness: 0.1, sweetness: 0.9}),
    (mango:Fruit {name: 'Mango',   tropical: 1, sourness: 0.3, sweetness: 1.0}),
    (plum:Fruit {name: 'Plum',     tropical: 0, sourness: 0.5, sweetness: 0.8})

  CREATE
    (dan)-[:LIKES]->(apple),
    (annie)-[:LIKES]->(banana),
    (matt)-[:LIKES]->(mango),
    (jeff)-[:LIKES]->(mango),
    (brie)-[:LIKES]->(banana),
    (elsa)-[:LIKES]->(plum),
    (john)-[:LIKES]->(plum),

    (dan)-[:KNOWS]->(annie),
    (dan)-[:KNOWS]->(matt),
    (annie)-[:KNOWS]->(matt),
    (annie)-[:KNOWS]->(jeff),
    (annie)-[:KNOWS]->(brie),
    (matt)-[:KNOWS]->(brie),
    (brie)-[:KNOWS]->(elsa),
    (brie)-[:KNOWS]->(jeff),
    (john)-[:KNOWS]->(jeff);
"""

# making sure the database is actually empty
assert gds.run_cypher("MATCH (n) RETURN count(n)").squeeze() == 0, "Database is not empty!"

# let's now write our graph!
gds.run_cypher(data_query)

gds.run_cypher("MATCH (n) RETURN count(n) AS nodeCount")

6. 投影图

现在我们已将图导入到数据库中,我们可以将其投影到我们的 GDS 会话中。我们通过使用 gds.graph.project() 端点来做到这一点。

我们正在使用的远程投影查询选择所有 Person 节点及其 LIKES 关系,以及所有 Fruit 节点及其 LIKES 关系。此外,出于说明目的,我们还投射节点属性。我们可以将这些节点属性用作算法的输入,尽管我们不会在本笔记本中这样做。

G, result = gds.graph.project(
    "people-and-fruits",
    """
    CALL {
        MATCH (p1:Person)
        OPTIONAL MATCH (p1)-[r:KNOWS]->(p2:Person)
        RETURN
          p1 AS source, r AS rel, p2 AS target,
          p1 {.age, .experience, .hipster } AS sourceNodeProperties,
          p2 {.age, .experience, .hipster } AS targetNodeProperties
        UNION
        MATCH (f:Fruit)
        OPTIONAL MATCH (f)<-[r:LIKES]-(p:Person)
        RETURN
          p AS source, r AS rel, f AS target,
          p {.age, .experience, .hipster } AS sourceNodeProperties,
          f { .tropical, .sourness, .sweetness } AS targetNodeProperties
    }
    RETURN gds.graph.project.remote(source, target, {
      sourceNodeProperties: sourceNodeProperties,
      targetNodeProperties: targetNodeProperties,
      sourceNodeLabels: labels(source),
      targetNodeLabels: labels(target),
      relationshipType: type(rel)
    })
    """,
)

str(G)

7. 运行算法

现在,我们可以在投影的图上运行算法。这是使用标准 GDS Python 客户端 API 完成的。还有许多其他教程涵盖了我们可以在此步骤中执行的一些有趣的事情,因此我们在这里将保持简短。

我们将简单地在图上运行 PageRank 和 FastRP。

print("Running PageRank ...")
pr_result = gds.pageRank.mutate(G, mutateProperty="pagerank")
print(f"Compute millis: {pr_result['computeMillis']}")
print(f"Node properties written: {pr_result['nodePropertiesWritten']}")
print(f"Centrality distribution: {pr_result['centralityDistribution']}")

print("Running FastRP ...")
frp_result = gds.fastRP.mutate(
    G,
    mutateProperty="fastRP",
    embeddingDimension=8,
    featureProperties=["pagerank"],
    propertyRatio=0.2,
    nodeSelfInfluence=0.2,
)
print(f"Compute millis: {frp_result['computeMillis']}")
# stream back the results
gds.graph.nodeProperties.stream(G, ["pagerank", "fastRP"], separate_property_columns=True, db_node_properties=["name"])

8. 写回 AuraDB

GDS 会话的内存中图是从我们指定的 AuraDB 实例中的数据投影的。因此,写回操作会将数据持久化回同一个 AuraDB。让我们将 PageRank 和 FastRP 算法的结果写回 AuraDB 实例。

# if this fails once with some error like "unable to retrieve routing table"
# then run it again. this is a transient error with a stale server cache.
gds.graph.nodeProperties.write(G, ["pagerank", "fastRP"])

当然,我们也可以只使用 .write 模式。让我们以写入模式运行 Louvain 以进行演示。

gds.louvain.write(G, writeProperty="louvain")

现在,我们可以使用 gds.run_cypher() 方法查询更新后的图。请注意,run_cypher() 方法将在 AuraDB 实例上运行查询。

gds.run_cypher(
    """
    MATCH (p:Person)
    RETURN p.name, p.pagerank AS rank, p.louvain
     ORDER BY rank DESC
    """
)

9. 删除会话

现在我们已经完成了分析,我们可以删除会话。我们生成的成果已写回我们的 AuraDB 实例,并且不会丢失。如果我们计算了未写回的其他内容,则这些内容将丢失。

删除会话将释放与其关联的所有资源,并停止产生费用。

gds.delete()

# or sessions.delete("people-and-fruits")
# let's also make sure the deleted session is truly gone:
sessions.list()
# Lastly, let's clean up the database
gds.run_cypher("MATCH (n:Person|Fruit) DETACH DELETE n")

10. 结论

我们完成了!我们创建了一个 GDS 会话,投影了一个图,运行了一些算法,写回了结果,并删除了会话。这是一个简单的示例,但它展示了使用 GDS 会话的主要步骤。