Apache GraphAr 数据读写实战详解

使用 Apache GraphAr Python SDK(graphar 0.13.0.dev1)完成图数据读写实战:核心 API 概览、官方 ldbc_sample 数据集读取、自建图写出读回闭环,以及产出目录解析与避坑清单。

Apache GraphArApacheApache GraphAr大数据PythonParquet2026/10/14

Apache GraphAr 数据读写实战详解

目标:用 Apache GraphAr 官方 Python SDK(PyPI 包名 graphar)完成两类最典型的实战——读取官方 ldbc_sample 图数据集、从已有元数据出发自建一张小图并完成「写出、读回」闭环,同时解析产出目录结构并沉淀实测踩坑点。全部代码与回显均在 Ubuntu 22.04(Python 3.10.12,graphar 0.13.0.dev1)真实环境跑通。

一、环境信息

本章实战依赖的软件与路径如下,所有回显均取自该环境的真实运行结果。

  • 操作系统:Ubuntu 22.04.5 LTS(x86_64)
  • Python:3.10.12,虚拟环境位于 /opt/venv-graphar
  • Apache GraphAr Python SDK:0.13.0.dev1(含 CLI 工具 graphar 与 C++ 核心库绑定)
  • 官方源码:/opt/incubator-graphar(commit 06dddb1)
  • 官方测试数据:/opt/incubator-graphar/testing(含 ldbc_sample、modern_graph 等)
  • 实战工作目录:/root/graphar-demo(自建图产出目录)

进入虚拟环境的验证命令与实测回显:

/opt/venv-graphar/bin/python -c "import graphar; import importlib.metadata as im; print('graphar version:', im.version('graphar'))"
graphar version: 0.13.0.dev1

💡 说明:graphar 包没有提供 __version__ 属性,官方推荐用标准库 importlib.metadata 读取版本号,如上实测。

二、前置条件

2.1 安装 graphar Python 包

GraphAr Python 包从 PyPI 安装即可,正确包名为 graphar。以下为从零创建虚拟环境到安装成功的完整命令与实测回显(包名陷阱排障见《Ubuntu 22.04 安装 Apache GraphAr 指南》)。

apt-get update && apt-get install -y python3 python3-venv python3-pip curl
Setting up python3-pip (22.0.2+dfsg-1ubuntu0.7) ...
Setting up python3-dev (3.10.6-1~22.04.1) ...
Processing triggers for libc-bin (2.35-0ubuntu3.15) ...
python3 -m venv /opt/venv-graphar && /opt/venv-graphar/bin/pip install --upgrade pip
  Downloading pip-26.2.1-py3-none-any.whl (1.8 MB)
    Found existing installation: pip 22.0.2
    Uninstalling pip-22.0.2:
      Successfully uninstalled pip-22.0.2
Successfully installed pip-26.2.1
/opt/venv-graphar/bin/pip install graphar
Collecting graphar
  Downloading graphar-0.13.0.dev1-cp310-cp310-manylinux_2_28_x86_64.whl (15.3 MB)
Installing collected packages: typing-extensions, tomli, shellingham, pyyaml, pygments, pluggy, packaging, mdurl, iniconfig, annotated-types, annotated-doc, typing-inspection, pydantic-core, markdown-it-py, exceptiongroup, rich, pytest, pydantic, typer, graphar
Successfully installed annotated-doc-0.0.5 annotated-types-0.8.0 exceptiongroup-1.3.1 graphar-0.13.0.dev1 iniconfig-2.3.1 markdown-it-py-4.2.0 mdurl-0.1.2 packaging-26.3 pluggy-1.6.0 pydantic-2.11.10 pydantic-core-2.33.2 pygments-2.21.0 pytest-7.4.4 pyyaml-6.0.3 rich-15.0.0 shellingham-1.5.4 tomli-2.5.0 typer-0.27.3 typing-extensions-4.16.0 typing-inspection-0.4.4

