边集合与顶点 #

一、顶点集合 #

1.1 创建顶点集合 #

顶点集合就是普通的文档集合:

javascript
db._create("users");
db._create("products");
db._create("posts");

1.2 插入顶点 #

aql
INSERT {
    name: "张三",
    email: "zhangsan@example.com",
    age: 28
} INTO users

1.3 顶点文档结构 #

json
{
    "_key": "user_001",
    "_id": "users/user_001",
    "_rev": "_abc123",
    "name": "张三",
    "email": "zhangsan@example.com",
    "age": 28
}

1.4 批量插入顶点 #

aql
FOR i IN 1..100
    INSERT {
        _key: CONCAT("user_", i),
        name: CONCAT("用户", i),
        email: CONCAT("user", i, "@example.com")
    } INTO users

二、边集合 #

2.1 创建边集合 #

javascript
db._createEdgeCollection("follows");
db._createEdgeCollection("purchased");
db._createEdgeCollection("commented");

2.2 边文档结构 #

json
{
    "_key": "follow_001",
    "_id": "follows/follow_001",
    "_rev": "_def456",
    "_from": "users/user_001",
    "_to": "users/user_002",
    "createdAt": "2024-01-15T10:30:00Z",
    "type": "friend"
}

2.3 插入边 #

aql
INSERT {
    _from: "users/user_001",
    _to: "users/user_002",
    createdAt: DATE_NOW(),
    type: "follow"
} INTO follows

2.4 批量插入边 #

aql
FOR i IN 1..50
    INSERT {
        _from: CONCAT("users/user_", i),
        _to: CONCAT("users/user_", i + 1),
        createdAt: DATE_NOW()
    } INTO follows

2.5 边集合选项 #

javascript
db._createEdgeCollection("follows", {
    replicationFactor: 2,
    numberOfShards: 4
});

三、图定义 #

3.1 创建图 #

使用JavaScript API:

javascript
var graph = db._createGraph("social", {
    edgeDefinitions: [
        {
            collection: "follows",
            from: ["users"],
            to: ["users"]
        },
        {
            collection: "purchased",
            from: ["users"],
            to: ["products"]
        }
    ]
});

3.2 边定义详解 #

javascript
{
    collection: "follows",
    from: ["users"],
    to: ["users"]
}
字段 说明
collection 边集合名称
from 起点顶点集合
to 终点顶点集合

3.3 多边定义 #

javascript
var graph = db._createGraph("ecommerce", {
    edgeDefinitions: [
        {
            collection: "purchased",
            from: ["users"],
            to: ["products"]
        },
        {
            collection: "reviewed",
            from: ["users"],
            to: ["products"]
        },
        {
            collection: "contains",
            from: ["orders"],
            to: ["products"]
        }
    ]
});

3.4 孤儿集合 #

孤儿集合是图中包含但不参与边定义的顶点集合:

javascript
var graph = db._createGraph("social", {
    edgeDefinitions: [
        {
            collection: "follows",
            from: ["users"],
            to: ["users"]
        }
    ],
    orphanCollections: ["categories"]
});

3.5 查看图 #

javascript
db._graphs.toArray();

3.6 获取图对象 #

javascript
var graph = db._graph("social");

3.7 删除图 #

javascript
db._graph("social").drop();

删除图和数据:

javascript
db._graph("social").drop(true);

四、图API操作 #

4.1 图对象操作 #

javascript
var graph = db._graph("social");

graph.V();  // 获取所有顶点
graph.E();  // 获取所有边

4.2 顶点操作 #

javascript
var graph = db._graph("social");

graph.addVertex("users", {
    name: "新用户",
    email: "new@example.com"
});

graph.removeVertex("users/user_001");

4.3 边操作 #

javascript
var graph = db._graph("social");

graph.addEdge("follows", {
    _from: "users/user_001",
    _to: "users/user_002",
    type: "friend"
});

graph.removeEdge("follows/follow_001");

4.4 获取顶点 #

javascript
var graph = db._graph("social");
var vertex = graph.vertex("users/user_001");

4.5 获取边 #

javascript
var graph = db._graph("social");
var edge = graph.edge("follows/follow_001");

五、边查询 #

5.1 查询所有边 #

aql
FOR edge IN follows
    RETURN edge

5.2 查询特定起点的边 #

aql
FOR edge IN follows
    FILTER edge._from == "users/user_001"
    RETURN edge

5.3 查询特定终点的边 #

aql
FOR edge IN follows
    FILTER edge._to == "users/user_001"
    RETURN edge

5.4 查询特定顶点的所有边 #

aql
FOR edge IN follows
    FILTER edge._from == "users/user_001" OR edge._to == "users/user_001"
    RETURN edge

5.5 边统计 #

aql
FOR edge IN follows
    COLLECT type = edge.type WITH COUNT INTO count
    RETURN {
        type: type,
        count: count
    }

六、顶点度数 #

6.1 出度 #

出度是从该顶点出发的边数量:

