Dgraph:AI时代的知识图谱引擎

构建智能系统的核心基础设施

核心定位

Dgraph是一款高性能、分布式图数据库,专为处理复杂关系数据而设计。在AI技术爆发式发展的背景下,它成为构建智能系统的核心基础设施

为什么Dgraph对AI至关重要?

当前AI(尤其是大语言模型LLM)面临的关键挑战:

  • 缺乏对信息深层关系的理解
  • 难以动态更新知识库
  • 无法验证信息的逻辑路径

Dgraph的解决方案

通过知识图谱技术提供:

  1. 结构化关系表示 - 精准建模实体间的复杂关联(如"用户-行为-商品"网络)
  2. 实时动态更新 - 支持增量式知识演进,适应快速变化的AI需求
  3. 可验证推理路径 - 所有结论均可追溯数据源头,满足审计要求
  4. 多模态语义理解 - 结合语义搜索与向量计算,突破关键词匹配局限

Dgraph的AI原生技术优势

能力 说明
多向量嵌入存储 同一节点/关系可存储多个AI模型向量,支持跨模型对比与融合
混合搜索引擎 同时支持:
- HNSW向量相似度搜索
- 关键词搜索
- 地理空间查询
- 图谱关系遍历
命名空间隔离 为多租户AI应用提供逻辑隔离的数据沙盒(如SaaS平台)
分布式架构 线性扩展能力支撑百亿级关联数据

典型应用场景:智能推荐系统、生物医药知识发现、健康知识库构建。

企业级AI支持路线图

Dgraph正持续进化以满足AI工业化需求:

  • 技术强化 - 优化核心引擎性能,开源v25版本
  • LLM深度集成 - 开发自然语言转图谱查询(NL2GraphQL)、语义推理接口
  • 生产就绪能力 - 增强监控、RBAC权限控制、SOC2合规性
  • 云原生部署 - 按用量计费模式,降低启动成本

Dgraph 核心概念

理解Dgraph的基础架构和核心组件

一、系统架构组件

术语 说明
Alpha 数据存储节点,负责:
- 存储关系数据(Predicates)
- 管理索引
- 通过增加Alpha节点实现横向扩展
Zero 集群控制节点,负责:
- 分配Alpha节点组
- 数据均衡调度
- 事务时间戳管理
- UID分配系统
Badger 底层存储引擎(Go语言开发):
- 高性能键值数据库
- 提供持久化存储层
- 支持快速读写操作

二、数据模型