安装验证:

/opt/venv-graphar/bin/pip show graphar
Name: graphar
Version: 0.13.0.dev1
Summary: An open source, standard data file format for graph data storage and retrieval.
Author-email: GraphAr community <dev@graphar.apache.org>
License: Apache-2.0
Location: /opt/venv-graphar/lib/python3.10/site-packages
Requires: pydantic, pytest, pyyaml, typer
Required-by:

⚠️ 注意:PyPI 上的 pygraphar 是 GraphScope 的占位包,安装它会失败,切勿使用;PyPI wheel 的运行时依赖只有 typer、pydantic、pyyaml、pytest 四个(C++ 层已捆绑 Arrow),不需要单独安装 pyarrow/numpy/pandas。

2.2 获取官方源码与测试数据

官方示例脚本与测试数据在 GitHub 两个仓库中,浅克隆即可满足本文实战:

git clone --depth 1 https://github.com/apache/incubator-graphar.git /opt/incubator-graphar
Cloning into 'incubator-graphar'...
git clone --depth 1 https://github.com/apache/incubator-graphar-testing.git /opt/incubator-graphar/testing

克隆结果验证(源码提交版本与测试数据目录):

git -C /opt/incubator-graphar log -1 --oneline && ls /opt/incubator-graphar/testing/
06dddb1 fix(java): declare maven-install-plugin once in the java module (#985)
LICENSE
README.md
java
ldbc
ldbc_sample
modern_graph
nebula
neo4j
transformer

2.3 设置测试数据环境变量

官方示例脚本通过环境变量 GAR_TEST_DATA 定位测试数据根目录,运行示例前先导出:

export GAR_TEST_DATA=/opt/incubator-graphar/testing

该变量只影响官方示例与测试脚本,不影响 SDK 本身的读写 API;本文实战二的代码不依赖它。

三、核心 API 概览

3.1 API 全景

先看模块暴露的完整 API 面(实测):

/opt/venv-graphar/bin/python -c "import graphar; print([n for n in dir(graphar) if not n.startswith('_')])"
['AdjacentList', 'BuilderEdge', 'BuilderVertex', 'DataType', 'Edge', 'EdgeInfo', 'EdgeIter',
 'EdgesBuilder', 'EdgesCollection', 'GraphInfo', 'Property', 'PropertyGroup', 'Vertex',
 'VertexInfo', 'VertexIter', 'VerticesBuilder', 'VerticesCollection', 'annotations',
 'graph_info', 'high_level']

按用途分为三组,后续小节逐一说明:

分组API作用
元数据GraphInfo、VertexInfo、EdgeInfo加载与组装图级、顶点级、边级元数据
读取VerticesCollection、EdgesCollection(high_level)以集合视图读回顶点与边数据
写出VerticesBuilder、EdgesBuilder(high_level)逐条组装顶点/边并写出为 Parquet 数据

3.2 元数据三件套:GraphInfo、VertexInfo、EdgeInfo

GraphInfo.load(path) 从图级 YAML 加载元数据,随后可按类型名取到 VertexInfo/EdgeInfo。三者对应磁盘上的三层 YAML 文件(字段详解见《Apache GraphAr 格式规格与元数据详解》),读取侧的典型入口是:

  • graph_info.get_name()、graph_info.get_prefix():图名与数据根前缀;
  • graph_info.get_vertex_info(type)、graph_info.get_edge_info(src, edge, dst):取子元数据;
  • vertex_info.get_chunk_size()、vertex_info.get_property_groups():分块大小与属性分组。

3.3 读取集合:VerticesCollection 与 EdgesCollection

高层读取 API 位于 graphar.high_level:

  • VerticesCollection.Make(graph_info, vertex_type):构建某顶点类型的集合,size() 取总数,迭代得到 Vertex 对象,用 vertex.id() 与 vertex.property(name) 取值;
  • EdgesCollection.Make(graph_info, src_type, edge_type, dst_type, adj_list_type):构建某边类型在某邻接表布局下的集合,迭代得到 Edge 对象,用 edge.source()、edge.destination()、edge.property(name) 取值。

3.4 写出构建器:VerticesBuilder 与 EdgesBuilder

写出侧通过工厂方法创建构建器:

  • VerticesBuilder.Make(vertex_info, dir, num_vertices):dir 为输出目录(务必以斜杠结尾,见第七章排障点),之后 BuilderVertex 逐个 AddProperty 并 AddVertex,最后 Dump() 落盘;
  • EdgesBuilder.Make(edge_info, dir, adj_list_type, num_vertices):额外指定邻接表布局,BuilderEdge(src, dst) 加属性后 AddEdge,Dump() 落盘。

两者都支持 SetValidateLevel(types.ValidateLevel.strong_validate) 打开强校验,让非法数据在写出前报错。

💡 技术拓展:adj_list_type 决定边数据在磁盘上的组织方式,可选值与经典图存储结构对应如下——

AdjListType对应结构特点适用场景
unordered_by_sourceCOO按写入顺序存放边,无排序开销追加写、全量扫描
ordered_by_sourceCSR按源顶点排序 + offset 索引沿出边遍历(图计算主流)
ordered_by_destCSC按目的顶点排序 + offset 索引沿入边遍历

本文实战二实际采用 ordered_by_dest(与官方测试代码一致),以验证 CSC 布局下读回的排序语义。

四、实战一:读取官方 ldbc_sample 数据集

4.1 示例代码

官方示例脚本位于 /opt/incubator-graphar/python/example/graph_info_example.py(元数据访问)与 high_level_example.py(数据读取),以下摘录与 API 直接相关的核心代码(完整脚本含 Apache License 头,见官方仓库):

import os
import graphar
import graphar.high_level as gar_api
import graphar.types as types


def load_graph_info():
    test_data_dir = os.environ.get("GAR_TEST_DATA")
    graph_yaml_path = os.path.join(
        test_data_dir, "ldbc_sample/parquet/ldbc_sample.graph.yml")
    graph_info = graphar.GraphInfo.load(graph_yaml_path)
    print(f"Graph name: {graph_info.get_name()}")
    print(f"Graph prefix: {graph_info.get_prefix()}")
    return graph_info


def access_vertex_info(graph_info):
    vertex_info = graph_info.get_vertex_info("person")
    print(f"Vertex type: {vertex_info.get_type()}")
    print(f"Chunk size: {vertex_info.get_chunk_size()}")
    print(f"Vertex prefix: {vertex_info.get_prefix()}")
    property_groups = vertex_info.get_property_groups()
    for i, pg in enumerate(property_groups):
        for prop in pg.get_properties():
            print(f"    - {prop.name}: {prop.type} (primary: {prop.is_primary})")


def access_edge_info(graph_info):
    edge_info = graph_info.get_edge_info("person", "knows", "person")
    print(f"Edge type: {edge_info.get_edge_type()}")
    print(f"Source type: {edge_info.get_src_type()}")
    print(f"Destination type: {edge_info.get_dst_type()}")
    print(f"Chunk size: {edge_info.get_chunk_size()}")
    print(f"Directed: {edge_info.is_directed()}")
    adj_list_types = [
        types.AdjListType.unordered_by_source,
        types.AdjListType.ordered_by_source,
        types.AdjListType.unordered_by_dest,
        types.AdjListType.ordered_by_dest,
    ]
    for adj_list_type in adj_list_types:
        if edge_info.has_adjacent_list_type(adj_list_type):
            adj_list = edge_info.get_adjacent_list(adj_list_type)
            print(f"  - {adj_list.get_type()}: {adj_list.get_file_type()}")


def demonstrate_vertices_collection(graph_info):
    vertices = gar_api.VerticesCollection.Make(graph_info, "person")
    print(f"Total number of vertices: {vertices.size()}")
    count = 0
    for vertex in vertices:
        if count >= 5:
            break
        print(f"Vertex ID: {vertex.id()}, Name: {vertex.property('firstName')} {vertex.property('lastName')}")
        count += 1


def demonstrate_edges_collection(graph_info):
    edges = gar_api.EdgesCollection.Make(
        graph_info, "person", "knows", "person", types.AdjListType.ordered_by_source)
    print(f"Total number of edges: {edges.size()}")
    count = 0
    for edge in edges:
        if count >= 5:
            break
        print(f"Edge: {edge.source()} -> {edge.destination()}, Creation Date: {edge.property('creationDate')}")
        count += 1

4.2 运行元数据示例与实测回显

cd /opt/incubator-graphar/python/example && GAR_TEST_DATA=/opt/incubator-graphar/testing python graph_info_example.py
GraphAr GraphInfo Example
=========================
Graph name: ldbc_sample
Graph prefix: /opt/incubator-graphar/testing/ldbc_sample/parquet/

--- Vertex Info ---
Vertex type: person
Chunk size: 100
Vertex prefix: vertex/person/
Properties:
  Group 0:
    - id: <graphar._core.DataType object at 0x708598342170> (primary: True)
  Group 1:
    - firstName: <graphar._core.DataType object at 0x708598341b70> (primary: False)
    - lastName: <graphar._core.DataType object at 0x708598341b70> (primary: False)
    - gender: <graphar._core.DataType object at 0x708598341b70> (primary: False)

--- Edge Info ---
Edge type: knows
Source type: person
Destination type: person
Chunk size: 1024
Directed: False
Adjacency list types:
  - AdjListType.unordered_by_source: FileType.PARQUET
  - AdjListType.ordered_by_source: FileType.PARQUET
  - AdjListType.ordered_by_dest: FileType.PARQUET
Properties:
  Group 0:
    - creationDate: <graphar._core.DataType object at 0x7085983426b0>

Example completed successfully!

💡 说明:- id: <graphar._core.DataType object at 0x708598342170> 这类输出是官方示例直接打印 C++ 绑定对象造成的,属正常现象;类型本体可通过 YAML 元数据确认(如 id 为 int64)。

4.3 运行数据读取示例与实测回显

cd /opt/incubator-graphar/python/example && GAR_TEST_DATA=/opt/incubator-graphar/testing python high_level_example.py
GraphAr High-Level API Example
==============================

--- Vertices Collection ---
Total number of vertices: 903
Vertex ID: 0, Name: Mahinda Perera
Vertex ID: 1, Name: Eli Peretz
Vertex ID: 2, Name: Joseph Anderson
Vertex ID: 3, Name: Yacine Abdelli
Vertex ID: 4, Name: Jose Alonso

--- Edges Collection ---
Total number of edges: 6626
Edge: 0 -> 87, Creation Date: 2010-07-30T15:19:53.298+0000
Edge: 0 -> 623, Creation Date: 2012-04-12T13:56:58.931+0000
Edge: 0 -> 849, Creation Date: 2010-10-27T02:33:06.288+0000
Edge: 1 -> 58, Creation Date: 2011-07-27T15:43:14.869+0000
Edge: 1 -> 318, Creation Date: 2011-06-16T11:28:39.623+0000

Example completed successfully!

4.4 结果解读

  • ldbc_sample 图含 903 个 person 顶点与 6626 条 knows 边,均从 Parquet 数据文件按元数据自动读出,无需人工指定任何文件路径;
  • 顶点按 chunk_size 100 切成 10 个数据文件、边按 chunk_size 1024 分 part 存储,集合 API 屏蔽了全部分块细节;
  • EdgesCollection 指定 ordered_by_source 布局后,返回顺序按源顶点 id 升序组织(0 的出边在前、1 的出边在后),与 CSR 语义一致。

五、实战二:自建图写出与读回闭环

5.1 完整代码

从零建图不要求手工编写全部元数据:实测验证的最短路径是「加载一份官方元数据,复用其 VertexInfo/EdgeInfo 组装自己的 GraphInfo,再用 Builder 写出数据」。以下脚本(保存为 /root/graphar_quickstart.py)完整演示该闭环:

import os
import shutil

import graphar as gar
import graphar.types as types
from graphar.high_level import (
    VerticesCollection,
    EdgesCollection,
    BuilderVertex,
    VerticesBuilder,
    BuilderEdge,
    EdgesBuilder,
)

TEST_DATA = "/opt/incubator-graphar/testing"
OUT = "/root/graphar-demo"

shutil.rmtree(OUT, ignore_errors=True)
shutil.rmtree(OUT + "vertex", ignore_errors=True)
shutil.rmtree(OUT + "edge", ignore_errors=True)
os.makedirs(OUT)

# 第 1 步:加载官方示例图元数据,确认加载通道可用
modern = gar.GraphInfo.load(f"{TEST_DATA}/modern_graph/modern_graph.graph.yml")
print("[1] GraphInfo loaded:", modern.get_name())
print("    vertex types:", [vi.get_type() for vi in modern.get_vertex_infos()])
print("    edge types  :",
      [(ei.get_src_type(), ei.get_edge_type(), ei.get_dst_type())
       for ei in modern.get_edge_infos()])

# 第 2 步:复用 ldbc_sample 的 VertexInfo/EdgeInfo 组装新 GraphInfo 并保存三层 YAML
ldbc = gar.GraphInfo.load(
    f"{TEST_DATA}/ldbc_sample/parquet/ldbc_sample.graph.yml")
vertex_info = ldbc.get_vertex_info("person")
edge_info = ldbc.get_edge_info("person", "knows", "person")

graph_info = gar.GraphInfo("demo_graph", [vertex_info], [edge_info],
                           prefix=OUT + "/", version=vertex_info.version())
# save() 生成的 graph.yml 固定按 <类型名>.vertex.yaml / <类型名>.edge.yaml 引用子文件,
# 三个文件名必须与该规则一致,否则重新 load 时会报 IOError 打不开 person.vertex.yaml
vertex_info.save(OUT + "/person.vertex.yaml")
edge_info.save(OUT + "/person_knows_person.edge.yaml")
graph_info.save(OUT + "/demo_graph.graph.yml")
print("[2] metadata yaml saved to", OUT, "->", sorted(os.listdir(OUT)))

# 第 3 步:VerticesBuilder 写出 3 个顶点(目录参数务必带尾斜杠,见第七章排障点)
vertices_data = [
    (0, "John", "Smith", "male"),
    (1, "Jane", "Doe", "female"),
    (2, "Alice", "Wonderland", "female"),
]
vbuilder = VerticesBuilder.Make(vertex_info, OUT + "/", 0)
vbuilder.SetValidateLevel(types.ValidateLevel.strong_validate)
for vid, fn, ln, g in vertices_data:
    v = BuilderVertex()
    v.AddProperty("id", vid)
    v.AddProperty("firstName", fn)
    v.AddProperty("lastName", ln)
    v.AddProperty("gender", g)
    vbuilder.AddVertex(v)
print("[3] vertices to write:", vbuilder.GetNum())
vbuilder.Dump()
print("    Dump OK ->", OUT)

# 第 4 步:EdgesBuilder 写出 4 条边(ordered_by_dest 布局)
edges_data = [
    (1, 0, "2010-01-01"),
    (0, 1, "2011-01-01"),
    (0, 2, "2012-01-01"),
    (2, 1, "2013-01-01"),
]
ebuilder = EdgesBuilder.Make(edge_info, OUT + "/",
                             types.AdjListType.ordered_by_dest,
                             len(vertices_data))
ebuilder.SetValidateLevel(types.ValidateLevel.strong_validate)
for s, d, date in edges_data:
    e = BuilderEdge(s, d)
    e.AddProperty("creationDate", date)
    ebuilder.AddEdge(e)
print("[4] edges to write:", ebuilder.GetNum())
ebuilder.Dump()
print("    Dump OK ->", OUT)

# 第 5 步:重新加载元数据并读回全部数据验证
gi2 = gar.GraphInfo.load(OUT + "/demo_graph.graph.yml")
vc = VerticesCollection.Make(gi2, "person")
print("[5] vertices read back:", vc.size())
for v in vc:
    print("    vertex id=%s name=%s %s gender=%s" % (
        v.property("id"), v.property("firstName"),
        v.property("lastName"), v.property("gender")))

ec = EdgesCollection.Make(gi2, "person", "knows", "person",
                          types.AdjListType.ordered_by_dest)
print("    edges read back:", ec.size())
for e in ec:
    print("    edge %s -> %s creationDate=%s" % (
        e.source(), e.destination(), e.property("creationDate")))

print("ALL DONE")

5.2 运行与实测回显

/opt/venv-graphar/bin/python /root/graphar_quickstart.py
[1] GraphInfo loaded: modern_graph
    vertex types: ['person', 'software']
    edge types  : [('person', 'knows', 'person'), ('person', 'created', 'software')]
[2] metadata yaml saved to /root/graphar-demo -> ['demo_graph.graph.yml', 'person.vertex.yaml', 'person_knows_person.edge.yaml']
[3] vertices to write: 3
    Dump OK -> /root/graphar-demo
[4] edges to write: 4
    Dump OK -> /root/graphar-demo
[5] vertices read back: 3
    vertex id=0 name=John Smith gender=male
    vertex id=1 name=Jane Doe gender=female
    vertex id=2 name=Alice Wonderland gender=female
    edges read back: 4
    edge 1 -> 0 creationDate=2010-01-01
    edge 0 -> 1 creationDate=2011-01-01
    edge 2 -> 1 creationDate=2013-01-01
    edge 0 -> 2 creationDate=2012-01-01
ALL DONE

写出与读回全部成功。注意边读回顺序为 1→0、0→1、2→1、0→2:ordered_by_dest 布局先按目的顶点排序(0、1、1、2),同目的内再按源顶点排序,符合 CSC 语义。

5.3 排障实录一:save() 的子文件命名固定为 .yaml 后缀

首次运行本脚本时第 2 步把顶点元数据保存成了 person.vertex.yml,随后重新 load 报错:

ValueError: IOError: Failed to open local file '/root/graphar-demo/person.vertex.yaml'. Detail: [errno 2] No such file or directory

定位过程:检查 graph_info.save() 生成的 demo_graph.graph.yml 内容,发现其中对子元数据的引用固定写作 person.vertex.yaml、person_knows_person.edge.yaml,与保存时使用的 .yml 后缀不一致。结论:使用 GraphInfo.save() 时,子元数据文件必须按 <类型名>.vertex.yaml、<源类型>_<边类型>_<目的类型>.edge.yaml 命名保存,改齐后问题消失。

5.4 排障实录二:Builder 目录参数必须带尾斜杠

第二次运行时把 Builder 的目录参数写成了 OUT(即 /root/graphar-demo,不带尾斜杠),Dump() 照样返回成功,但读回阶段报错:

RuntimeError: IOError: Failed to open local file '/root/graphar-demo/vertex/person/vertex_count'. Detail: [errno 2] No such file or directory

排查:用 find 检查磁盘,数据实际被写到了 /root/graphar-demovertex/person/vertex_count 与 /root/graphar-demoedge/ 目录下——Builder 的目录参数与元数据 prefix 是纯字符串拼接,目录不带尾斜杠会静默丢失路径分隔符(0.13.0.dev1 实测行为)。修正为统一传 OUT + "/" 后,写出与读回路径一致,闭环通过。

⚠️ 注意:这类「写偏了但报成功」的问题读回端才会暴露,建议每次 Dump 后用 find <输出目录> -type f 核对实际落盘位置(见第六章)。

5.5 闭环验证

最后用 CLI 校验自建图的元数据规范性:

graphar check -p /root/graphar-demo/demo_graph.graph.yml
INFO     Graph is valid

六、产出目录结构解析

自建图闭环跑通后,/root/graphar-demo 的完整产出如下(实测):

find /root/graphar-demo -type f | sort
/root/graphar-demo/demo_graph.graph.yml
/root/graphar-demo/edge/person_knows_person/ordered_by_dest/adj_list/part0/chunk0
/root/graphar-demo/edge/person_knows_person/ordered_by_dest/creationDate/part0/chunk0
/root/graphar-demo/edge/person_knows_person/ordered_by_dest/edge_count0
/root/graphar-demo/edge/person_knows_person/ordered_by_dest/offset/chunk0
/root/graphar-demo/edge/person_knows_person/ordered_by_dest/vertex_count
/root/graphar-demo/person.vertex.yaml
/root/graphar-demo/person_knows_person.edge.yaml
/root/graphar-demo/vertex/person/firstName_lastName_gender/chunk0
/root/graphar-demo/vertex/person/id/chunk0
/root/graphar-demo/vertex/person/vertex_count

逐项说明:

文件/目录作用
demo_graph.graph.yml图级元数据,引用下面两个子元数据文件
person.vertex.yamlperson 顶点类型元数据(chunk_size、属性分组)
person_knows_person.edge.yamlknows 边类型元数据(三种邻接表声明、属性)
vertex/person/<属性组prefix>/chunk0顶点属性数据,每个属性组一个目录,按 chunk 切分
vertex/person/vertex_count顶点计数文件(8 字节定长,本图为 3)
edge/person_knows_person/ordered_by_dest/adj_list/part0/chunk0邻接表本体(源/目的顶点索引对)
edge/person_knows_person/ordered_by_dest/creationDate/part0/chunk0边属性数据,行序与邻接表一致
edge/person_knows_person/ordered_by_dest/offset/chunk0CSC 式 offset 索引
edge/person_knows_person/ordered_by_dest/edge_count0边计数文件(本图为 4)
edge/person_knows_person/ordered_by_dest/vertex_count参与该布局的目的顶点段计数

数据文件虽无 .parquet 扩展名,但实测文件头尾均为 Parquet 魔数(PAR1),任何 Parquet 读取器都能直接打开。

七、注意事项

以下均为本次实战实测确认的行为约束,写代码前对照检查可避免大部分返工:

  1. 包名必须是 graphar:pygraphar 是 GraphScope 的占位包,安装直接失败;
  2. save() 子文件命名:GraphInfo.save() 生成的图级 YAML 固定按 <类型名>.vertex.yaml、<源>_<边>_<目的>.edge.yaml 引用子文件,自存元数据必须用同名文件;
  3. Builder 目录参数带尾斜杠:VerticesBuilder.Make/EdgesBuilder.Make 的目录参数与 prefix 是字符串直拼,不带 / 会静默写到错位路径且 Dump 不报错;
  4. DataType 无工厂方法:Python 绑定不能凭空构造属性类型,从零建图请加载官方或已有元数据后复用其 VertexInfo/EdgeInfo(实测 Property("id", None) 能构造但 save 校验会报 vertex info not validated);
  5. GraphInfo.prefix 决定读写闭环:自建图把 GraphInfo 的 prefix 设为绝对输出目录(带尾斜杠),Builder 写出与 Collection 读回才能对齐同一路径;
  6. 边读回顺序由布局决定:ordered_by_dest 下先按目的顶点、再按源顶点排序,业务侧不要假设与写入顺序一致;
  7. 强校验建议常开:SetValidateLevel(types.ValidateLevel.strong_validate) 能在写出前拦截非法数据,代价可忽略。

八、参考链接