aql
LET userId = "users/user_001"
FOR edge IN follows
    FILTER edge._from == userId
    COLLECT WITH COUNT INTO outDegree
    RETURN outDegree

6.2 入度 #

入度是到达该顶点的边数量:

aql
LET userId = "users/user_001"
FOR edge IN follows
    FILTER edge._to == userId
    COLLECT WITH COUNT INTO inDegree
    RETURN inDegree

6.3 总度数 #

aql
LET userId = "users/user_001"
LET outDegree = (
    FOR edge IN follows
        FILTER edge._from == userId
        COLLECT WITH COUNT INTO count
        RETURN count
)[0]
LET inDegree = (
    FOR edge IN follows
        FILTER edge._to == userId
        COLLECT WITH COUNT INTO count
        RETURN count
)[0]
RETURN {
    userId: userId,
    outDegree: outDegree || 0,
    inDegree: inDegree || 0,
    totalDegree: (outDegree || 0) + (inDegree || 0)
}

七、实战示例 #

7.1 社交网络图 #

创建图结构:

javascript
db._create("users");
db._create("posts");
db._createEdgeCollection("follows");
db._createEdgeCollection("posted");
db._createEdgeCollection("liked");

var graph = db._createGraph("social", {
    edgeDefinitions: [
        {
            collection: "follows",
            from: ["users"],
            to: ["users"]
        },
        {
            collection: "posted",
            from: ["users"],
            to: ["posts"]
        },
        {
            collection: "liked",
            from: ["users"],
            to: ["posts"]
        }
    ]
});

插入数据:

aql
INSERT { name: "张三", email: "zhangsan@example.com" } INTO users
INSERT { name: "李四", email: "lisi@example.com" } INTO users
INSERT { title: "第一篇文章", content: "内容..." } INTO posts

INSERT { _from: "users/张三_key", _to: "users/李四_key" } INTO follows
INSERT { _from: "users/张三_key", _to: "posts/文章_key" } INTO posted
INSERT { _from: "users/李四_key", _to: "posts/文章_key" } INTO liked

7.2 电商推荐图 #

创建图结构:

javascript
db._create("users");
db._create("products");
db._create("categories");
db._createEdgeCollection("purchased");
db._createEdgeCollection("viewed");
db._createEdgeCollection("belongs_to");

var graph = db._createGraph("ecommerce", {
    edgeDefinitions: [
        {
            collection: "purchased",
            from: ["users"],
            to: ["products"]
        },
        {
            collection: "viewed",
            from: ["users"],
            to: ["products"]
        },
        {
            collection: "belongs_to",
            from: ["products"],
            to: ["categories"]
        }
    ]
});

7.3 知识图谱 #

创建图结构:

javascript
db._create("concepts");
db._create("entities");
db._createEdgeCollection("is_a");
db._createEdgeCollection("has_part");
db._createEdgeCollection("related_to");

var graph = db._createGraph("knowledge", {
    edgeDefinitions: [
        {
            collection: "is_a",
            from: ["concepts", "entities"],
            to: ["concepts"]
        },
        {
            collection: "has_part",
            from: ["concepts", "entities"],
            to: ["concepts", "entities"]
        },
        {
            collection: "related_to",
            from: ["concepts", "entities"],
            to: ["concepts", "entities"]
        }
    ]
});

八、边集合索引 #

8.1 默认索引 #

边集合自动创建以下索引:

  • _from上的持久化索引
  • _to上的持久化索引

8.2 创建复合索引 #

javascript
db.follows.ensureHashIndex(["_from", "type"]);
db.follows.ensureHashIndex(["_to", "type"]);

8.3 创建跳表索引 #

javascript
db.follows.ensureSkipList(["createdAt"]);

九、边集合管理 #

9.1 查看边集合属性 #

javascript
db.follows.properties();

9.2 查看边集合统计 #

javascript
db.follows.figures();

9.3 清空边集合 #

javascript
db.follows.truncate();

9.4 删除边集合 #

javascript
db._drop("follows");

十、常见问题 #

10.1 边引用不存在的顶点 #

aql
FOR edge IN follows
    LET fromExists = DOCUMENT(edge._from)
    LET toExists = DOCUMENT(edge._to)
    FILTER fromExists == null OR toExists == null
    RETURN edge._key

10.2 清理孤立边 #

aql
FOR edge IN follows
    LET fromExists = DOCUMENT(edge._from)
    LET toExists = DOCUMENT(edge._to)
    FILTER fromExists == null OR toExists == null
    REMOVE edge IN follows

10.3 检查边集合类型 #

javascript
db.follows.properties().type === 3;

十一、总结 #

边集合与顶点操作要点:

  1. 顶点集合:普通文档集合
  2. 边集合:特殊集合,包含_from和_to
  3. 图定义:定义边集合连接的顶点集合
  4. 边操作:INSERT、REMOVE边文档
  5. 索引:_from和_to自动创建索引

下一步,让我们学习图遍历查询!

最后更新:2026-03-27