Skip to content

Graph data formats

The knowledge map of a case is served as four static files under /v1/graph/{case}/. All binary files are little-endian and are cached with Cache-Control: public, max-age=86400, immutable plus an ETag. Use graphVersion from /v1/cases or version from meta as a cache key.

{
"case": "papers",
"version": "ragflow_v2",
"nodes": 7656,
"links": 61248,
"bounds": { "min": [-512.3, -498.1, -470.9], "max": [506.7, 515.2, 489.4] },
"clusters": 42
}

float32[nodes * 3] — x, y, z for each node, in nodeIndex order. Byte size is nodes × 12.

offset 0: x0 y0 z0 | 12: x1 y1 z1 | 24: x2 y2 z2 | …

int32[] adjacency list. A negative value starts a new source node and encodes it as -(id + 1); the positive values that follow are its neighbours encoded as id + 1. Ids are nodeIndex values.

[-1, 2, 3, -2, 3, -4, 1]
└ node 0 → 1, 2 └ node 1 → 2 └ node 3 → 0

Links are undirected for visualisation; a pair may appear once or in both directions.

const positions = await vol.graph.positions("papers"); // Float32Array
const links = await vol.graph.links("papers"); // Int32Array
const xyz = (i: number) => positions.subarray(i * 3, i * 3 + 3);
function* edges(links: Int32Array): Generator<[number, number]> {
let src = -1;
for (const v of links) {
if (v < 0) src = -v - 1;
else if (src >= 0) yield [src, v - 1];
}
}
// CSR adjacency (fast neighbour lookup for 80k+ nodes)
function toCsr(links: Int32Array, n: number) {
const deg = new Uint32Array(n);
for (const [a, b] of edges(links)) { deg[a]!++; deg[b]!++; }
const offsets = new Uint32Array(n + 1);
for (let i = 0; i < n; i++) offsets[i + 1] = offsets[i]! + deg[i]!;
const cols = new Uint32Array(offsets[n]!);
const fill = offsets.slice(0, n);
for (const [a, b] of edges(links)) { cols[fill[a]!++] = b; cols[fill[b]!++] = a; }
return { offsets, cols };
}

string[] with one title per node, in nodeIndex order. Use it for tooltips; fetch full metadata lazily with GET /v1/graph/{case}/nodes/{nodeIndex}.

interface ClustersFile {
clusters: { id: number; label: string; color: string; centroid: [number, number, number]; size: number }[];
assignment: number[]; // nodeIndex -> cluster id
}

color is #rrggbb. assignment.length === meta.nodes. Cluster ids are not guaranteed to be contiguous, so index clusters by id, not by array position.