我正在考虑开发一个年龄函数,返回图的邻接矩阵。邻接矩阵存储两个节点之间的边数。检查邻接矩阵中是否存在边的复杂度为 O(1),而空间复杂度为 O(v^2),其中 v = 顶点数。 AGE 将每个图的顶点存储在
graph_name._ag_label_vertex
中,而边存储在 graph_name._ag_label_edge
中。
顶点表包含两列:id和properties。 id 列是整数类型,而properties 列是类似 JSON 的格式。边表包含边的 id、它来自的顶点的 id、它去的顶点的 id 以及边的属性。
示例:
SELECT * FROM "graph_name"."Vertex";
id | properties
------------------+-------------
844424930131971 | {}
1407374883553281 | {}
SELECT * FROM "graph_name"."Edges";
id | start_id | end_id | properties
------------------+-----------------+------------------+------------
1125899906842625 | 844424930131971 | 1407374883553281 | {}
(1 row)
我正在考虑首先遍历顶点列,以便最初可以存储顶点ID:
[0, 1, 2, 3]
[1, 0, 0, 0]
[2, 0, 0, 0]
[3, 0, 0, 0]
之后,循环遍历edges表,如果两个节点之间存在边,则存储1(如果一对节点之间有多条边,则为每条边在已经设置的值上加1)。但我不知道如何在 C 中为 postgres 函数执行此操作。 我应该调用哪个函数来遍历表并从 id 列获取值?我虽然使用了 SPI 两次,第一次用于顶点,第二次用于边缘,但我不知道这是否是最好的接近。
在age--1.3.0.sql文件中,我将函数声明为
CREATE FUNCTION ag_catalog.get_adjacency_matrix(graph_name name)
RETURNS integer[][]
LANGUAGE c
AS 'MODULE_PATHNAME';
它的定义在src/backend/commands/graph_commands.c
PG_FUNCTION_INFO_V1(get_adjacency_matrix);
/*
* Function for returning the graph's adjacency matrix. This adjacency matrix
* stores the number of edges between two nodes. The complexity to check if an
* edge exists within an adjacency matrix is O(1), while the space complexity
* is O(v^2) with v = number of vertices.
*/
Datum get_adjacency_matrix(PG_FUNCTION_ARGS)
{
PG_RETURN_VOID();
}
这不是答案,但它可以被视为来自另一个函数的指南:
通过查看
get_all_edge_labels_per_graph
在某些时候,我们可以使用这些函数来获取其中的元组,如下所示:
功能:
/*
* Retrieves a list of all the names of a graph.
*
* XXX: We may want to use the cache system for this function,
* however the cache system currently requires us to know the
* name of the label we want.
*/
List *get_all_edge_labels_per_graph(EState *estate, Oid graph_oid)
{
List *labels = NIL;
ScanKeyData scan_keys[2];
Relation ag_label;
TableScanDesc scan_desc;
HeapTuple tuple;
TupleTableSlot *slot;
ResultRelInfo *resultRelInfo;
// setup scan keys to get all edges for the given graph oid
ScanKeyInit(&scan_keys[1], Anum_ag_label_graph, BTEqualStrategyNumber,
F_OIDEQ, ObjectIdGetDatum(graph_oid));
ScanKeyInit(&scan_keys[0], Anum_ag_label_kind, BTEqualStrategyNumber,
F_CHAREQ, CharGetDatum(LABEL_TYPE_EDGE));
// setup the table to be scanned
ag_label = table_open(ag_label_relation_id(), RowExclusiveLock);
scan_desc = table_beginscan(ag_label, estate->es_snapshot, 2, scan_keys);
resultRelInfo = create_entity_result_rel_info(estate, "ag_catalog",
"ag_label");
slot = ExecInitExtraTupleSlot(
estate, RelationGetDescr(resultRelInfo->ri_RelationDesc),
&TTSOpsHeapTuple);
// scan through the results and get all the label names.
while(true)
{
Name label;
bool isNull;
Datum datum;
tuple = heap_getnext(scan_desc, ForwardScanDirection);
// no more labels to process
if (!HeapTupleIsValid(tuple))
break;
ExecStoreHeapTuple(tuple, slot, false);
datum = slot_getattr(slot, Anum_ag_label_name, &isNull);
label = DatumGetName(datum);
labels = lappend(labels, label);
}
table_endscan(scan_desc);
destroy_entity_result_rel_info(resultRelInfo);
table_close(resultRelInfo->ri_RelationDesc, RowExclusiveLock);
return labels;
}
参考资料: