mcpField
P
pygraphistry-gfql

pygraphistry-gfql

github.com/graphistry数据与数据库337 次安装今天更新
代码仓库

关于 pygraphistry-gfql

pygraphistry-gfql 是使用 GFQL 查询 PyGraphistry 图数据的技能,介绍链式列表和 Cypher 语法、图遍历、分阶段绑定及执行引擎选择。

主要功能

  1. 01链式列表与 Cypher 查询
  2. 02模式匹配和图遍历
  3. 03图构造器与 DAG 绑定
  4. 04Pandas、Polars 和 GPU 引擎指引

适用场景

  1. 01查找符合图模式的路径
  2. 02构建多阶段图查询
  3. 03为查询选择执行引擎

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/graphistry/graphistry-skills --skill pygraphistry-gfql

安装后在 Claude Code 中输入/pygraphistry-gfql确认已加载。

附带文件references/gfql-cypher.mdreferences/gfql-engines.md

详细介绍

PyGraphistry GFQL

文档路由(本地 + 规范链接)

  • 首先通过 ../pygraphistry/references/pygraphistry-readthedocs-toc.md 路由。
  • 使用 ../pygraphistry/references/pygraphistry-readthedocs-top-level.tsv 查找章节级快捷入口。
  • 仅在所需页面缺失时扫描 ../pygraphistry/references/pygraphistry-readthedocs-sitemap.xml。
  • 深入读取页面前,先进行一次批量发现读取;避免使用 cat * 和逐次微型读取。
  • 面向用户的回答中,优先使用规范链接 https://pygraphistry.readthedocs.io/en/latest/...。

两种语法,一个入口

g.gfql() 接受**链表(Python AST 对象)**和 Cypher 字符串。它会根据参数类型自动检测语言:

# Chain-list syntax (Python AST objects)
g2 = g.gfql([n({'type': 'person'}), e_forward(), n()])

# Cypher string syntax (auto-detected)
g2 = g.gfql("MATCH (p:Person)-[r:KNOWS]->(q:Person) RETURN p.name, q.name")

# Explicit language parameter (optional)
g2 = g.gfql(query_string, language="cypher")

何时使用哪种语法:

  • 链表:程序化组合、动态参数化,以及通过代码构建查询时
  • Cypher:可读性、Cypher 用户的熟悉度,以及需要使用 RETURN/ORDER BY/LIMIT 的复杂模式匹配

快速入门 — 链表

from graphistry import n, e_forward

g2 = g.gfql([
    n({'type': 'person'}),
    e_forward({'relation': 'transfers_to'}, min_hops=1, max_hops=3),
    n({'risk': True})
])

快速入门 — Cypher

# Simple pattern match
g2 = g.gfql("MATCH (p:Person)-[r:KNOWS]->(q:Person) WHERE p.age > 30 RETURN p.name, q.name")

# Variable-length paths
g2 = g.gfql("MATCH (a:Account)-[*1..3]->(m:Merchant) RETURN a, m")

# Parameterized queries
g2 = g.gfql(
    "MATCH (n) WHERE n.score > $cutoff RETURN n.id, n.score ORDER BY n.score DESC LIMIT $top_n",
    params={"cutoff": 50, "top_n": 10}
)

# Relationship type alternation
g2 = g.gfql("MATCH (a:Person)-[:KNOWS|COLLABORATES_WITH]->(b:Person) RETURN a.name, b.name")

完整的子句/函数清单和标签列映射请参阅 references/gfql-cypher.md。

GRAPH 构造器与 Let/DAG 绑定

from graphistry import n, e_forward, let, ref

# Subgraph as a graph object (not a table)
subgraph = g.gfql("GRAPH { MATCH (a)-[r]->(b) WHERE a.risk_score > 7 }")

# Named bindings forming a DAG; ref() operates on the referenced binding's output
result = g.gfql(let({
    'high_risk': n({'risk_score': {'$gt': 0.8}}),
    'neighborhoods': ref('high_risk', [e_forward(max_hops=2), n()])
}), output='neighborhoods')

