跳转到主要内容

Vermeer Python 客户端

vermeer-python-clientVermeer 的 Python SDK。Vermeer 是使用 Go 编写、以内存计算为主的图计算引擎。该 SDK 封装了 Vermeer master 的 REST API,可以在 Python 中列出图、提交加载和计算任务、读取任务状态。导入时使用的包名是 pyvermeer

模块没有固定 Vermeer 服务端版本,它通过 HTTP 访问 Vermeer master,调用的接口见 API 概览

环境要求

  • 单独使用该模块需要 Python 3.9 或更高版本;HugeGraph-AI 仓库整体要求 Python 3.10 或更高版本
  • 一个可通过 HTTP 访问的 Vermeer master。默认 HTTP 端口为 6688;Docker 部署需发布 6688:6688,见 Vermeer 快速开始
  • uv(推荐)或 pip

运行时依赖:requestsurllib3python-dateutildecoratorrichsetuptools

安装

打包元数据中的发行包名是 vermeer-python-client,其版本号独立于仓库版本号管理。该包尚未发布到 PyPI,请从源码安装。

在 HugeGraph-AI 仓库根目录,使用 vermeer extra 把它安装到共用的虚拟环境中:

git clone https://github.com/apache/hugegraph-ai.git
cd hugegraph-ai
uv sync --extra vermeer
source .venv/bin/activate

vermeer-python-client 是以可编辑路径依赖的方式接入的,并不是 uv workspace member,因此在仓库根目录直接执行 uv sync 不会安装它,必须显式指定该 extra(或使用 --all-extras)。

单独安装该模块:

git clone https://github.com/apache/hugegraph-ai.git
cd hugegraph-ai/vermeer-python-client
uv sync
source .venv/bin/activate

连接 Vermeer master

from pyvermeer.client.client import PyVermeerClient

client = PyVermeerClient(
    ip="127.0.0.1",
    port=6688,
    token="",
    timeout=(0.5, 15.0),
    log_level="INFO",
)

构造函数参数:

参数类型默认值说明
ipstr必填Vermeer master 的主机名或 IP 地址
portint必填Vermeer master 的 REST 端口
tokenstr必填原样作为 Authorization 请求头发送
timeout(float, float)NoneNone连接超时和读取超时,单位为秒
log_levelstr"INFO"应用到共享 VermeerClient 日志器的级别

连接前需要了解的行为:

  • 当 master 不校验鉴权时,token 可以是空字符串,但不能是 None,否则会话会抛出 ValueError("Vermeer Token must be provided.")
  • timeout(连接超时, 读取超时) 二元组。VermeerConfig 自身的默认值是 (0.5, 15.0),但客户端总是把自己的参数传下去,因此不传 timeout 时实际存入的是 None,请求会一直等待。需要超时就显式传入该二元组。
  • 基础 URL 固定拼接为 http://{ip}:{port}/,即客户端只使用明文 HTTP。
  • 每个请求都会设置 Content-Type: application/json,并把 params 序列化进请求体,GET 请求也是如此。
  • 底层会话在 HTTP 500、502、504 时最多重试 3 次,退避系数为 0.1
  • log_level 设置的是名为 VermeerClient 的共享日志器的级别。它的控制台 handler 固定为 INFO,因此目前 DEBUG 级别的记录不会打印到控制台。

端到端示例

模块自带一个可运行的示例:vermeer-python-client/src/pyvermeer/demo/task_demo.py。下面的版本在其基础上增加了带超时和失败处理的任务状态轮询,等待加载成功后再读取图,并从环境变量读取 HugeGraph 密码:

import os
import time

from pyvermeer.client.client import PyVermeerClient
from pyvermeer.structure.task_data import TaskCreateRequest

client = PyVermeerClient(
    ip="127.0.0.1",
    port=6688,
    token="",
    timeout=(0.5, 15.0),
    log_level="INFO",
)

# 列出 master 上的任务
tasks = client.tasks.get_tasks()
print(tasks.to_dict())

# 从 HugeGraph 把图数据加载到 Vermeer
create_response = client.tasks.create_task(
    create_task=TaskCreateRequest(
        task_type="load",
        graph_name="DEFAULT-example",
        params={
            "load.hg_pd_peers": '["127.0.0.1:8686"]',
            "load.hugegraph_name": "DEFAULT/example/g",
            "load.hugegraph_username": "admin",
            "load.hugegraph_password": os.environ["HUGEGRAPH_PASSWORD"],
            "load.parallel": "10",
            "load.type": "hugegraph",
        },
    )
)
print(create_response.errcode, create_response.message)
if create_response.errcode != 0:
    raise RuntimeError(f"Could not create load task: {create_response.message}")