术语 说明
Node 业务实体对象:
- 通过全局唯一标识符(UID)定位
- 可包含属性值(如姓名)
- 与其他节点建立关系
Predicate 数据最小单元,分为两类:
1. 属性类型:存储字面值(如name: "Alice"
2. 关系类型:连接其他节点(如knows: <Bob_UID>
Edge 节点间连接线(关系可视化表达)
Relationship 具名有向关系:
- 可附加属性(Facets)如权重/时间/类型
- 等同于Edge和Predicate的关系类型
Triple RDF标准数据单元:
<Subject> <Predicate> <Object>
(如<Alice> <knows> <Bob>
UID 节点全局唯一标识符:
- 系统自动生成或显式指定
- 通过uid属性访问

三、查询语言

术语 说明
DQL Dgraph原生查询语言:
- 基于GraphQL扩展
- 支持数据增删改查
- 比GraphQL表达能力更强
GraphQL 标准声明式查询语言:
- Dgraph自动暴露GraphQL API端点
- 支持部署GraphQL数据模型
Mutation 数据修改操作:
- 包含插入/更新/删除
- 可与Query组合成Upsert操作
Upsert 查询+修改组合操作:
- 实现节点存在性检查
- 确保谓词唯一性

四、高级功能

术语 说明
Lambda GraphQL解析器:
- 用JavaScript编写自定义逻辑
- 操作GraphQL类型/接口/查询(与AWS Lambda无关)
Sharding 分布式架构核心:
- 按谓词分片(Predicate-based)
- 单个谓词数据存储于同组服务器
gRPC 高性能通信框架:
- 支持Go/C#/Java/JS/Python客户端
- 在事务中执行修改与查询

五、工具与标准

术语 说明
Ratel 官方GUI工具:
- 数据可视化
- 集群管理
- 支持DQL操作
RDF 语义网标准数据格式:
- Dgraph支持RDF/JSON双格式
- 用于数据导入/导出

核心特性总结

  1. 混合数据模型 - 融合属性图(Property Graph)与RDF三元组模型,支持复杂关系建模
  2. 分布式架构 - 通过Predicate分片实现线性扩展,Zero节点智能调度资源
  3. 多语言支持 - 官方gRPC客户端覆盖主流开发语言
  4. 标准化兼容 - 原生支持GraphQL API与RDF数据交换格式
  5. 实时可扩展 - Lambda机制允许注入自定义业务逻辑

澄清

澄清Dgraph的常见误解与核心概念

核心概念对比

理解Dgraph中几个关键概念的区别和联系,避免混淆。

DQL vs GraphQL

特性 DQL GraphQL
语法风格 函数式,基于RDF三元组 声明式,类似JSON结构
查询方式 func: eq(name, "Alice") queryPerson(filter: {name: {eq: "Alice"}})
复杂查询 支持递归、聚合、变量 功能相对有限
适用场景 复杂图分析、数据科学 前端应用、API开发

JSON vs RDF

特性 JSON RDF
结构 嵌套对象和数组 三元组(subject-predicate-object)
可读性 直观易读 需要理解RDF概念
适用场景 API交换、配置管理 知识图谱、语义查询

DQL/GQL vs JSON/RDF

重要区别

DQL/GQL是查询语言,JSON/RDF是数据格式 - 这是两个不同层面的概念:

  • DQL/GQL:用于查询和操作数据的语言/语法
  • JSON/RDF:用于存储和传输数据的格式/结构
层面 DQL/GQL(查询语言) JSON/RDF(数据格式)
性质 操作指令:如何查询数据 数据结构:如何存储数据
作用 告诉数据库"我要什么" 告诉数据库"数据长什么样"
关系 DQL操作RDF格式,GQL操作JSON格式 RDF是DQL的底层,JSON是GQL的接口
示例 func: eq(name, "Alice") {"name": "Alice"}
实际应用关系
# DQL查询RDF格式的数据
{
  alice(func: eq(name, "Alice")) {
    uid
    name
  }
}

# 返回JSON格式的结果
{
  "alice": [
    {
      "uid": "0x1",
      "name": "Alice"
    }
  ]
}

# GraphQL查询(内部转换为DQL)
query {
  queryPerson(filter: { name: { eq: "Alice" } }) {
    id
    name
  }
}

Schema Type vs dgraph.type

特性 Schema Type定义 dgraph.type赋值
性质 蓝图/模板:定义理想结构 实例/实现:标记具体节点
作用 规定:"Person应该有哪些字段" 声明:"这个节点是Person"
用途 数据验证、API生成 数据查询、类型过滤

节点类型:dgraph.type详解

深入理解Dgraph中最重要的概念之一:节点类型系统。

核心理解

类比说明
  • 节点 = 实体(人、公司、产品等)
  • dgraph.type = 标签集合(分类标识)
  • 就像给物品贴标签,一个物品可以有多个标签
  • 回答:"这个节点属于哪些类型?"
实际例子:

Alice可以同时是:Person + Employee + Manager

就像一个人可以同时是:学生 + 员工 + 志愿者

关键价值

价值 说明
高效查询 通过类型索引快速定位,避免全表扫描
数据组织 为大规模图数据提供结构化分类
Schema集成 连接具体数据与抽象模型定义
权限控制 基于类型设置数据访问权限

使用方法

基本用法
# 单类型节点
_:alice <dgraph.type> "Person" .
_:alice <name> "Alice Johnson" .

# 多类型节点
_:bob <dgraph.type> "Person" .
_:bob <dgraph.type> "Employee" .
_:bob <dgraph.type> "Manager" .
_:bob <name> "Bob Smith" .
查询操作
# 按类型查询
{
  persons(func: type(Person)) {
    uid
    name
  }
}

# 多类型查询
{
  employees(func: type(Person, Employee)) {
    uid
    name
    dgraph.type
  }
}

重要澄清

Dgraph不支持类型继承

关键事实:Dgraph的类型系统是扁平化的,不支持真正的继承关系。

  • ❌ 没有父类-子类关系
  • ❌ 没有属性继承
  • ✅ 支持多类型标签
  • ✅ 通过标签组合模拟层次关系

常见误区澄清

澄清关于Dgraph的常见误解,避免踩坑。

误区1:可以创建自定义类型谓语

❌ 错误做法:

_:alice <myType> "Person" .
_:alice <nodeType> "Employee" .

✅ 正确做法:

_:alice <dgraph.type> "Person" .
_:alice <dgraph.type> "Employee" .

事实:自定义谓语无法与Dgraph的类型系统和GraphQL集成协同工作。

误区2:不设置dgraph.type也可以

❌ 没有dgraph.type的节点:

_:alice <name> "Alice" .
_:alice <age> "30" .

查询时无法找到:

{
  persons(func: type(Person)) {
    name  # 结果为空
  }
}

事实:没有dgraph.type的节点无法参与基于类型的查询和操作。

误区3:Schema Type和dgraph.type是同一个东西

事实:Schema中的type是蓝图,dgraph.type是具体实现,两者需要配合但并非同一概念。

  • Schema Type:定义数据结构和API接口
  • dgraph.type:标记具体节点的类型归属
  • 必须一致:Schema中定义的类型名必须与dgraph.type的值匹配

误区4:一个节点只能有一个类型

❌ 错误理解:认为每个节点只能属于一个类型

✅ 正确理解:一个节点可以有多个类型标签

# ✅ 正确:一个节点可以有多个类型
_:alice <dgraph.type> "Person" .
_:alice <dgraph.type> "Employee" .
_:alice <dgraph.type> "Manager" .
_:alice <name> "Alice" .

# 查询时可以看到所有类型
{
  alice(func: eq(name, "Alice")) {
    uid
    name
    dgraph.type  # 返回: ["Person", "Employee", "Manager"]
  }
}

实际价值:多类型标签让节点可以同时扮演多个角色,更灵活地建模现实世界。

误区5:Dgraph支持类型继承

❌ 错误理解:认为Employee可以"继承"Person的所有属性

✅ 正确理解:Dgraph不支持继承,只能通过多类型标签模拟

# ❌ 错误:以为有继承关系
# Employee "继承" 自 Person

# ✅ 正确:通过多类型标签模拟
_:bob <dgraph.type> "Person" .
_:bob <dgraph.type> "Employee" .
_:bob <name> "Bob" .        # Person属性
_:bob <employeeId> "EMP1" . # Employee属性

# 查询所有Person(包括Employee)
{
  allPersons(func: type(Person)) {
    uid
    name
    employeeId  # Employee节点有此字段,纯Person节点为null
  }
}

关键区别:没有自动的属性继承,需要手动为每个节点分配所有相关类型标签。

误区6:图数据库只适合社交网络

❌ 错误理解:认为图数据库只能用于朋友关系、社交网络

✅ 正确理解:适用于任何有复杂关系的场景

应用场景 关系类型 实际价值
电商平台 用户-商品-订单-评价 推荐算法、用户行为分析
金融系统 账户-交易-风险-合规 反欺诈、风险评估
知识图谱 实体-概念-关系-属性 智能问答、知识发现
物联网 设备-传感器-事件-位置 设备管理、异常检测
生物信息 基因-蛋白质-疾病-药物 药物发现、疾病研究

核心优势:图数据库擅长处理多对多关系、复杂查询和关系分析,不仅限于社交网络。

误区7:图数据库性能不如关系数据库

❌ 错误理解:认为图数据库在所有场景下都比关系数据库慢

✅ 正确理解:在关系密集型查询中,图数据库性能更优

# 图数据库:O(1)关系查找
{
  alice(func: eq(name, "Alice")) {
    friend {
      friend {
        name  # 2度朋友,高效查询
      }
    }
  }
}

# 关系数据库:需要多次JOIN
SELECT f2.name 
FROM person p1
JOIN friendship f1 ON p1.id = f1.person1_id
JOIN person p2 ON f1.person2_id = p2.id
JOIN friendship f2 ON p2.id = f2.person1_id
WHERE p1.name = 'Alice'

性能特点:图数据库在关系遍历、多跳查询、图算法方面性能优异,但在简单CRUD操作上可能不如关系数据库。

误区8:Dgraph只能存储图数据

❌ 错误理解:认为Dgraph只能存储节点和边的关系数据

✅ 正确理解:Dgraph可以存储任何类型的数据

# 可以存储复杂嵌套结构
_:document <dgraph.type> "Document" .
_:document <title> "技术文档" .
_:document <content> "这是一份详细的技术文档..." .
_:document <metadata> '{"author": "Alice", "version": "1.0"}' .
_:document <tags> "技术" .
_:document <tags> "文档" .
_:document <tags> "指南" .

# 支持多种数据类型
_:product <dgraph.type> "Product" .
_:product <name> "智能手机" .
_:product <price> "2999.99" .
_:product <inStock> "true" .
_:product <releaseDate> "2024-01-15" .
_:product <specifications> '{"ram": "8GB", "storage": "256GB"}' .

支持的数据类型:字符串、数字、布尔值、日期时间、JSON对象、地理空间数据、全文搜索等。

最佳实践

遵循这些实践,确保正确使用Dgraph。

必须遵循的实践

实践 说明 重要性
始终使用dgraph.type 不要尝试创建自定义谓语来替代 ⚠️ 必须
预先规划类型系统 在设计阶段规划好类型结构 ⚠️ 必须
为dgraph.type建立索引 否则无法高效查询 ⚠️ 必须
保持一致性 Schema定义与实际使用保持一致 ⚠️ 必须
命名规范 类型名使用PascalCase ✅ 推荐

思维和原则

图数据库的哲学思维与设计原则

哲学思维:世界即关系,关系即意义

Dgraph 的哲学并非源于对传统数据库或其它技术的否定,而是源于一种 对世界本质的不同认知

核心思想
  • 世界是由 实体及其间无限的关系 构成的
  • 理解世界的最佳方式,不是先定义范畴再填充数据,而是 先记录一切可观察的事实,让意义和结构从中"涌现"(Emerge)
  • 这是一种 自下而上、基于实践和观察的认识论,与"自上而下"、基于理论和分类的认识论形成互补
  • Dgraph 正是这种哲学在数据领域的实践体现

第一性原理:关系的原生性

The Primacy of Relationships

核心思想

  • 关系不是数据的附属品,而是与数据原子同等重要的基础组成部分
  • 在 Dgraph 中,一条关系(边)和一条属性(谓词)在存储和处理的层面上是 同构的
  • 这意味着,连接两个节点的"关系"本身,就是一个独立、可检索、可计算的"一等公民"

深层解读

  • 打破了"实体为主,关系为辅"的传统数据观
  • 世界不是孤立的点的集合,而是一张交织的网
  • 任何一个点(实体)的意义和价值,完全由它与其它无数点的连接方式(关系)来定义
  • 没有关系,实体就近乎于不存在

方法论:平铺、标记与涌现

Flatten, Label, and Emerge

1. 平铺(Flatten)

  • 放弃预先设计复杂、静态的层级结构(如多表关联、严格分类)
  • 将所有已知的事实以最直接的方式"平铺"为三元组
# 三元组示例
(人物A) - (居住在) - (城市B)  
(人物A) - (喜欢) - (电影C)  
(电影C) - (的类型是) - (科幻)

无需额外设计"关系表",只是陈述事实。

2. 标记(Label)

  • "谓词"(Predicate)即是标签
  • 可以是属性(姓名、年龄)、关系(朋友、创作)、甚至类别(科幻、爵士乐)
  • 谓词本身也是数据,可以随时新增,不破坏原有结构
  • Schema 会随着事实积累而自然生长

3. 涌现(Emerge)

  • 不必预先知道所有问题的答案
  • 只需持续记录事实和标签
  • 当数据累积到一定程度,使用 DQL/GraphQL 查询时,隐藏的模式、关联与洞察会自然"浮现"
  • 例如:你可能会发现"喜欢某类音乐的人,常住在某类城市"
  • 这不是事先假设的,而是从数据中读出来的

Dgraph 的实现:为涌现而生的引擎

1. 分布式图灵机

  • 所有数据视为三元组,分布式存储
  • 查询时,像一台并行图灵机在巨图上遍历,让复杂的深度关联查询成为可能

2. 灵活的模式(Schema)

  • 支持 Schema-less 写入,先自由贴标签,再引入模式确认规律
  • 模式不是限制,而是对"已涌现规律"的总结与固化

3. GraphQL/DQL 查询语言

  • 查询即探索路径:从一个点出发,沿关系逐步扩展、过滤、聚合
  • 查询过程本身就是数据探索的模拟

设计原则

原则 说明
三元组原则 一切都是 (subject → predicate → object)
全局命名原则 UID、谓语全局唯一
灵活建模原则 Schema 可选,允许演化
关系优先原则 价值来自多跳关系查询
类型即接口 Type 用于对外暴露 API,而非约束本体
演化原则 数据模式随着认知成长,不必一次到位
统一接口原则 DQL(底层灵活) + GraphQL(接口友好)

总结:数据的有机体

Dgraph 的哲学鼓励我们把数据库视为 一个生长的有机体,而不是一个静态的建筑:

对比 传统数据库(建筑) Dgraph(有机体)
设计理念 依赖蓝图(ER 图),结构一旦确定,修改代价极高 从简单三元组开始,随着环境输入(新数据)不断演化
发展方式 静态结构,需要重新设计才能扩展 动态生长,最终形成复杂、智慧、充满内在联系的整体
使用 Dgraph 的最佳方式
  • 立即开始,不必等完美 schema
  • 记录一切事实,拥抱不确定性
  • 让模式和意义自然"涌现"
  • 把它当作 思想的放大镜,帮助你发现超越逻辑推演的复杂真理

一句话总结

Dgraph 的哲学是 关系原生、事实平铺、意义涌现;它既是数据库,也是一个不断成长的知识有机体。

部署方式选择指南

根据数据规模、技术能力、预算和控制需求选择最适合的部署方式

部署决策关键因素

当迁移到自托管Dgraph时,您的部署选择取决于几个关键因素:数据规模、团队技术能力、预算限制和控制需求。以下是这些因素如何影响部署决策的详细分析:

1. 数据规模考量

数据规模是选择部署方式的首要因素:

数据规模 推荐部署方式 说明
< 100GB Docker Compose 或 Linux 小规模数据,单机部署即可满足需求
100GB – 1TB Kubernetes 或 Linux 中等规模,需要考虑扩展性和高可用性
> 1TB Kubernetes(必须) 大规模数据,必须使用分布式架构

2. 团队技术能力因素

团队的技术经验和专业知识直接影响部署方式的选择:

团队经验水平 推荐部署方式 优势
Kubernetes 经验丰富 Kubernetes(推荐) 充分利用K8s的自动化能力
Kubernetes 经验有限 Docker Compose 或 Linux 更易上手,降低学习成本

3. 预算限制

预算策略决定了您能承受的基础设施和管理成本:

预算策略 推荐部署方式 特点
成本优化型 Linux(最经济) 直接部署在裸金属服务器,无额外管理开销
平衡型 Docker Compose(折中选择) 容器化部署,便于管理但成本可控
企业级 Kubernetes(企业级功能) 支持自动扩缩容、高可用性,但成本较高

4. 控制需求

对基础设施的控制程度影响部署方式的选择:

控制级别 推荐部署方式 特点
最大控制权 Linux(完全掌控环境) 适合需要深度定制和优化的团队
托管基础设施 Kubernetes(自动化管理能力) 适合希望减少运维负担的企业

5. 可用部署方法对比

不同部署方式的特点和适用场景:

部署方式 适用场景 优势 注意事项
Kubernetes 大规模部署、企业环境、具备K8s专业知识的团队 自动扩缩容、高可用性、服务发现 学习曲线陡峭、运维复杂度高
Docker Compose 开发、测试环境,或小型生产负载 快速部署、易于管理、成本可控 扩展性有限、单点故障风险
Linux 预算有限、需要完全控制基础设施的团队 成本最低、完全控制、性能最优 手动配置、运维复杂度高

6. 部署决策流程图

使用以下决策树来帮助选择最适合的部署方式:

决策流程

  1. 数据规模评估
    • 如果 < 100GB → 考虑 Docker Compose 或 Linux
    • 如果 100GB - 1TB → 考虑 Kubernetes 或 Linux
    • 如果 > 1TB → 必须使用 Kubernetes
  2. 技术能力评估
    • 如果 K8s 经验丰富 → 优先选择 Kubernetes
    • 如果 K8s 经验有限 → 选择 Docker Compose 或 Linux
  3. 预算控制评估
    • 如果成本敏感 → 选择 Linux
    • 如果平衡型 → 选择 Docker Compose
    • 如果企业级 → 选择 Kubernetes

7. 渐进式迁移策略

如果团队缺乏Kubernetes经验但需要扩展性,建议采用渐进式迁移策略:

第一阶段:原型验证

使用 Docker Compose 快速搭建环境,验证业务逻辑和性能需求。

第二阶段:学习提升

团队学习 Kubernetes 基础知识,在测试环境中进行小规模部署。

第三阶段:生产迁移

逐步将生产环境迁移到 Kubernetes,确保平滑过渡。

总结建议

开发/测试环境

推荐Docker Compose

原因:快速搭建,便于迭代

中小规模生产(<1TB)

推荐Linux(低成本)或 Kubernetes(如需扩展性)

原因:平衡成本和功能需求

大规模企业级(>1TB)

推荐必须使用 Kubernetes

原因:确保高可用和自动化管理

重要提醒

:如果团队缺乏Kubernetes经验但需要扩展性,建议先采用Docker Compose进行原型验证,再逐步迁移到Kubernetes。

Docker部署

快速搭建Dgraph开发和生产环境

环境准备

确保您的系统已安装Docker和Docker Compose:

# 检查Docker版本
docker --version
docker-compose --version

# 确保Docker服务正在运行
docker info

版本选择

Dgraph提供多个版本,根据您的需求选择合适的版本:

  • V25版本:最新预览版,支持MCP功能
  • V24版本:稳定版本,生产环境推荐
  • Latest版本:最新稳定版本

V25版本配置(推荐开发环境)

创建docker-compose-v25.yml文件:

version: "3.8"

services:
  zero:
    container_name: zero
    image: Dgraph/Dgraph:v25.0.0-preview6
    volumes:
      - /opt/Dgraph:/Dgraph
    ports:
      - 5080:5080
      - 6080:6080
    restart: on-failure
    command: Dgraph zero --my=zero:5080
    networks:
      - Dgraph-network

  alpha:
    container_name: alpha
    image: Dgraph/Dgraph:v25.0.0-preview6
    volumes:
      - /opt/Dgraph:/Dgraph
    ports:
      - 8080:8080
      - 9080:9080
    restart: on-failure
    command: Dgraph alpha --my=alpha:7080 --zero=zero:5080 --mcp --security whitelist=0.0.0.0/0
    networks:
      - Dgraph-network

  ratel:
    container_name: ratel
    image: Dgraph/ratel:latest
    ports:
      - 8000:8000
    networks:
      - Dgraph-network

networks:
  Dgraph-network:
    driver: bridge

V25版本特性

  • 支持MCP(Model Context Protocol)功能
  • 增强的安全性和性能
  • 改进的GraphQL支持
  • 注意:这是预览版本,不建议在生产环境使用

V24版本配置(生产环境推荐)

创建docker-compose-v24.yml文件:

version: "3.2"

services:
  zero:
    image: Dgraph/Dgraph:latest
    volumes:
      - /opt/Dgraph:/Dgraph
    ports:
      - 5080:5080
      - 6080:6080
    restart: on-failure
    command: Dgraph zero --my=zero:5080

  alpha:
    image: Dgraph/Dgraph:latest
    volumes:
      - /opt/Dgraph:/Dgraph
    ports:
      - 8080:8080
      - 9080:9080
    restart: on-failure
    command: Dgraph alpha --my=alpha:7080 --zero=zero:5080 --security whitelist=0.0.0.0/0

  ratel:
    image: Dgraph/ratel:latest
    ports:
      - 8000:8000
    restart: on-failure

V24版本优势

  • 稳定可靠,经过充分测试
  • 生产环境验证
  • 完整的文档和社区支持
  • 企业级功能支持

启动服务

在包含配置文件的目录中运行:

# 启动V25版本服务
docker-compose -f docker-compose-v25.yml up -d

# 启动V24版本服务
docker-compose -f docker-compose-v24.yml up -d

# 查看服务状态
docker-compose ps

# 查看日志
docker-compose logs -f

# 停止服务
docker-compose down

验证部署

服务启动后,可以通过以下方式验证:

服务 端点 说明
GraphQL API http://localhost:8080/graphql GraphQL查询和变更接口
DQL端点 http://localhost:8080/query Dgraph查询语言接口
Ratel工具 http://localhost:8000 图形化管理界面
HTTP API http://localhost:9080 HTTP JSON格式接口
MCP端点(V25) http://localhost:8080/mcp/sse AI助手集成接口

组件说明

Dgraph集群由三个核心组件组成:

组件 功能说明 端口
Zero 集群管理节点,负责元数据管理、节点协调、分片分配 5080(RPC), 6080(HTTP)
Alpha 数据存储节点,执行查询、更新数据、管理存储 7080(Live Query), 8080(GraphQL), 9080(HTTP), 9180(gRPC)
Ratel 图形用户界面,提供友好的数据管理和查询界面 8000(Web UI)

MCP功能配置(V25版本)

V25版本支持MCP(Model Context Protocol),可以集成AI助手:

# 使用 --mcp 启动 Dgraph Alpha
Dgraph alpha --my=localhost:7080 --zero=localhost:5080 --mcp

# 启用两个MCP端点:
# 完全访问:http://localhost:8080/mcp/sse
# 只读访问:http://localhost:8080/mcp-ro/sse

AI助手配置示例

为本地Dgraph配置AI助手(如Claude Desktop):

{
  "mcpServers": {
    "Dgraph-local": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:8080/mcp/sse"]
    },
    "Dgraph-local-readonly": {
      "command": "npx",
      "args": ["mcp-remote", "http://localhost:8080/mcp-ro/sse"]
    }
  }
}

常用管理命令

日常运维和管理命令:

# 查看容器状态
docker ps -a

# 查看容器日志
docker logs -f alpha
docker logs -f zero
docker logs -f ratel

# 进入容器
docker exec -it alpha bash
docker exec -it zero bash

# 备份数据
docker exec alpha Dgraph backup --alpha=localhost:9080 --destination=/Dgraph/backup

# 恢复数据
docker exec alpha Dgraph restore --alpha=localhost:9080 --backup=/Dgraph/backup

# 查看集群状态
curl http://localhost:8080/state

注意事项

  • 数据持久化:确保挂载的目录有适当的权限
  • 网络安全:生产环境建议配置防火墙和访问控制
  • 资源限制:根据数据量调整内存和CPU限制
  • 备份策略:定期备份数据,测试恢复流程
  • 监控告警:配置监控系统,及时发现异常

部署总结

  1. 版本选择 - V25用于开发测试,V24用于生产环境
  2. 组件配置 - Zero、Alpha、Ratel三个核心组件
  3. 端口管理 - 不同服务使用不同端口,避免冲突
  4. MCP支持 - V25版本支持AI助手集成
  5. 运维管理 - 完善的监控、备份、恢复策略

Go客户端

使用Go语言连接和操作Dgraph - 支持v2 API

安装依赖

在Go项目中添加Dgraph客户端依赖:

// 传统v1 API(兼容性)
go get github.com/Dgraph-io/dgo/v210
go get github.com/Dgraph-io/dgo/v210/protos/api

// 新版v2 API(推荐,版本25+)
go get github.com/Dgraph-io/dgo/v250

版本说明

v2 API特性:版本25引入v2 API,提供更简化的客户端创建和DQL执行功能,当前支持dgo/v250包。

建立连接

Dgraph v2 API支持多种连接方式:

基础连接方式

dgo包支持通过连接字符串连接Dgraph集群,格式为:Dgraph://host:port?arguments

参数 可选值 说明
bearertoken <token> 访问令牌
sslmode disable/require/verify-ca TLS模式(默认disable),verify-ca需配置有效CA证书
package main

import (
    "context"
    "log"
    
    "github.com/Dgraph-io/dgo/v250"
)

func main() {
    // 连接非TLS集群
    client, err := dgo.Open("Dgraph://localhost:9080")
    if err != nil {
        panic(err)
    }
    defer client.Close()
    
    log.Println("成功连接到Dgraph!")
}

高级客户端配置

根据需求选择不同的客户端配置:

单节点客户端

import (
    "github.com/Dgraph-io/dgo/v250"
    "google.golang.org/grpc/credentials/insecure"
)

client, err := dgo.NewClient("localhost:9080",
    dgo.WithGrpcOption(grpc.WithTransportCredentials(insecure.NewCredentials())),
)
if err != nil {
    panic(err)
}
defer client.Close()

多节点负载均衡客户端

client, err := dgo.NewRoundRobinClient([]string{
    "localhost:9181", 
    "localhost:9182", 
    "localhost:9183",
}, dgo.WithGrpcOption(grpc.WithTransportCredentials(insecure.NewCredentials())))
if err != nil {
    panic(err)
}
defer client.Close()

连接Hypermode Graph

Hypermode集群自动处理负载均衡,支持两种连接方式:

通过连接字符串

client, err := dgo.Open("Dgraph://.hypermode.host?sslmode=verify-ca&bearertoken=")
if err != nil {
    panic(err)
}
defer client.Close()

通过NewClient

client, err := dgo.NewClient(".hypermode.host:443",
    dgo.WithBearerToken(""),
    dgo.WithSystemCertPool(), // 使用系统证书池
)
if err != nil {
    panic(err)
}
defer client.Close()

数据操作

v2 API简化了DQL执行流程,统一使用RunDQL方法:

设置Schema

sch := `
    name: string @index(exact) .
    email: string @index(exact) @unique .
    age: int .
`
err := client.SetSchema(context.TODO(), dgo.RootNamespace, sch)
if err != nil {
    panic(err)
}

插入数据(Mutation)

mutationDQL := `{
    set {
        _:alice  "Alice" .
        _:alice  "alice@example.com" .
        _:alice  "29" .
    }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, mutationDQL)
if err != nil {
    panic(err)
}
fmt.Printf("生成UID映射: %+v\n", resp.BlankUids)

查询数据(Query)

支持多种查询方式和选项:

基础查询

queryDQL := `{
    alice(func: eq(name, "Alice")) {
        name
        email
        age
    }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL)
if err != nil {
    panic(err)
}
fmt.Printf("查询结果: %s\n", resp.QueryResult)

带变量的查询

queryDQL := `query Alice($name: string) {
    alice(func: eq(name, $name)) {
        name
        email
        age
    }
}`
vars := map[string]string{"$name": "Alice"}
resp, err := client.RunDQLWithVars(context.TODO(), dgo.RootNamespace, queryDQL, vars)
if err != nil {
    panic(err)
}

只读查询(ReadOnly)

resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL, dgo.WithReadOnly())
if err != nil {
    panic(err)
}

RDF格式返回

import "github.com/Dgraph-io/dgo/v250/protos/api_v2"

resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, queryDQL, 
    dgo.WithResponseFormat(api_v2.RespFormat_RDF))