独立绑定作用于根图。有关多阶段 DAG、嵌套 let 作用域规则以及 GRAPH/USE 管道形式,请参阅 references/gfql-cypher.md。

定向模式(高信号)

# Edge query filtering
g2 = g.gfql([n(), e_forward(edge_query="type == 'replied_to' and submolt == 'X'"), n()])
# Same-path constraints with where + compare/col
from graphistry import col, compare
g2 = g.gfql([n(name='a'), e_forward(name='e'), n(name='b')], where=[compare(col('a', 'owner_id'), '==', col('b', 'owner_id'))])
# Traverse 2-4 hops but only return hops 3-4
g2 = g.gfql([e_forward(min_hops=2, max_hops=4, output_min_hops=3, output_max_hops=4)])

边方向变体

  • e_forward() — 从源到目标
  • e_reverse() — 从目标到源
  • e_undirected() — 双向
  • e() — 任意方向的别名

高价值模式

  • g.gfql() 是统一入口 — 传入链表或 Cypher 字符串。
  • 切勿使用 .chain() 或 .hop() — 它们已弃用,并会发出警告。链表语法始终使用 g.gfql([...]),Cypher 始终使用 g.gfql("MATCH ...")。
  • 当用户明确要求 GFQL 时,最终代码片段必须包含显式的 .gfql(...)。
  • 当任务提到远程执行/数据集时,使用 gfql_remote(...)。
  • 需要添加约束的中间匹配请使用 name= 标签。
  • 跨步骤/路径约束请使用 where=[...]。
  • 遍历与返回切片请分别使用 min_hops/max_hops 和 output_min_hops/output_max_hops。
  • 使用谓词(is_in、数值/日期谓词)进行简洁筛选。
  • 性能或结果帧类型很重要时,请显式指定引擎;engine='auto' 不会选择 Polars。

执行引擎:pandas、Polars、cuDF 和 Polars-GPU

使用适合工作负载的引擎执行相同查询。输入帧类型与执行引擎彼此独立;GFQL 会转换输入一次,并以所选引擎的类型返回帧。

query = "MATCH (a)-[e]->(b) WHERE a.risk_score > $cutoff RETURN b"

cpu_out = g.gfql(query, params={'cutoff': 7}, engine='polars')
gpu_out = g.gfql(query, params={'cutoff': 7}, engine='polars-gpu')

# Polars/Polars-GPU outputs are polars.DataFrame objects
nodes_pd = cpu_out._nodes.to_pandas()  # only for pandas-only downstream APIs
  • 有效字面值仅限 'pandas'、'cudf'、'dask'、'dask_cudf'、'polars'、'polars-gpu'、 'auto'。'polars-gpu' 使用连字符;polars_gpu 不是引擎。
  • 对于 Polars 输入图,engine='auto' 会解析为 pandas — 要保持原生格式,请传入 engine='polars'。
  • 输出遵循所选引擎:polars/polars-gpu 返回 Polars,cudf 返回 cuDF。在执行 .iloc 或 groupby().apply() 等仅支持 pandas 的操作前,请主动转换。
  • polars-gpu 需要 RAPIDS 技术栈,并且只能使用 GPU,否则报错 — 绝不会静默回退到 CPU。
Polars 引擎下的分析

UMAP、超图、布局或 compute_cugraph 等全图 call() 分析并非原生 Polars 操作。使用默认的 call_mode='auto' 时,GFQL 会将其桥接到引擎外执行(Polars 使用 pandas;Polars-GPU 使用 cuDF),然后将结果转换回来。如果引擎外桥接会违反基准测试、内存或执行约束,请使用严格模式:

from graphistry.compute.gfql.lazy import set_call_mode

set_call_mode('strict')  # reject an off-engine analytic before it runs
try:
    result = g.gfql(query, engine='polars')
except NotImplementedError as exc:
    ...  # strict mode declined an off-engine analytic