# 轮询本次创建的加载任务,直到成功、失败或超时
task_id = create_response.task.id
poll_timeout = 300.0
deadline = time.monotonic() + poll_timeout
while time.monotonic() < deadline:
    task = client.tasks.get_task(task_id)
    if task.errcode != 0:
        raise RuntimeError(f"Could not read task {task_id}: {task.message}")
    state = task.task.state
    print(task_id, state)
    if state == "loaded":
        break
    if state in ("error", "canceled"):
        raise RuntimeError(f"Load task {task_id} ended with state {state}")
    remaining = deadline - time.monotonic()
    if remaining > 0:
        time.sleep(min(1.0, remaining))
else:
    raise TimeoutError(f"Load task {task_id} did not finish within {poll_timeout}s")

# 图加载完成后查看图信息
print(client.graph.get_graph("DEFAULT-example").to_dict())

加载任务以 loaded 表示成功;errorcanceled 会中止示例,不再读取图。可按数据量调整 poll_timeout(此处为 300 秒)。轮询期限与 HTTP 连接、读取超时相互独立,已发出的请求及 SDK 重试可能使实际等待时间超过该期限。超时只停止客户端等待,不会取消服务端任务。

不要把真实的 HugeGraph 密码写死在脚本或配置文件中,请像上面这样从环境变量或凭据管理系统读取。

模块自带的 task_demo.py 使用 8688。运行前,请将其中 PyVermeerClientport 改为 6688,与默认 master HTTP 端口保持一致。根据安装后所在的目录选择对应命令:

仓库根目录安装(在 hugegraph-ai/ 下运行):

python vermeer-python-client/src/pyvermeer/demo/task_demo.py

独立安装(在 hugegraph-ai/vermeer-python-client/ 下运行):

python src/pyvermeer/demo/task_demo.py

API 概览

PyVermeerClient 以属性的方式暴露各个 API 组,目前注册了 graphtasks 两个组。

client.graph

方法Vermeer 接口返回值
get_graphs()GET /graphsGraphsResponse
get_graph(graph_name)GET /graphs/{graph_name}GraphResponse

client.tasks

方法Vermeer 接口返回值
get_tasks()GET /tasksTasksResponse
get_task(task_id)GET /task/{task_id}TaskResponse
create_task(create_task)POST /tasks/createTaskCreateResponse

pyvermeer/api/master.pypyvermeer/api/worker.py 目前只有许可证头,也没有注册到客户端上。因此尽管 pyvermeer/structure/ 下已经有 MasterResponseWorkersResponse,master 和 worker 信息暂时还无法通过客户端获取。

client.send_request(method, endpoint, params) 是这两个组共用的请求入口。对于还没有封装的 Vermeer 接口,可以直接调用它,返回值是解析后的 JSON 字典。

请求与响应对象

TaskCreateRequest(task_type, graph_name, params) 序列化为 {"task_type": ..., "graph": ..., "params": ...}。注意 graph_name 在报文中的字段名是 graph,与 Vermeer REST API 的请求体一致。

所有响应类型都继承 BaseResponse,提供 errcodemessage 属性和 to_dict() 方法。errcode0 表示成功,1 表示错误,-1 表示响应体中没有该字段。

  • GraphsResponse.graphsGraphResponse.graph 返回 VermeerGraph 对象,包含 namespace_namestatuscreate_timeupdate_timevertex_countedge_countworkersworker_groupuse_out_edgesuse_propertyuse_out_degreeuse_undirectedon_diskbackend_option
  • TasksResponse.tasksTaskResponse.taskTaskCreateResponse.task 返回 TaskInfo 对象,包含 idstatecreate_usercreate_typecreate_timestart_timeupdate_timegraph_namespace_nametypeparamsworkers
  • 时间字段由 python-dateutil 解析为 datetime 对象,空字符串会解析为 None

任务参数

客户端不会校验 params,键和值都会原样传给 Vermeer,因此可用的参数名由引擎决定,而不是由 SDK 决定。加载参数以及各算法的参数请参考 Vermeer 快速开始

使用流程与直接调用 REST API 相同:先创建 load 任务把图读入 Vermeer,等待任务完成,再针对已加载的图创建计算任务。

异常

pyvermeer.utils.exception 定义了四种异常,都由底层的 requests 或 JSON 解析失败包装而来:

异常触发场景
ConnectErrorrequests.ConnectionError,无法连接 master
TimeOutErrorrequests.Timeout,连接或读取超时
JsonDecodeError响应体不是合法的 JSON
UnknownError请求过程中的其他失败
from pyvermeer.utils.exception import ConnectError, TimeOutError

try:
    graphs = client.graph.get_graphs()
except (ConnectError, TimeOutError) as error:
    print(error)

客户端不检查响应的 HTTP 状态码,请通过返回对象的 errcodemessage 判断是成功还是 Vermeer 端返回了错误。

代码检查

在 HugeGraph-AI 仓库根目录执行格式化和静态检查:

./style/code_format_and_analysis.sh

源码位于 vermeer-python-client/src/pyvermeer/。该模块目前没有测试用例。

参考