想象你所在的整座城市有一个巨大的档案馆,里面存放着建城以来每一笔金融交易的原始凭证。要查某个人三年前的一笔转账,管理员只能抱着几十本厚账本从头翻起,而且每天闭馆时还会运来几车新账本——这就是区块链世界的原始体验:数据全都在,但想快速精准地找到某一条,难如大海捞针。The Graph 正是给这座档案馆修建的“现代图书馆检索系统”:专业的“图书管理员”提前把账本里的关键信息整理成一张张主题索引卡片,任何人来查询,只需递上一张检索单,几秒钟就能拿到答案。这篇文章就用“图书馆”贯穿全程,带你认识 The Graph 的协议架构、子图开发、GraphQL 查询与 GRT 通证激励。
掌握 The Graph,等于掌握了 Web3 开发者面对链上数据时最趁手的“检索技能”,无论做 DApp 前端、链上数据分析还是 DeFi 风控,你都能比同行更快拿到干净、规范的数据。
可视化演示
展示区块链数据索引管线、子图事件映射流程,以及去中心化索引市场的GRT质押激励机制。
本节配有交互动效(进入视口后自动加载,约 3KB)。
索引管线架构 链上数据:区块事件实时监听 索引节点:提取并转换链上数据 Query→GraphQL→Subgraph 索引节点将链上数据转为可查询格式
索引之困
想象你走进一座没有目录的档案馆:账本堆满整面墙,管理员找一笔三年前的转账,只能从第一本账本翻起,翻完 20 万页才发现记错了日期。更崩溃的是,每天闭馆时又会运来几车新账本。这种“全部数据都在,却无从下手”的状态,就是没有索引的区块链体验。
区块链上的全节点确实保存了自创世以来的每一笔数据,但要通过 JSON-RPC 接口“按条件查找”时,能力非常有限。比如想知道某个地址的历史转账,最常见的做法是从第一个区块开始逐个遍历,把每笔交易拉下来比对;想过滤某种类型的日志,还要手工构造主题过滤器并解析十六进制编码的日志。换个场景,如果想知道某个 DeFi 协议所有池子当前锁定了多少美元,靠一个一个区块翻出来再累加,几乎不可行,而且大部分公共 RPC 节点还会限流。
The Graph 解决的正是“检索效率”问题:它把链上事件预先解析、清洗、建模后存入数据库,对外提供索引接口。查询的复杂度从“全表扫描”降到“按索引查找”,效率提升可以用下面这个比值描述:
回到图书馆的比喻:管理员花大力气把账本整理成索引卡片,读者以后查资料就不用再从第一页翻起。The Graph 的价值,就是让“找数据”从体力活变成脑力活。
- 分子 n全链扫描需要依次检查的区块或交易数量,查询耗时与数据总量成正比。
- 分母 log₂n在已建立的索引上做二分或树形查找,最多需要比较的次数,增长速度远低于 n。
- 比值 η索引查询相对全链扫描的效率提升倍数。区块越多,η 越大,节省的时间越惊人。
三角色架构
一座图书馆要高效运转,不能只有一张服务台,还得有整理书籍的整理员、决定哪些书值得做专题索引的选书人、以及把书借给整理员并分享收益的市民。The Graph 网络也对应着三个核心角色:索引者(Indexer)、策展人(Curator)和委托人(Delegator),再加上发起查询的消费者(Consumer)。
索引者就是“图书管理员”,他们质押 GRT 通证运行索引节点,负责处理子图数据,并提供 GraphQL 查询服务;查询质量越高、响应越快,越能吸引消费者。策展人是“选书人”,他们发现某个子图有价值,就质押 GRT 对它发出“信号”,引导索引者优先为这个主题投入算力。委托人不想亲自运营节点,但想参与生态收益,便把自己的 GRT 委托给信任的索引者,按比例分享未来收益。消费者(通常是 DApp 或链上数据分析工具)发起查询,并支付对应的查询费。
三个角色的质押形成了一套权重体系。网络在分配查询工作量或收益时,会按质押占比计算权重:
图书馆里的人各司其职:整理员出力,选书人把关,市民出书,读者受益。The Graph 用通证把三个角色的利益绑在一起,形成一条互相促进的“查书流水线”。
- S_i索引者 i 所质押的 GRT 数量,代表他投入的资源与承诺。
- 分母 ΣS_j所有参与网络质押的 GRT 总量,包括全部索引者的质押。
- 权重 W_i索引者 i 在查询分配或收益中占的比例。质押越多,信誉越高,获得的查询流量也越多。
子图定义
图书馆里最值钱的东西,是那些“专题索引卡片”:比如“按作者姓名的索引”“按出版年份的索引”。The Graph 里这样的专题索引叫子图(Subgraph)。它不是把整条链复制一份,而是只针对某个协议或业务,抽取相关事件并建模成便于查询的实体。
一张专题索引卡片要能工作,需要三种信息:卡片版式、资料来源、摘抄规则。对应到子图就是三个文件。首先是 manifest(subgraph.yaml),它声明数据源——合约地址、网络、要监听哪些事件;然后是 schema.graphql,它定义实体模型,相当于卡片上有哪些栏目;最后是 mappings,由 AssemblyScript 编写,负责把链上事件“翻译”成对实体的增删改操作。
整个子图的核心逻辑,就是这样一个映射过程:
子图就像选书人亲手做的专题卡片集:不搬走整座档案馆,只摘录大家最常问的信息,并且持续跟随新账本更新,让“专题检索”又快又准。
- Event_chain链上产生的一个原始事件,比如一次转账或一次兑换,包含 topics 和 data 等原始字段。
- Entity_graph经过建模后的实体对象,例如用户、交易对、订单,拥有清晰的字段类型与关系。
- 映射函数 f_map由子图开发者编写的事件处理逻辑,决定事件如何被解码、清洗并写入索引数据库。
开发四步
写一张专题索引卡片也有固定工序:先领空白卡片模板,再填写卡片栏目,然后逐条摘抄账本内容,最后把卡片插入检索柜供读者使用。子图开发同样分四步。
第一步是初始化项目,使用 graph init 命令创建子图脚手架,自动生成项目目录和基础配置。第二步是编写配置与模型:在 subgraph.yaml 中填写合约地址与要监听的事件,在 schema.graphql 中定义实体和字段,随后运行代码生成器,把 schema 编译成 TypeScript 类型。第三步是编写映射逻辑,也就是在 mappings 中用 AssemblyScript 处理事件,把参数写到对应实体中。第四步是部署与验证,通过 graph deploy 上传子图,并在网关上执行一条测试查询确认数据正确。
随着新区块不断产生,索引也需要持续“追更”。这个过程可以看作一次并集更新:
就像图书馆每晚闭馆后都会把当天新到的账本摘录入卡片柜,子图也会在每个新区块出现后自动补充索引,读者第二天一早总能查到最新数据。
- S_t当前已经索引好的实体集合,即截至区块 t 的数据库快照。
- ΔS(block_{t+1})新产生的区块 t+1 中,被映射函数捕捉到的事件带来的实体变更。
- 并集更新新变更合并进已有集合,索引状态不断向前推进,与链上状态保持最终一致。
GraphQL查询
读者在图书馆里不用自己翻书,只需填一张“检索单”:要查什么字段、按什么条件过滤、按什么排序。这张检索单的语言就是 GraphQL。它由 The Graph 对外提供,但你把它当成一种通用的“点菜式”查询语言就好:你要什么,服务员给你上什么,不多不少。
一个典型查询会声明所需字段,并通过参数控制返回范围。比如查询“储备量最高的五个交易对”,可以指定实体类型 pairs,用 orderBy 按储备金排序,用 orderDirection 指定降序,再用 first 限制条数。嵌套关系也能一步带出:查交易对的同时,把对应的两个代币符号取出来。分页则通过 first 与 skip 游标实现,适合前端滚动加载。
从数据库角度看,这类查询可以被理解为先筛选、再投影的关系运算:
对比原来的体验:以前要把账本整段搬回来自己拆解,现在只需递上一张检索单,管理员几秒钟就把整理好的答案送到你面前。这就是 GraphQL 查询的魅力。
- σ_where(D_graph)对索引数据库先做条件过滤,只保留满足 where 条件的记录。
- π_fields(……)对过滤结果做字段投影,只摘取查询里要求的字段列。
- 结果 R最终返回给前端的数据结构,干净、嵌套清晰,省去大量手工解析。
GRT激励
图书馆要持续运转,需要电费、员工工资和新书采购费。The Graph 的“图书馆经费”由 GRT 通证承载,贯穿所有角色。索引者质押 GRT 才能获得服务资格;策展人质押 GRT 对子图发信号,引导资源流向优质主题;委托人把 GRT 委托给索引者,换取未来分成;消费者则在使用查询服务时支付 GRT。每一条链路都是实实在在的经济激励。
索引者的收益主要来自查询费分成。网络会按质押权重分配查询任务,质押越多、服务越好,分到的查询费就越高。把前面提到的权重公式代入收益计算,就是:
在这套机制里,策展人是“风向标”,委托人是“出资人”,索引者是“出力人”。谁的判断准、服务好,谁就能从图书馆的收入蛋糕中分到更大一块,生态也因此自我驱动、持续生长。
- F_q一段时间内该索引者服务的子图产生的查询费总额。
- 质押占比该索引者质押量占全网质押量的比例,决定他能分走查询费的份额。
- 收益 R_i索引者最终获得的查询费收入,质押与服务越好,收入越高。
实战落地
当这套“图书馆检索系统”建好之后,城市里到处都可以用:DApp 前端用它加载用户资产历史,数据分析平台用它聚合全协议的交易池数据,风控系统用它监听巨鲸异动。对 Web3 开发者来说,接入 The Graph 已经是常规操作。
实际工程中,性能与可靠性是绕不开的话题。一个请求的完整耗时可以简单拆成三段:
优化方向也由此而来:尽量让数据在后端过滤干净,避免一次拉取整张表;合理建模实体,减少不必要的连接查询;关注子图当前的索引区块高度,判断数据是否已经追到最新;部署时选择稳定的网关与索引者。把这几点做好,你的 DApp 就能享受到“图书馆检索系统”真正的快捷与稳定。
- L_network请求在公网上的往返延迟,取决于网关节点与索引者节点的位置。
- L_index索引者节点执行 GraphQL 查询、命中数据库索引的时间。
- L_serialize结果序列化并返回给前端所花的时间,字段越多越大。
AI 应用场景
DApp 前端数据接入
阶段:数据获取与特征前置
解决的问题:传统 DApp 需要前端重复调用 RPC,逐个解析日志、拼接逻辑,既慢又容易出错。子图把链上数据提前整理成结构化实体,前端一次 GraphQL 请求就能拿到全部所需字段,响应速度大幅提升。
具体案例:一个借贷类 DApp 需要展示用户的借还款历史、抵押率与利息累计。接入子图后,前端只需按用户地址查询“用户实体 + 借还款列表”,原本数百行 RPC 轮询与日志解码代码缩成了几十行查询语句。
链上数据聚合看板
阶段:数据清洗与聚合
解决的问题:分析平台要统计某协议所有流动性池的总锁仓量、交易量、手续费等指标,靠链上逐块扫描几乎不可能实时完成。子图天然支持跨实体的聚合与排序,能满足仪表盘的实时刷新需求。
具体案例:一个 DeFi 排名网站通过查询某交易平台的子图接口,按储备量倒序拉取 Top 20 交易对,结合代币价格计算协议级 TVL,并绘制趋势图。整个数据链路从“小时级”升级为“秒级”。
大额异动监控告警
阶段:实时事件监听
解决的问题:安全团队希望第一时间发现巨鲸转账、协议异常提款等事件。子图对转账事件做了实体化建模,配合过滤条件即可完成高吞吐量监听,无需自己部署索引服务。
具体案例:某风控平台利用子图监控目标地址的 Transfer 事件,当单笔金额超过阈值时触发 webhook 告警,并在看板上展示资金流向图。相比原生 RPC 轮询,误报率更低、延迟更短。
Python 演示
import jsonimport urllib.request SUBGRAPH_URL = "https://api.thegraph.com/subgraphs/name/uniswap/uniswap-v2" QUERY = """{ pairs(orderBy: reserveUSD, orderDirection: desc, first: 5) { id token0 { symbol } token1 { symbol } reserveUSD }}""" def query_subgraph(endpoint, graphql_query): request = urllib.request.Request( endpoint, data=json.dumps({"query": graphql_query}).encode("utf-8"), headers={"Content-Type": "application/json"}, ) with urllib.request.urlopen(request, timeout=15) as response: return json.loads(response.read().decode("utf-8")) def main(): try: result = query_subgraph(SUBGRAPH_URL, QUERY) except urllib.error.URLError as exc: raise SystemExit("网络请求失败: {}".format(exc)) if "errors" in result: raise SystemExit("子图返回错误: {}".format(result["errors"])) pairs = result["data"]["pairs"] print("Uniswap V2 按储备量排序的 Top5 交易对:") for pair in pairs: symbol0 = pair["token0"]["symbol"] symbol1 = pair["token1"]["symbol"] reserve = float(pair["reserveUSD"]) print(" {}/{}: {:.0f} USD".format(symbol0, symbol1, reserve)) if __name__ == "__main__": main()
SUBGRAPH_URL = "..."子图托管端点,相当于图书馆“服务台地址”。QUERY = """..."""GraphQL 检索单,声明要查的交易对字段与排序方式。json.dumps({"query": graphql_query}).encode("utf-8")把查询包装成 JSON,编码为请求体。headers={"Content-Type": "application/json"}告诉服务端发送的是 JSON 数据。with urllib.request.urlopen(request, timeout=15) as response:发起网络请求并读取响应。if "errors" in result:检查子图是否返回了错误对象,有则中止。pairs = result["data"]["pairs"]从响应中取出交易对数组,开始逐条格式化输出。if __name__ == "__main__":程序入口,保证模块被导入时不会直接执行。
常见误区
误区我查子图接口,返回的数据应该就是区块链当前时刻的状态,可以用来做精确判断。
正解子图是异步索引的,新区块产生后需要时间被索引者抓取、处理、入库。这段延迟通常有几秒到几分钟。对时序敏感的场景,应该查询子图返回中的 _meta 字段里的 block.number,对比链上最新区块高度,判断数据是否已经“追平”。
为何常见:索引层查询太顺畅,容易让人误以为它跟全节点一样实时,忽略了事件处理流水线的存在。
误区子图查询结果既然来自链上事件,那它就可以作为合约之间的结算依据。
正解子图是链下派生数据,属于“最终一致”的索引视图,可能出现延迟、遗漏甚至开发者配置错误。任何涉及资金安全的高价值操作,最终都必须回到链上进行验证,子图更适合做展示、聚合与检索。
为何常见:查询结果长得太像“权威数据”,金融场景中容易放松对数据源的警戒。
误区要做子图,就得先搭一台全节点服务器,否则无数据可索引。
正解The Graph 的去中心化网络和托管服务都由专业索引者运行节点,子图开发者只需提供 subgraph.yaml、schema.graphql 和 mappings 三件套,部署后就能对外提供查询。自建节点只是很多索引者的内部选择,不是开发者的门槛。
为何常见:听说了“索引者运行节点”这件事,就以为子图开发也要自己运维基础设施。
误区The Graph 叫什么,GraphQL 就是它出的,离开链上数据就用不了。
正解GraphQL 是 Facebook 开源的一种通用 API 查询语言,广泛用于各类传统后端服务。The Graph 只是借助 GraphQL 来暴露链上索引数据,二者不是绑定关系。
为何常见:两者名字都带“Graph”,初学者很容易把协议和查询语言画上等号。
误区只要想查某个合约的数据,就必须先给这个合约开发一个专属子图。
正解简单的合约状态直接通过 RPC 读取即可;需要跨合约聚合、历史检索、复杂筛选时才适合引入子图。而且一个子图可以在 manifest 中声明多个数据源,同时索引一组相关合约,不必“一合约一子图”。
为何常见:误把子图当成了访问链上数据的唯一入口,忽略了它只是索引层的补充。
面试题
Q1. The Graph 网络的核心功能是什么?
- A.发行去中心化稳定币
- B.为链上数据建立索引← 正确答案
- C.替代智能合约执行逻辑
- D.提供共享矿机算力
答案:B。The Graph 的本质是区块链数据的索引协议,相当于给链上数据建图书馆检索系统。A 是 MakerDAO 类项目的事,C 是链上合约本身的事,D 与 The Graph 无关。
Q2. 子图的 schema.graphql 文件主要用来做什么?
- A.定义实体与字段模型← 正确答案
- B.设置节点的质押金额
- C.存储链上原始日志
- D.分配查询手续费
答案:A。schema.graphql 定义实体类型和字段,相当于专题索引卡片的“版式设计”。质押金额属于协议层,日志存储由索引者数据库负责,手续费分配属于经济层,都与 schema 无关。
Q3. 下列哪个角色在 The Graph 中负责运行节点并提供查询服务?
- A.委托人(Delegator)
- B.策展人(Curator)
- C.索引者(Indexer)← 正确答案
- D.验证者(Validator)
答案:C。索引者就是图书馆里的“整理员”,质押 GRT 运行索引节点并响应查询;策展人负责发信号筛选优质子图,委托人只出借 GRT 分享收益,The Graph 中不存在名为“验证者”的核心角色。
Q4. 一个完整的子图通常由哪三部分核心文件组成?
- A.清单、模式、映射代码← 正确答案
- B.合约、字节码、编译器
- C.接口、事件、交易哈希
- D.区块、交易、共识规则
答案:A。子图三件套是 manifest(数据源清单)、schema(实体模式)和 mappings(事件映射代码)。B 属于合约开发的产物,C 和 D 描述的是链上通用概念,不是子图的组成结构。
Q5. GraphQL 查询中的 orderBy 参数的主要作用是什么?
- A.对结果按指定字段排序← 正确答案
- B.过滤掉空值字段
- C.限制返回的字段集合
- D.合并多个数据源
答案:A。orderBy 指定按哪个字段排序,配合 orderDirection 控制升序或降序,类似“检索单上写按金额从高到低排列”。过滤空值、限制字段、合并数据源是其他参数或操作符的职责。
Q6. 关于 GRT 的质押与委托,下列说法正确的有哪些?
- A.委托人可将 GRT 委托给索引者分享收益← 正确答案
- B.策展人通过质押 GRT 标记优质子图← 正确答案
- C.索引者无需质押即可提供查询服务
- D.查询者必须质押 GRT 才能发起查询
答案:AB。索引者必须质押 GRT 才能参与服务,C 错;查询者只需支付查询费,无需质押,D 错。委托人出借 GRT 分享收益,策展人质押 GRT 发信号,A 和 B 正确。
Q7. 相比直接调用 RPC 读区块链,用子图查询有哪些优势?
- A.支持聚合关联实体数据← 正确答案
- B.免去手工解析原始日志← 正确答案
- C.可以直接修改链上状态
- D.支持复杂的过滤与排序← 正确答案
答案:ABD。子图把散乱的日志解析成实体模型,并支持跨实体聚合、过滤和排序,A、B、D 都对。索引层永远不能修改链上状态,链上状态只能由交易改变,C 错。
Q8. 下列哪些数据查询场景适合使用 The Graph 子图?
- A.查询钱包的历史转账记录← 正确答案
- B.聚合项目的流动性池数据← 正确答案
- C.读取合约部署时的字节码
- D.监听并统计巨鲸大额转账← 正确答案
答案:ABD。历史转账、流动性池聚合、大额转账统计都需要事件解析与聚合检索,正是子图擅长的场景。而合约字节码是部署时就确定的静态数据,用 RPC 直接读取即可,不需要建索引。
Q9. The Graph 去中心化网络与早期托管服务的区别在于?
- A.去中心化网络由多索引者竞争服务← 正确答案
- B.托管服务的查询结果完全不可信
- C.去中心化网络不需要任何质押
- D.托管服务能永久保存全部数据
答案:A。去中心化网络由众多索引者质押并竞争查询订单,而托管服务由官方集中维护。B 过于绝对,C 错误(索引者必须质押),D 与事实不符,托管服务也会随协议迁移淘汰旧子图。
Q10. 关于索引者(Indexer)收益来源,正确的描述是哪个?
- A.查询费分成与网络质押奖励← 正确答案
- B.为子图发信号获取手续费
- C.打包区块所获得的 Gas 收入
- D.出售节点硬件获得的收入
答案:A。索引者通过服务查询获得查询费分成,在部分网络阶段还能获得质押奖励,A 正确。为子图发信号是策展人的行为,打包区块是矿工或验证人的收入,出售硬件与协议激励无关。