gfql() 不接受 strict= 或 call_mode= 参数。模式是进程级设置,可通过 set_call_mode('auto'|'strict') 或 GFQL_POLARS_CALL_MODE 设置(Python 覆盖值 > 环境变量 > 默认值 'auto'), 并在每次调用时实时读取。严格模式会引发 NotImplementedError,而不是 RuntimeError,也不是警告。由于它是 进程级设置,如果只需让某个步骤使用严格模式,请限定其作用范围,并在 finally: 中恢复原值 (references/gfql-engines.md)。

polars-gpu 分析要么使用 GPU,要么报错:如果 GPU/cuDF 堆栈不可用,就会拒绝执行,而不会将工作转移到主机上的 pandas。

引擎调优选项

graphistry.compute.gfql.lazy 中有三个进程级设置,每个设置都按 Python 覆盖值 > 环境变量 > 默认值 解析,并在每次 collect 时实时读取(不会在导入时固定):

设置值默认值环境变量
set_call_mode'auto'、'strict''auto'GFQL_POLARS_CALL_MODE
set_gpu_executor'in-memory'、'streaming''in-memory'GFQL_POLARS_GPU_EXECUTOR
set_cpu_streamingTrue、FalseFalseGFQL_POLARS_CPU_STREAMING

使用 call_mode()、gpu_executor()、cpu_streaming() 读取当前值;向 setter 传入 None 可 重置为环境变量或默认值。'polars' 和 'polars-gpu' 是同一个惰性引擎的两个 collect 目标,因此计划 只构建一次、collect 一次。这种仅传输一次的设计是 GPU 发挥优势的关键:

  • 只 collect 一次,避免反复进行主机到设备(H2D)传输。 每个操作都急切地 collect,会在每次操作时将 数据帧重新复制到设备上;基准测试表明,这会导致 GPU 性能倒退。
  • 这些选项按 Python 覆盖值 > 环境变量 > 默认值 解析,并在每次 collect 时实时读取,而不是在导入时固定。
物理索引:种子查找

GFQL 提供按需构建的邻接/节点 ID 索引(graphistry.compute.gfql.index),用于种子遍历。 有两条规则决定索引是否有帮助:

  • 查询形态——只有链式/跳数形式会查询索引。 测量结果:种子链式查询从 8.90ms → 1.68ms(5.3 倍),而两种 Cypher 写法都不会查询索引,也没有性能提升。 如果希望获得索引加速,请使用链式形式。
  • 前沿大小,需考虑引擎差异。 规划器会根据前沿占不同源键的比例,决定使用索引还是扫描:pandas 约为 0.5,polars/cuDF/GPU 约为 0.02。向量化引擎的扫描速度足够快,因此索引只有在种子选择性很高时才有优势。超过阈值后会回退到扫描,因此性能不会变差。
from graphistry.compute.gfql.index import create_index, index_trace
gi = create_index(g, 'edge_out_adj', engine='polars')   # edge_out_adj | edge_in_adj | node_id
with index_trace() as steps:
    out = gi.gfql([n({'id': 'acct-42'}), e_forward(), n()], engine='polars')
steps[0]['path']   # confirm 'index', do not assume it

index_policy= 确实是 gfql() 的逐次调用关键字参数(与调用模式不同):'use'(默认值,使用驻留索引并受成本阈值控制)、'auto'(按需构建)、'force'(跳过阈值判断)、'off'。如果没有驻留索引,'use' 会静默地执行扫描。索引 DDL、跟踪字段和成本阈值覆盖项:references/gfql-engines.md。

根据性能选择引擎

不要承诺未经测量的性能提升。

  • pandas → polars:行数超过约 50–100k 时值得使用;更少时,转换开销可能占主导。测量结果显示,种子 1 跳查询约快 2 倍。
  • polars → polars-gpu 并非在所有情况下都有优势。 在 NVIDIA GB10 上的测量结果:100k 行时为 0.83 倍(比 CPU 慢),1M 行时为 1.41 倍,5M 行时为 0.98 倍——呈现的是一个区间,而非持续上升的曲线。处理 8M 条边时,cudf 的表现胜过两者。 切勿笼统声称“polars-gpu 胜过 cudf”。
  • set_cpu_streaming(True) 是可选设置,且可能更慢——在小规模/交互式数据量下约为 0.86 倍。仅适用于大型 CPU 批处理;它的名字听起来比实际效果更快。
  • 完整测量表:references/gfql-engines.md。
