图结构 (Graph)
图用于表达点与边组成的关系网络,常见于社交关系、知识图谱、推荐系统等。
在 Aiao 中可采用两种方式建模:
- 使用多对多关系(邻接集)——简单直接,适合轻量场景
- 使用
@GraphEntity——自动生成边表,支持边权重与边属性
多对多方式(邻接集)
可用多对多关系实现用户之间的"好友"关系(无向图):
GraphEntity 方式(自动边表)
@GraphEntity 会将类标记为图实体,并在运行期根据配置生成一张"边表"(命名为 节点实体名_edges)。
import { GraphEntity, GraphEntityBase, PropertyType } from '@aiao/rxdb';
@GraphEntity({
name: 'UserNode',
properties: [
{ name: 'name', type: PropertyType.string },
{ name: 'type', type: PropertyType.string }
],
features: {
// graphType: 'undirected-graph' | 'directed-graph'(默认无向图)
graphWeight: true, // 边是否带权重(生成 weight 字段)
graphProperties: true // 是否启用边属性 JSON(生成 properties 字段)
}
})
export class UserNode extends GraphEntityBase {}
自动边表:
- 表名:
UserNode_edges(与节点实体同命名空间) - 字段:
weight?: number、properties?: json(由 features 决定)
GraphRepository 图查询能力
GraphRepository 继承自 Repository,提供图遍历和路径查询能力。
查询邻居节点
// 查询直接好友(1跳)
const friends = await UserNode.findNeighbors({
entityId: 'alice-id',
level: 1
});
// 查询好友的好友(2度人脉,1跳+2跳)
const extendedNetwork = await UserNode.findNeighbors({
entityId: 'alice-id',
level: 2
});
// 结果包含节点、边信息和跳数
// { node: 邻居节点, edge: { sourceId, targetId, direction, weight, properties }, level: 跳数 }
查询选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
entityId | string | 必填 | 起始节点 ID |
level | number | 1 | 最大跳数(1-10) |
direction | 'in' | 'out' | 'both' | 'both' | 查询方向 |
where | RuleGroup | - | 节点过滤条件 |
edgeWhere | EdgeFilterOptions | - | 边过滤条件(权重、属性) |
统计邻居数量
// 高性能统计,不返回完整节点数据
const friendCount = await UserNode.countNeighbors({
entityId: 'alice-id',
level: 1
});
查询路径
// 查找两个节点之间的所有路径
const paths = await UserNode.findPaths({
fromId: 'alice-id',
toId: 'bob-id',
maxDepth: 5
});
// 路径结果
// {
// nodes: [节点数组,按顺序],
// edges: [边数组,包含 sourceId、targetId、weight、properties],
// length: 跳数,
// totalWeight: 总权重
// }
路径查询选项:
| 选项 | 类型 | 默认值 | 说明 |
|---|---|---|---|
fromId | string | 必填 | 源节点 ID |
toId | string | 必填 | 目标节点 ID |
maxDepth | number | 10 | 最大搜索深度(1-100) |
direction | 'in' | 'out' | 'both' | 'both' | 查询方向 |
where | RuleGroup | - | 路径节点过滤条件 |
edgeWhere | EdgeFilterOptions | - | 边过滤条件 |
边操作
// 添加边(可选权重和属性)
await UserNode.addEdge(userA, userB, 8, {
category: 'colleague',
since: '2024-01-01'
});
// 移除边
await UserNode.removeEdge(userA, userB);
边过滤条件
// 按权重过滤
const highValueFriends = await UserNode.findNeighbors({
entityId: 'alice-id',
level: 1,
edgeWhere: {
weight: { min: 5, max: 10 }
}
});
// 按边属性过滤
const businessPartners = await UserNode.findNeighbors({
entityId: 'alice-id',
level: 2,
edgeWhere: {
properties: { category: 'business' }
}
});
框架集成
各框架提供响应式 Hooks 来订阅图查询结果:
- Angular
- React
- Vue
import { useGraphNeighbors, useCountNeighbors, useGraphPaths } from '@aiao/rxdb-angular';
// 响应式邻居查询
const neighbors = useGraphNeighbors(UserNode, {
entityId: signal('alice-id'),
level: signal(2)
});
// 响应式邻居数量
const count = useCountNeighbors(UserNode, {
entityId: signal('alice-id'),
level: signal(1)
});
// 响应式路径查询
const paths = useGraphPaths(UserNode, {
fromId: signal('alice-id'),
toId: signal('bob-id'),
maxDepth: signal(5)
});
import { useGraphNeighbors, useCountNeighbors, useGraphPaths } from '@aiao/rxdb-react';
function SocialGraph() {
// 响应式邻居查询
const neighbors = useGraphNeighbors(UserNode, {
entityId: 'alice-id',
level: 2
});
// 响应式邻居数量
const count = useCountNeighbors(UserNode, {
entityId: 'alice-id',
level: 1
});
// 响应式路径查询
const paths = useGraphPaths(UserNode, {
fromId: 'alice-id',
toId: 'bob-id',
maxDepth: 5
});
return <div>好友数量: {count}</div>;
}
<script setup lang="ts">
import { useGraphNeighbors, useCountNeighbors, useGraphPaths } from '@aiao/rxdb-vue';
import { ref } from 'vue';
const entityId = ref('alice-id');
// 响应式邻居查询
const neighbors = useGraphNeighbors(UserNode, {
entityId,
level: ref(2)
});
// 响应式邻居数量
const count = useCountNeighbors(UserNode, {
entityId,
level: ref(1)
});
// 响应式路径查询
const paths = useGraphPaths(UserNode, {
fromId: entityId,
toId: ref('bob-id'),
maxDepth: ref(5)
});
</script>
<template>
<div>好友数量: {{ count }}</div>
</template>