if err != nil {
    panic(err)
}

更新或插入(Upsert)

支持基础Upsert和条件Upsert操作:

基础Upsert

upsertQuery := `upsert {
    query { user as var(func: eq(email, "alice@example.com")) }
    mutation { 
        set { 
            uid(user)  "30" . 
            uid(user)  "Alice Sayum" . 
        } 
    }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, upsertQuery)
if err != nil {
    panic(err)
}

条件Upsert(@if指令)

upsertQuery := `upsert {
    query { user as var(func: eq(email, "alice@example.com")) }
    mutation @if(eq(len(user), 1)) {
        set { 
            uid(user)  "30" . 
            uid(user)  "Alice Sayum" . 
        }
    }
}`
resp, err := client.RunDQL(context.TODO(), dgo.RootNamespace, upsertQuery)
if err != nil {
    panic(err)
}

数据清理

清理和重置数据:

清空所有数据

err := client.DropAllNamespaces(context.TODO())
if err != nil {
    panic(err)
}

安全配置

生产环境的安全建议:

安全配置要点

  • 启用TLS:生产环境务必启用sslmode=verify-ca
  • 访问令牌:配置bearertoken进行身份验证
  • CA证书:确保集群配置有效的CA证书
  • 网络隔离:限制客户端访问的网络范围

完整示例

一个完整的Go客户端使用示例:

package main

import (
    "context"
    "fmt"
    "log"
    
    "github.com/Dgraph-io/dgo/v250"
)

func main() {
    // 1. 建立连接
    client, err := dgo.Open("Dgraph://localhost:9080")
    if err != nil {
        log.Fatal("连接失败:", err)
    }
    defer client.Close()
    
    ctx := context.Background()
    
    // 2. 设置Schema
    schema := `
        name: string @index(exact) .
        email: string @index(exact) @unique .
        age: int .
    `
    if err := client.SetSchema(ctx, dgo.RootNamespace, schema); err != nil {
        log.Fatal("设置Schema失败:", err)
    }
    
    // 3. 插入数据
    mutation := `{
        set {
            _:alice  "Alice" .
            _:alice  "alice@example.com" .
            _:alice  "29" .
        }
    }`
    
    resp, err := client.RunDQL(ctx, dgo.RootNamespace, mutation)
    if err != nil {
        log.Fatal("插入数据失败:", err)
    }
    
    fmt.Printf("插入成功,UID映射: %+v\n", resp.BlankUids)
    
    // 4. 查询数据
    query := `{
        alice(func: eq(name, "Alice")) {
            name
            email
            age
        }
    }`
    
    queryResp, err := client.RunDQL(ctx, dgo.RootNamespace, query)
    if err != nil {
        log.Fatal("查询失败:", err)
    }
    
    fmt.Printf("查询结果: %s\n", queryResp.QueryResult)
}

关键特性总结

  1. v2 API特性 - 简化了DQL执行流程,统一使用RunDQL方法处理查询和变更
  2. 多种连接方式 - 支持连接字符串、单节点、多节点负载均衡
  3. Hypermode集成 - 自动负载均衡,适合多节点生产环境
  4. 完整数据操作 - 支持Schema设置、增删改查、Upsert等操作
  5. 安全配置 - 支持TLS、访问令牌、CA证书等安全特性

重要提醒

:所有代码示例需处理错误(if err != nil),此处为简洁省略。生产环境务必启用sslmode=verify-cabearertoken

GraphiQL

使用GraphiQL进行GraphQL查询和开发

什么是GraphiQL

GraphiQL是一个用于测试GraphQL查询的交互式开发环境,提供语法高亮、自动补全、实时错误提示和查询历史记录。它是GraphQL开发者的必备工具。

获取GraphiQL

下载独立的GraphiQL文件,可以离线使用,更灵活:

下载GraphiQL

点击下方按钮下载 view.html 文件

使用步骤
  1. 下载 view.zip 文件到本地
  2. 解压zip文件,获得 view.html
  3. 修改 view.html 中的 url 配置
  4. 用浏览器直接打开即可使用
优势特点
  • 非常简单:只需修改URL部分,就可以使用浏览器直接打开使用了!
  • 离线可用:本地文件,不依赖网络连接
  • 完全控制:可以自定义配置和修改
  • 便携性强:文件可以复制到任何地方使用

配置GraphiQL

修改 view.html 文件中的配置:

修改GraphQL端点

// 找到这一行并修改URL
const fetcher = createGraphiQLFetcher({
  url: 'http://localhost:8080/graphql',  // 修改为您的Dgraph GraphQL端点
});

常见配置示例

部署类型 URL配置 说明
本地Docker http://localhost:8080/graphql 标准Docker部署端口
本地独立部署 http://localhost:9080/graphql 独立部署的HTTP端口
远程服务器 http://your-server:8080/graphql 替换为实际服务器地址
HTTPS服务 https://your-domain.com/graphql 生产环境HTTPS配置

使用GraphiQL

配置完成后,用浏览器打开 view.html 文件即可开始使用:

基本操作步骤

  1. 打开文件:用浏览器打开下载的 view.html 文件
  2. 验证连接:确认右上角显示连接状态
  3. 开始查询:在左侧编辑器中编写GraphQL查询
  4. 执行查询:点击播放按钮或按 Ctrl+Enter 执行
  5. 查看结果:右侧面板显示查询结果

基本查询示例

在GraphiQL中尝试以下查询:

查询所有人员

query {
  queryPerson {
    id
    name
    age
    friend {
      name
      age
    }
  }
}

条件查询

query {
  queryPerson(filter: { age: { ge: 25 } }) {
    id
    name
    age
    email
  }
}

插入数据

mutation {
  addPerson(input: {
    name: "张三"
    age: 30
    email: "zhangsan@example.com"
  }) {
    person {
      id
      name
      age
      email
    }
  }
}

GraphiQL功能特性

GraphiQL提供丰富的开发功能:

语法高亮

GraphQL查询语法彩色显示,提高代码可读性

自动补全

智能提示字段名、类型和参数,减少输入错误

实时验证

即时检查语法错误和类型不匹配问题

查询历史

保存和重用之前的查询语句

文档浏览器

右侧面板显示Schema文档,便于了解可用字段

变量支持

支持查询变量,便于参数化查询

常见问题解决

使用过程中可能遇到的问题和解决方案:

问题 解决方案
无法连接到Dgraph 检查URL配置、网络连接、Dgraph服务状态
查询返回错误 检查查询语法、字段名是否正确、Schema是否已设置
浏览器显示空白 检查JavaScript控制台错误、网络请求是否成功
字段不显示 确认Schema中已定义该字段、检查字段权限

使用总结

  1. 下载配置 - 下载view.html文件,修改URL配置
  2. 简单使用 - 用浏览器直接打开即可使用
  3. 功能丰富 - 语法高亮、自动补全、实时验证
  4. 开发友好 - 查询历史、文档浏览、变量支持
  5. 离线可用 - 本地文件,不依赖网络连接

快速开始

三步搞定:下载文件 → 修改URL → 浏览器打开,就是这么简单!

Postman

使用Postman测试Dgraph API

配置请求

在Postman中配置Dgraph请求:

  • URL:http://localhost:8080/graphql
  • Method:POST
  • Headers:Content-Type: application/json

管理接口

Dgraph还提供了管理接口用于系统监控和配置:

  • 管理界面http://localhost:8080/admin
  • 功能:集群状态监控、性能指标、健康检查
  • 用途:系统管理、故障排查、性能调优

说明:管理接口提供了Dgraph集群的实时监控信息,包括节点状态、内存使用、查询性能等关键指标,是运维人员的重要工具。

请求体示例

GraphQL查询请求体:

{
  "query": "query { queryPerson { id name age } }",
  "variables": {}
}

DQL语法

Dgraph原生查询语言完整指南

关键词

DQL的核心关键词定义了查询和操作的基本结构:

核心关键词

关键词 用途 示例
query 查询数据 query { user(func: has(name)) {...} }
mutation 修改数据 mutation { set { _:a <name> "Alice" . } }
schema 定义结构 schema { name: string @index(term) . }
type 定义节点类型 type User { name, age, friend }
func 定义查询函数 user(func: eq(name, "Alice")) {...}
var 变量块 var(func: has(name)) { friends as friend }

辅助关键词

关键词 用途 示例
expand 展开所有字段 expand(_all_)
has 判断属性存在 func: has(email)
uid 指定 UID func: uid(0x1, 0x2)
val 取变量值 val(friends)
math 数学计算 math(age + 1)

名称规则

Dgraph 对谓词类型名称(谓词标识符)、节点类型名称(节点标识符)和变量名称有特定的命名规范:

基本规则

核心要点
  • 字母数字组合:任何字母数字组合的谓词名称都是允许的
  • 国际化支持:支持国际化资源标识符(IRI)
  • 保留命名空间:不能定义以 dgraph. 开头的类型或谓词
# ✅ 有效的谓词名称
name: string .
age: int .
user_name: string .
user123: string .
<姓名>: string .  # 中文谓词
<user-name>: string .  # 带连字符

# ❌ 无效的类型定义
dgraph.Student: string .  # 错误:不能以 dgraph. 开头

特殊字符规则

字符类型 字符列表 使用规则 示例
支持的特殊字符 ][&*()_-+=!#$% 允许作为前缀或后缀 user_name, test-123
不支持的特殊字符 ^}|{`\~ 完全不允许使用 user^name
@ 后缀 @ 不限制使用,但会被忽略 name@enname