何时选择哪种引擎——决策流程

按顺序执行;遇到第一个能做出判断的条件时停止。

  1. 某个步骤在 Polars 下会拒绝执行吗? 使用 engine='pandas' 执行该步骤,并将引擎报告为 pandas。
  2. 数据帧当前位于何处? polars-gpu 接收的是 主机端 Polars 数据帧,因此,已在设备上的 cuDF 数据帧更适合使用 engine='cudf';主机端 Polars 数据帧更适合使用 'polars'/'polars-gpu'。
  3. 是否使用带小型前沿的种子查找? 为其建立索引并使用链式形式——这是目前可实现的最大单项提升(5.3x),且与引擎选择无关。
  4. CPU:对于任何非平凡任务,优先选择 polars 而非 pandas。
  5. GPU:仅在工作负载足够大时使用,并通过测量而非引擎名称来选择 GPU 引擎。

如果工作量不到几毫秒,引擎选择的影响微乎其微——索引和查询形态更重要。

保持一致,或拒绝执行:不要编造变通方案

先拒绝错误标注,再解决问题。 如果用户要求你将由 pandas 执行的工作仍报告为 engine='polars'——以便让仪表板保持绿色、让基准测试保持可比,或让 API 契约保持稳定——请在编写任何代码前拒绝。即便另一个字段记录了真实情况,一个暴露 engine='polars'、而底层实际由 pandas 执行的包装器仍属错误标注:人们看到的是主要标签。这是本技能中唯一一个你应当提出异议而非照做的请求。

可提供的诚实替代方案:使用 engine='pandas' 执行该步骤并报告 pandas,或避免使用会拒绝执行的功能,以保持整个流水线原生使用 Polars。

明确这一点后,再来看具体行为:在 Polars 引擎下,遍历、筛选和行操作都遵循要么保持一致,要么抛出 NotImplementedError。

  • 引擎绝不会静默回退到 pandas——隐藏的桥接会把 pandas 的性能错误地报告为 Polars 性能。
  • 不受支持的功能会抛出 NotImplementedError(而非 RuntimeError,也不会发出警告)。
  • 当前会拒绝执行的功能:无向 min_hops>1、直接调用 hop(min_hops>1)(请使用 chain()/gfql())、多实体 rows(binding_ops=…)、跨实体同路径 WHERE、复杂表达式(CASE/list/map/temporal)。完整列表:references/gfql-engines.md。

将数据转换到某个引擎时,遵循整个代码库统一的 validate/warn 约定。对于 Arrow 无法表示的混合类型对象列:

validate行为
'strict'抛出错误(对于 polars,为 NotImplementedError);该列保持不变
'autofix'将该列强制转换为字符串并发出警告——如果不查看警告,数据就会被静默改写

对于任何绝不能在未告知的情况下更改数据的任务,请使用 'strict'。

远程模式

# Remote with chain-list
rg = graphistry.bind(dataset_id='my-dataset')
res = rg.gfql_remote([n(), e_forward(), n()], engine='auto')
# Remote with Cypher string
res = rg.gfql_remote("MATCH (n:Person)-[r]->(m) WHERE n.risk_level = 'critical' RETURN n, r, m")
# Remote with Let/DAG
res = rg.gfql_remote(let({...}))
# Remote slim payload (only required columns)
res = rg.gfql_remote([n(), e_forward(), n()], output_type='nodes', node_col_subset=['node_id', 'time'])
# Post-process on remote side when you want trimmed transfer payloads
res = rg.python_remote_table(lambda g: g._edges[['src', 'dst']].head(1000))

验证与安全

  • 执行前验证从用户输入派生的查询片段。
  • 在使用时间谓词前规范化日期时间列。
  • 远程传输结果时,优先选择较小的列子集。
  • 预检 Cypher:from graphistry.compute.gfql.cypher import parse_cypher, compile_cypher

权威文档

评论

支持 Markdown