实际示例

# ✅ 有效的命名示例
user_name: string @index(term) .
user-age: int @index(int) .
user_email: string @index(exact) .
user_123: string .
user.name: string .  # 点号是允许的
user@domain: string .  # @ 会被忽略,实际是 userdomain
<用户姓名>: string .  # 中文名称
<user-name>: string .  # 带连字符

# ❌ 无效的命名示例
^username: string .  # 错误:^ 不被支持
user}name: string .  # 错误:} 不被支持
{username: string .  # 错误:{ 不被支持
`username: string .  # 错误:` 不被支持
\username: string .  # 错误:\ 不被支持
~username: string .  # 错误:~ 不被支持
dgraph.user: string .  # 错误:dgraph. 是保留命名空间

国际化资源标识符(IRI)

# IRI 格式的谓词名称
<http://example.org/name>: string .
<https://schema.org/name>: string .
<urn:uuid:123e4567-e89b-12d3-a456-426614174000>: string .

# 使用 IRI 谓词
{
  set {
    _:user <http://example.org/name> "Alice" .
    _:user <https://schema.org/name> "Alice Smith" .
  }
}

变量

DQL中的变量用于标识节点、边和存储查询结果:

UID类型

类型 格式 说明 示例
永久 UID <0x123> 系统分配的永久标识符 <0x1>
临时 Blank Node _:a 临时标识符,用于创建新节点 _:alice

别名和变量

{
  # 给返回结果字段命名
  user(func: eq(name, "Alice")) {
    uid
    name
    age
    friends: friend {  # 别名
      name
    }
  }
  
  # var 变量保存查询结果
  var(func: has(name)) {
    friends as friend  # 保存朋友关系
  }
  
  # 使用变量
  aliceFriends(func: uid(friends)) {
    name
    age
  }
}

类型系统

Dgraph支持多种数据类型和关系类型:

标量类型

类型 说明 示例
string 字符串 "Alice"
int 整数 25
float 浮点数 3.14
bool 布尔值 true
dateTime 日期时间 "2024-01-15T10:30:00Z"
geo 地理位置 {"type":"Point","coordinates":[116.4,39.9]}
password 密码(加密存储) "secret123"

关系类型

# Schema 声明
name: string @index(term) .           # 属性
friend: [uid] @reverse .              # 多关系
worksFor: uid @reverse .              # 单关系
location: geo @index(geo) .           # 地理位置

# 节点类型定义
type User {
  name
  age
  friend
  worksFor
}

系统保留类型

dgraph.type

dgraph.type 是系统保留的谓词,用于给节点打类型标签:

mutation {
  set {
    _:alice <name> "Alice" .
    _:alice <dgraph.type> "User" .
  }
}

函数库

DQL提供丰富的内置函数用于查询和计算:

比较函数

函数 说明 示例
eq() 等于 eq(name, "Alice")
lt() 小于 lt(age, 18)
gt() 大于 gt(age, 65)
le() 小于等于 le(age, 18)
ge() 大于等于 ge(age, 18)

集合函数

函数 说明 示例
uid() 按UID查询 uid(0x1, 0x2)
uid_in() UID在集合中 uid_in(friend, 0x1, 0x2)
between() 区间查询 between(age, 18, 65)

全文搜索函数

函数 说明 示例
allofterms() 包含所有关键词 allofterms(name, "Alice Bob")
anyofterms() 包含任一关键词 anyofterms(name, "Alice Bob")
anyoftext() 全文搜索 anyoftext(description, "machine learning")
regexp() 正则匹配 regexp(name, /^A.*/)

聚合函数

{
  stats(func: has(age)) {
    count(uid)        # 计数
    sum(age)          # 求和
    avg(age)          # 平均值
    min(age)          # 最小值
    max(age)          # 最大值
  }
}

数学/值函数

{
  users(func: has(age)) {
    name
    age
    nextYear: math(age + 1)        # 数学计算
    friendsCount: count(friend)    # 朋友数量
  }
}

运算符

DQL支持多种运算符进行逻辑和比较操作:

逻辑运算符

{
  # AND 逻辑
  adults(func: has(age)) @filter(ge(age, 18) AND le(age, 65)) {
    name
    age
  }
  
  # OR 逻辑
  youngOrOld(func: has(age)) @filter(lt(age, 18) OR gt(age, 65)) {
    name
    age
  }
  
  # NOT 逻辑
  noEmail(func: has(name)) @filter(NOT has(email)) {
    name
  }
}

比较运算符

{
  # 数值比较
  users(func: has(age)) @filter(age = 25) {
    name
    age
  }
  
  # 范围查询
  adults(func: has(age)) @filter(age > 18 AND age < 65) {
    name
    age
  }
}

控制逻辑

DQL提供多种控制逻辑来精确控制查询行为:

条件过滤

{
  # 基本过滤
  users(func: has(name)) @filter(eq(name, "Alice")) {
    name
    age
  }
  
  # 复杂过滤
  adults(func: has(age)) @filter(ge(age, 18) AND has(email)) {
    name
    age
    email
  }
}

结果控制

{
  # 结果裁剪 - 只返回有完整数据的节点
  users(func: has(name)) @cascade {
    name
    age
    friend {
      name
    }
  }
  
  # 结果扁平化 - 将嵌套结构扁平化
  users(func: has(name)) @normalize {
    name
    friend {
      name
    }
  }
  
  # 分页控制
  users(func: has(name), first: 10, offset: 20) {
    name
    age
  }
  
  # 排序
  users(func: has(age), orderasc: age) {
    name
    age
  }
}

语法拆解

通过具体示例深入理解DQL查询的语法结构:

示例查询

network(func: eq(name, "Alice")) @recurse(depth: 3) {
  name
  friend {
    name
  }
}

语法拆解

组成部分 说明 示例
1. network 查询块别名 (alias) 给查询结果起名字,返回JSON时包在 "network": [...]
2. func: 关键字 (keyword) 表示「入口函数」,只能写 func:,不能换成别的
3. eq(name, "Alice") 入口函数 (function) 选出所有 name 等于 "Alice" 的节点作为查询起点
4. @recurse(depth: 3) 查询修饰符 (directive) 递归查询,自动沿着边展开,depth: 3 限制最多走3步关系
5. { ... } 结果字段选择 (projection) 定义要返回哪些属性/关系
6. name 属性字段 返回每个节点的 name 属性,
这里的 name 是标识符,完整的写法是<name>
使用中文时,< >不能省略!!!
7. friend { name } 关系字段 (edge) 从当前节点沿着 friend 边走到相关节点,返回它们的 name

执行逻辑总结

执行步骤
  1. 起点:找到所有 name = "Alice" 的节点
  2. 递归:从这些节点出发,顺着 friend 关系往外扩展,最多3层
  3. 返回:每一层节点的 name 和它的 friend.name
  4. 输出格式:包在JSON里的 "network": [...]
结果说明

network 查询得到的就是「Alice 的社交网络」,递归展开到3层朋友。

谓语类型

理解 Dgraph 中的谓词系统、类型定义和约束

什么是谓词?

谓词是描述对象信息的最小单元,可以是文字值,也可以是与其他实体的关系。

核心理解
  • 谓词是三元组中的"谓词"部分:<主语> <谓词> <宾语>
  • 每个谓词都有特定的数据类型和约束
  • 谓词可以是标量值(字符串、数字等)或关系(指向其他节点)

谓词声明模式

Dgraph 集群的模式决定是否必须先定义谓词才能执行数据变更:

Strict 模式

您必须在模式中声明谓词后,才可以通过 mutation 插入数据。

# 启动 Alpha 节点时设置 --limit 参数
dgraph alpha --limit "mutations=strict; mutations-nquad=1000000" --my=<alpha-node-ip>:7080 --zero=<zero-node-ip>:5080

这会启用严格模式,只允许对已在 schema 中的谓词进行突变操作。在执行突变之前,需要先通过 alter 操作声明谓词及其 schema 类型。

Flexible 模式(默认)

可以在 mutation 中使用未声明的谓词,Dgraph 会自动推断并添加这些谓词到模式里。

📌 注意:当通过 GraphQL API 部署模式时,Dgraph 会自动生成底层的 Dgraph 类型。

谓词类型分类

谓词类型用于指示谓词所能存储的数据类型、是否为列表、是否需要索引以及是否支持多语言等:

1. 标量类型(Scalar types)

类型名称 对应 Go 类型 说明
string / default string 默认字符串类型
int int64 整数类型
float float 浮点类型
bool bool 布尔型
dateTime time.Time 日期时间,要符合 RFC 3339 格式
geo geo 类型 地理位置类型(支持 go-geom)
password string(加密存储) 加密后的密码,用于安全验证
float32vector []float32 浮点数数组,常用于存储 embeddings

2. UID 类型

用于表示关系,在内部每个节点通过 uint64 类型的 UID 唯一标识。

# 关系谓词示例
friends: [uid] .
parent: uid .
children: [uid] @reverse .

多语言支持(Predicates i18n)

支持通过 IRI 格式的谓词名称(使用 <> 符号括起)和语言标签:

# Schema 定义
<公司>: string @index(fulltext) @lang .

# Mutation 示例
{
  set {
    _:a <公司> "Dgraph Labs Inc"@en .
    _:b <公司> "夏新科技有限责任公司"@zh .
    _:a <dgraph.type> "Company" .
  }
}

📌 关键点:若需针对不同语言进行全文索引,应使用 @lang 指令,并在 mutation 时使用语言标签。

唯一性约束(@unique)

通过 @unique 指令可以确保该谓词的值在所有节点中唯一:

# 字符串类型需要 hash 或 exact 索引
email: string @unique @index(exact) .

# 整数类型需要 int 索引
user_id: int @unique @index(int) .
重要规则
  • 字符串类型:需要 hashexact 索引
  • 整数类型:需要 int 索引
  • 必须同时定义索引才能使用 @unique

Upsert 指令(@upsert)

用于执行"先查再插"操作,当两个事务尝试创建同一数据时,可确保不会冲突:

email: string @index(exact) @upsert .

该做法会检查索引键,并防止写入冲突。

防冲突指令(@noconflict)

这是一个试验性指令,可用于避免在某些情况下检测冲突:

email: string @index(exact) @noconflict .

⚠️ 警告:但有可能导致数据丢失,不推荐在高正确性场景使用。

密码类型(password)

密码属性使用 password 类型定义,密码被加密保存(bcrypt),不可直接查询:

Schema 定义

pass: password .

Mutation 设置密码

{
  set {
    <0x123> <name> "Password Example" .
    <0x123> <pass> "ThePassword" .
  }
}

验证密码

{
  check(func: uid(0x123)) {
    name
    checkpwd(pass, "ThePassword")
  }
}

返回格式示例:

{
  "data": {
    "check": [
      {
        "name": "Password Example",
        "checkpwd(pass)": true
      }
    ]
  }
}

使用别名形式

{
  check(func: uid(0x123)) {
    name
    secret: checkpwd(pass, "ThePassword")
  }
}

向量类型(float32vector)

float32vector 表示浮点数数组,常用于存储机器学习模型生成的 embeddings:

# Schema 定义
embedding: float32vector @index(hnsw) .

# 在建立 hnsw 索引后,可以结合 similar_to 函数进行相似度搜索
{
  similar(func: similar_to(embedding, [0.1, 0.2, 0.3, ...])) {
    uid
    name
  }
}

谓词命名规范

规则类型 说明
基本规则 可使用字母数字组合,也支持国际化资源标识符(IRI)格式
保留命名空间 无法定义以 dgraph. 开头的类型或谓词
支持的特殊字符 ][&*()_-+=!#$%(只要前后有字母或数字)
不支持的特殊字符 ^}|{~`

基于 RDF 类型的谓词类型推断

使用 RDF 类型进行 mutation 时,即使模式中已有定义,类型可能会被 RDF 类型覆盖:

重要说明
  • 如果类型不一致且不能转换,mutation 会报错
  • 如果 age 未定义,第一次 mutation 为 xs:int 类型,则模式设置为 int
  • 后续类型兼容则转换,若不兼容则报错

核心要点总结

  • 谓词是描述对象信息的最小单元,可以是文字值或关系
  • 两种模式:strict 模式需要预先声明,flexible 模式自动推断
  • 标量类型:string、int、float、bool、dateTime、geo、password、float32vector
  • UID 类型:用于表示实体间的关系
  • 多语言支持:使用 @lang 指令和语言标签
  • 约束指令@unique@upsert@noconflict
  • 密码类型:使用 checkpwd 函数验证,不能直接查询

谓语指令

掌握 Dgraph 中谓词级别的各种指令和配置

什么是谓语指令?

谓词是 Dgraph 的核心(相当于边/属性)。所有指令几乎都是定义在谓词上的。

核心理解
  • 谓词级别的指令用于配置谓词的行为和特性
  • 这些指令决定了如何存储、索引和查询数据
  • 不同的指令组合可以实现复杂的数据操作需求

@index 索引指令

给谓词建索引,支持不同类型的索引方式,是查询性能的关键:

字符串类型索引

# 不同字符串索引类型
name: string @index(term) .           # 词项索引,支持部分匹配
email: string @index(exact) .         # 精确匹配索引
description: string @index(trigram) . # 三元组索引,支持模糊搜索
content: string @index(fulltext) .    # 全文索引,支持语言分析
pattern: string @index(regexp) .      # 正则表达式索引
索引类型 用途 查询函数
term 词项匹配,支持部分匹配 allofterms, anyofterms
exact 精确匹配 eq, in
trigram 模糊搜索,支持拼写错误 match
fulltext 全文搜索,支持语言分析 alloftext, anyoftext
regexp 正则表达式匹配 regexp

数值和日期类型索引

# 数值类型索引
age: int @index(int) .
score: float @index(float) .

# 日期时间索引
created_at: dateTime @index(year) .   # 按年索引
updated_at: dateTime @index(day) .    # 按天索引
event_time: dateTime @index(month) .  # 按月索引
log_time: dateTime @index(hour) .     # 按小时索引

特殊类型索引

# 地理位置索引
location: geo @index(geo) .

# 向量索引(用于机器学习)
embedding: float32vector @index(hnsw(metric: "cosine")) .
similarity: float32vector @index(hnsw(metric: "euclidean")) .

@reverse 反向指令

为 UID 边建立反向谓词,可以用 <~edge> 查询:

# Schema 定义
parent: [uid] @reverse .
children: [uid] @reverse .

# 查询示例
{
  # 查询某个人的所有孩子
  person(func: uid(0x123)) {
    name
    children {
      name
    }
  }
  
  # 查询某个人的所有父母(使用反向关系)
  child(func: uid(0x456)) {
    name
    <~parent> {
      name
    }
  }
}

📌 关键点:反向关系让您可以双向遍历图结构,无需显式存储两个方向的边。

@count 计数指令

为 UID 边建立 count 索引,可以快速获取边的数量:

# Schema 定义
friends: [uid] @count .
posts: [uid] @count .

# 查询示例
{
  users(func: gt(count(friends), 10)) {
    name
    count(friends)
  }
  
  # 按朋友数量排序
  popular_users(func: type(User), orderdesc: count(friends)) {
    name
    count(friends)
  }
}

@upsert 更新插入指令

用于 upsert(先查再写)操作,保证唯一性时避免冲突:

# Schema 定义
email: string @index(exact) @upsert .
username: string @index(exact) @upsert .

# Mutation 示例
{
  set {
    _:user <email> "alice@example.com" .
    _:user <name> "Alice" .
    _:user <dgraph.type> "User" .
  }
}

📌 工作原理:如果已存在相同 email 的用户,则更新该用户;否则创建新用户。

@unique 唯一性指令

确保某个谓词在所有节点中唯一(需要配合索引):

# Schema 定义
email: string @unique @index(exact) .
user_id: int @unique @index(int) .
phone: string @unique @index(hash) .
重要规则
  • 字符串类型:需要 hashexact 索引
  • 整数类型:需要 int 索引
  • 尝试插入重复值会导致 mutation 失败

@noconflict 防冲突指令

实验性指令,禁用事务冲突检测:

# Schema 定义
counter: int @noconflict .
status: string @noconflict .

⚠️ 警告:这可能导致数据丢失,不推荐在高正确性场景使用。

@lang 多语言指令

启用多语言支持,可以在字符串值后添加 @en@zh 等:

# Schema 定义
title: string @index(fulltext) @lang .
description: string @index(fulltext) @lang .

# Mutation 示例
{
  set {
    _:article <title> "Hello World"@en .
    _:article <title> "你好世界"@zh .
    _:article <description> "A greeting"@en .
    _:article <description> "一个问候"@zh .
    _:article <dgraph.type> "Article" .
  }
}

# 查询示例
{
  articles(func: alloftext(title@en, "Hello")) {
    title@en
    title@zh
  }
}

查询指令(非 Schema 指令)

严格说,这些是查询指令,不是 schema 指令,但很多人会混淆:

@cascade 级联指令

{
  users(func: type(User)) @cascade {
    name
    posts {
      title
      comments {
        content
      }
    }
  }
}

只返回所有嵌套字段都有值的用户。

@normalize 标准化指令

{
  users(func: type(User)) @normalize {
    name
    posts {
      title
    }
  }
}

将嵌套结构扁平化,每个 post 都会产生一个独立的用户记录。

指令组合使用

多个指令可以组合使用,实现复杂的数据需求:

# 复杂的谓词定义示例
email: string @index(exact) @unique @upsert .
name: string @index(term) @lang .
friends: [uid] @count @reverse .
location: geo @index(geo) .
embedding: float32vector @index(hnsw(metric: "cosine")) .
created_at: dateTime @index(year) .
tags: [string] @index(term) .
最佳实践
  • 根据查询需求选择合适的索引类型
  • 唯一性约束需要配合相应的索引
  • 多语言支持需要配合全文索引
  • 向量索引用于机器学习和相似度搜索

核心要点总结

  • @index:各种索引类型,决定查询性能和方式
  • @reverse:建立反向关系,支持双向遍历
  • @count:快速获取边的数量
  • @upsert:先查再写,避免冲突
  • @unique:确保唯一性,需要配合索引
  • @noconflict:实验性,禁用冲突检测
  • @lang:多语言支持
  • @cascade/@normalize:查询指令,非 schema 指令

节点类型

理解和使用 dgraph.type 标签系统

什么是 dgraph.type?

dgraph.type 是 Dgraph 内置的系统谓词

它的作用是:给某个节点打上一个或多个 类型标签(type/tag)

在 GraphQL schema 中定义的类型(type User { ... })最终也会映射为节点上的 dgraph.type 属性。

核心理解
  • Dgraph 底层没有真正的"节点类型",所有节点本质上都是一堆三元组
  • 但通过 dgraph.type,可以人为地为节点分组,使其具有"类型"的语义

基本语法

给节点添加类型标签的 mutation 写法:

RDF 语法

mutation {
  set {
    _:u1 <name> "Alice" .
    _:u1 <age> "25" .
    _:u1 <dgraph.type> "User" .
  }
}

这里:

  • _:u1 是新建节点的临时 blank node ID
  • <dgraph.type> "User" 表示该节点类型为 User

JSON 语法

mutation {
  set {
    "uid": "_:u1",
    "name": "Alice",
    "age": 25,
    "dgraph.type": "User"
  }
}

多类型标签

一个节点可以有多个类型:

mutation {
  set {
    _:m1 <name> "Inception" .
    _:m1 <release_date> "2010-07-16" .
    _:m1 <dgraph.type> "Film" .
    _:m1 <dgraph.type> "SciFi" .
  }
}

📌 节点 m1 同时属于 Film 和 SciFi 类型。

查询时使用 dgraph.type

你可以用 type() 函数筛选节点:

{
  q(func: type(User)) {
    uid
    name
    age
  }
}

这会返回所有 dgraph.type 包含 "User" 的节点。

结合 Schema 类型定义

节点类型是可选定义,用于声明某种类型节点应包含哪些谓词:

# 首先在 Schema 中声明谓词
name: string @index(term) .
dob: datetime .
home_address: string .
friends: [uid] .

# 然后定义类型
type Student {
  name
  dob
  home_address
  friends
}
重要规则
  • 类型定义中的所有谓词必须已在类型模式中声明
  • 不同节点类型可以共用相同谓词
  • 即使使用了类型,也可以为节点添加未声明的额外谓词

反向谓词(Reverse predicates)

使用 @reverse 可定义反向关系,并在类型中加以展示:

# Schema 定义
children: [uid] @reverse .
name: string @index(term) .

# 类型定义
type Parent {
  name
  children
}

type Child {
  name
  <~children>
}

这里 <~children> 表示反向关系,即从子节点指向父节点。

主要使用场景

节点类型主要用于以下两类操作:

1. 删除操作

delete {
  <0x123> * * .
}

使用 delete { <uid> * * . } 删除节点所有信息时,Dgraph 可根据类型定义识别哪些谓词需要删除。

2. 展开操作

{
  q(func: uid(0x123)) {
    expand(all)
  }
}

使用 expand(all) 查询所有谓词时,Dgraph 可根据类型定义识别哪些谓词需要展开。

⚠️ 注意:即使使用了类型,也可以为节点添加未声明的额外谓词,操作如 expand(all) 或删除可能不会影响这些额外谓词。

完整示例:电影数据库

以下是基于电影与演员数据库构建的完整模式示例:

# 谓词定义
director.film: [uid] @reverse .
actor.film: [uid] @count .
genre: [uid] @reverse .
initial_release_date: dateTime @index(year) .
name: string @index(exact, term) @lang .
starring: [uid] .
performance.film: [uid] .
performance.character_note: string .
performance.character: [uid] .
performance.actor: [uid] .
performance.special_performance_type: [uid] .
type: [uid] .

# 类型定义
type Person {
  name
  director.film
  actor.film
}

type Movie {
  name
  initial_release_date
  genre
  starring
}

type Genre {
  name
}

type Performance {
  performance.film
  performance.character
  performance.actor
}

特殊说明

规则 说明
数据类型 dgraph.type 必须是字符串(string),不能是 uid
大小写敏感 值区分大小写,例如 "User""user" 是不同的类型
多类型支持 节点可以拥有多个类型(值为字符串数组),如 ["Pet", "Animal"]
类型定义规则 类型定义中的所有谓词必须已在类型模式中声明
额外谓词 即使使用了类型,也可以为节点添加未声明的额外谓词
GraphQL 集成 在 GraphQL API 中写 mutation { addUser(...) } 时,底层其实就是自动在节点上打了 dgraph.type: "User"

核心要点总结

  • dgraph.type 是 Dgraph 内置的标签系统,用来给节点分组和定义类型
  • 节点类型是可选定义,用于声明某种类型节点应包含哪些谓词
  • 主要用途:删除操作和 expand(all) 查询时识别相关谓词
  • 支持多类型:一个节点可以拥有多个类型标签
  • 反向关系:使用 @reverse<~predicate> 语法
  • 在 DQL 里手动设置,在 GraphQL 里由系统自动生成

增删改查

DQL查询模式和Mutation数据变更完整指南

查询模式

DQL提供多种查询模式来满足不同的数据检索需求:

基本查询

query {
  user(func: eq(name, "Alice")) {
    uid
    name
    age
  }
}

按类型查询

{
  # 使用 type() 函数
  users(func: type(User)) {
    uid
    name
    age
  }
  
  # 使用 @filter 过滤
  users(func: has(name)) @filter(eq(dgraph.type, "User")) {
    uid
    name
    age
  }
}

递归查询

{
  # 无限层级递归
  network(func: eq(name, "Alice")) @recurse {
    name
    friend {
      name
    }
  }
  
  # 限制递归深度
  network(func: eq(name, "Alice")) @recurse(depth: 3) {
    name
    friend {
      name
    }
  }
}

多块查询

{
  # 用户查询
  users(func: type(User)) {
    uid
    name
    age
  }
  
  # 电影查询
  movies(func: type(Movie)) {
    uid
    title
    year
  }
  
  # 关系查询
  relationships(func: has(friend)) {
    uid
    friend {
      name
    }
  }
}

参数化查询

query all($name: string, $minAge: int) {
  users(func: eq(name, $name)) @filter(ge(age, $minAge)) {
    uid
    name
    age
  }
}

请求变量:

{
  "name": "Alice",
  "minAge": 18
}

聚合查询

{
  stats(func: has(age)) {
    count(uid)        # 总数量
    sum(age)          # 年龄总和
    avg(age)          # 平均年龄
    min(age)          # 最小年龄
    max(age)          # 最大年龄
  }
}

分组查询

{
  # 按年龄分组统计
  ageGroups(func: has(age)) @groupby(age) {
    count(uid)
  }
  
  # 按类型分组统计
  typeGroups(func: has(dgraph.type)) @groupby(dgraph.type) {
    count(uid)
  }
}

边属性(Facet)查询

{
  users(func: has(name)) {
    name
    friend @facets(since, closeness) {  # 查询边的属性
      name
    }
  }
}

展开查询

{
  # 展开所有字段
  users(func: eq(name, "Alice")) {
    expand(_all_) {
      expand(_all_)
    }
  }
  
  # 展开特定类型的所有字段
  users(func: type(User)) {
    expand(User)
  }
}

Mutation(数据变更)

DQL的Mutation操作支持多种数据变更模式:

新增节点

使用RDF格式创建新节点:

mutation {
  set {
    _:alice <name> "Alice Johnson" .
    _:alice <age> "30" .
    _:alice <email> "alice@example.com" .
    _:alice <dgraph.type> "User" .
  }
}

使用JSON格式创建新节点:

mutation {
  set {
    "uid": "_:alice",
    "dgraph.type": "User",
    "name": "Alice Johnson",
    "age": 30,
    "email": "alice@example.com"
  }
}

创建关系

mutation {
  set {
    _:alice <name> "Alice" .
    _:alice <dgraph.type> "User" .
    
    _:bob <name> "Bob" .
    _:bob <dgraph.type> "User" .
    
    _:alice <friend> _:bob .
    _:bob <friend> _:alice .  # 双向关系
  }
}

更新节点

mutation {
  set {
    <0x1> <age> "31" .
    <0x1> <email> "alice.new@example.com" .
    <0x1> <lastLogin> "2024-01-15T10:30:00Z" .
  }
}

更新类型标签

mutation {
  set {
    <0x1> <dgraph.type> "Employee" .  # 添加新类型
    <0x1> <dgraph.type> "Manager" .   # 添加多个类型
  }
}

删除操作

mutation {
  delete {
    <0x1> <email> * .                    # 删除email属性
    <0x1> <friend> <0x2> .              # 删除特定关系
    <0x1> <dgraph.type> "Manager" .     # 删除特定类型标签
  }
}

mutation {
  delete {
    <0x1> * * .  # 删除整个节点及其所有属性和关系
  }
}

事务控制

# 立即提交事务
mutation {
  set {
    _:alice <name> "Alice" .
    _:alice <dgraph.type> "User" .
  }
  commitNow: true
}

# 指定事务开始时间戳
mutation {
  set {
    _:alice <name> "Alice" .
  }
  startTs: 1234567890
}

# 回滚事务
mutation {
  set {
    _:alice <name> "Alice" .
  }
  abort: true
}

批量操作

mutation {
  set {
    _:person1 <name> "Alice" .
    _:person1 <age> "30" .
    _:person1 <dgraph.type> "User" .
    
    _:person2 <name> "Bob" .
    _:person2 <age> "28" .
    _:person2 <dgraph.type> "User" .
    
    _:person3 <name> "Charlie" .
    _:person3 <age> "32" .
    _:person3 <dgraph.type> "User" .
    
    # 建立关系网络
    _:person1 <friend> _:person2 .
    _:person2 <friend> _:person3 .
    _:person1 <friend> _:person3 .
  }
}

条件更新

{
  # 先查询需要更新的节点
  var(func: eq(name, "Alice")) {
    alice as uid
  }
  
  # 然后更新
  mutation {
    set {
      uid(alice) <status> "active" .
      uid(alice) <lastLogin> "2024-01-15T10:30:00Z" .
    }
  }
}

类型标签操作

管理节点的类型标签系统:

添加类型标签

mutation {
  set {
    <0x1> <dgraph.type> "Employee" .  # 给现有节点添加Employee类型
    <0x1> <dgraph.type> "Manager" .   # 同时添加Manager类型
    <0x1> <dgraph.type> "Admin" .     # 可以添加多个类型
  }
}

删除类型标签

mutation {
  delete {
    <0x1> <dgraph.type> "Manager" .  # 删除Manager类型标签
  }
}

按类型查询

{
  # 查询所有Employee
  employees(func: type(Employee)) {
    uid
    name
    dgraph.type
  }
  
  # 查询既是Person又是Employee的节点
  personEmployees(func: type(Person, Employee)) {
    uid
    name
    dgraph.type
  }
  
  # 查询包含特定类型的所有节点
  allUsers(func: has(dgraph.type)) @filter(uid_in(dgraph.type, "User", "Employee")) {
    uid
    name
    dgraph.type
  }
}

类型统计

{
  # 按类型分组统计
  typeStats(func: has(dgraph.type)) @groupby(dgraph.type) {
    count(uid)
  }
  
  # 统计特定类型的数量
  userCount(func: type(User)) {
    count(uid)
  }
}

高级操作

复杂的数据操作和查询模式:

Upsert操作

{
  # 查询或创建
  var(func: eq(email, "alice@example.com")) {
    alice as uid
  }
  
  mutation {
    set {
      uid(alice) <name> "Alice" .
      uid(alice) <email> "alice@example.com" .
      uid(alice) <dgraph.type> "User" .
    }
  }
}

复杂关系操作

{
  # 查询朋友的朋友
  var(func: eq(name, "Alice")) {
    friends as friend
  }
  
  friendsOfFriends(func: uid(friends)) {
    name
    friend {
      name
    }
  }
}

数据迁移

{
  # 查询需要迁移的数据
  var(func: type(OldUser)) {
    oldUsers as uid
  }
  
  # 迁移数据
  mutation {
    set {
      uid(oldUsers) <dgraph.type> "User" .
    }
    delete {
      uid(oldUsers) <dgraph.type> "OldUser" .
    }
  }
}

中文支持

Dgraph 对中文编码的完整支持和最佳实践

Dgraph 对中文的支持

Dgraph 默认支持 UTF-8 编码,这意味着对中文编码有完整的原生支持。

核心要点
  • 节点(主语):完全支持中文标识符
  • 边(谓语):完全支持中文谓词名
  • 属性值:完全支持中文字符串
  • 唯一限制:使用中文标识符时,不能省略 < > 尖括号

重要规则:尖括号不能省略

当使用中文作为节点或谓词标识符时,必须使用尖括号

❌ 错误写法

# 错误:中文标识符没有尖括号
张三 <姓名> "张三" .
张三 <年龄> "25" .
张三 <朋友> 李四 .

✅ 正确写法

# 正确:中文标识符使用尖括号
<张三> <姓名> "张三" .
<张三> <年龄> "25" .
<张三> <朋友> <李四> .

完整的中文示例

以下是一个完整的中文数据模型示例:

Schema 定义

# 中文谓词定义
<姓名>: string @index(term) .
<年龄>: int @index(int) .
<职业>: string @index(term) .
<公司>: string @index(term) .
<朋友>: [uid] @reverse .
<同事>: [uid] @reverse .
<居住地>: string @index(term) .

# 中文类型定义
type 人员 {
  <姓名>
  <年龄>
  <职业>
  <公司>
  <朋友>
  <同事>
  <居住地>
}

数据插入

mutation {
  set {
    <张三> <姓名> "张三" .
    <张三> <年龄> 28 .
    <张三> <职业> "软件工程师" .
    <张三> <公司> "阿里巴巴" .
    <张三> <居住地> "杭州" .
    <张三> <dgraph.type> "人员" .
    
    <李四> <姓名> "李四" .
    <李四> <年龄> 26 .
    <李四> <职业> "产品经理" .
    <李四> <公司> "腾讯" .
    <李四> <居住地> "深圳" .
    <李四> <dgraph.type> "人员" .
    
    <王五> <姓名> "王五" .
    <王五> <年龄> 30 .
    <王五> <职业> "设计师" .
    <王五> <公司> "字节跳动" .
    <王五> <居住地> "北京" .
    <王五> <dgraph.type> "人员" .
    
    # 建立关系
    <张三> <朋友> <李四> .
    <张三> <朋友> <王五> .
    <李四> <同事> <王五> .
  }
}

数据查询

{
  # 查询所有人员
  所有人员(func: type(人员)) {
    <姓名>
    <年龄>
    <职业>
    <公司>
    <居住地>
  }
  
  # 查询张三的朋友
  张三的朋友(func: eq(<姓名>, "张三")) {
    <姓名>
    <朋友> {
      <姓名>
      <职业>
    }
  }
  
  # 查询在杭州的人员
  杭州人员(func: eq(<居住地>, "杭州")) {
    <姓名>
    <职业>
    <公司>
  }
}

多语言混合使用

Dgraph 支持中英文混合使用,提供了极大的灵活性:

# 中英文混合的 Schema
name: string @index(term) .
<姓名>: string @index(term) .
age: int @index(int) .
<年龄>: int @index(int) .
company: string @index(term) .
<公司>: string @index(term) .

# 中英文混合的数据
{
  set {
    <user1> name "Alice" .
    <user1> <姓名> "爱丽丝" .
    <user1> age 25 .
    <user1> <年龄> 25 .
    <user1> company "Google" .
    <user1> <公司> "谷歌" .
  }
}

中文索引和查询

中文文本支持各种索引类型和查询方式:

全文索引

# Schema 定义
<文章内容>: string @index(fulltext) @lang .

# 数据插入
{
  set {
    <article1> <文章内容> "人工智能正在改变世界"@zh .
    <article1> <文章内容> "Artificial Intelligence is changing the world"@en .
  }
}

# 中文全文搜索
{
  搜索结果(func: alloftext(<文章内容>@zh, "人工智能")) {
    <文章内容>@zh
  }
}

词项索引

# Schema 定义
<标签>: [string] @index(term) .

# 数据插入
{
  set {
    <product1> <标签> "智能手机" .
    <product1> <标签> "5G" .
    <product1> <标签> "拍照" .
  }
}

# 词项搜索
{
  产品搜索(func: allofterms(<标签>, "智能手机 拍照")) {
    <标签>
  }
}

最佳实践

场景 建议 示例
标识符命名 使用有意义的中文名称 <用户>, <订单>, <产品>
谓词命名 保持简洁明了 <姓名>, <年龄>, <创建时间>
类型定义 使用业务领域术语 type 用户, type 订单
索引选择 根据查询需求选择 精确匹配用 exact,模糊搜索用 term
多语言支持 使用 @lang 指令 <标题>: string @index(fulltext) @lang

常见问题和解决方案

问题1:中文查询结果为空

原因:可能没有正确使用尖括号或索引配置不当

解决:确保中文标识符使用 <> 包围,并配置合适的索引

问题2:中文字符显示乱码

原因:客户端编码设置问题

解决:确保客户端使用 UTF-8 编码

问题3:中文全文搜索不准确

原因:没有使用 @lang 指令

解决:添加 @lang 指令并指定语言标签

核心要点总结

  • UTF-8 原生支持:Dgraph 默认支持中文编码
  • 尖括号必须:中文标识符必须使用 <> 包围
  • 完整功能支持:节点、边、属性值都支持中文
  • 索引支持:中文文本支持各种索引类型
  • 多语言混合:可以中英文混合使用
  • 全文搜索:使用 @lang 指令支持中文全文搜索
  • 最佳实践:使用有意义的命名和合适的索引