mirror of
https://github.com/morluto/rea.git
synced 2026-10-29 02:45:58 +00:00
perf(javascript): index version relationships once per comparison (#1347)
relationshipSignature rebuilt a node map and scanned every graph edge for each side of each matched pair, so comparison cost grew as pairs x (nodes + edges). Build node and adjacency indexes once per graph in ItemContext; signatures, sorting and output are unchanged. At 4000 matched modules, end-to-end compare: 5.7s -> 2.9s (2 edges per node) and 10.4s -> 5.8s (6 edges per node); 8000: 3.3x and 2.5x. Output JSON is byte-identical on the base commit.
This commit is contained in:
1 parent
3f59a84bd1
commit
b1e85ad711
2 files changed
+232
-27
No files matched your search
@@ -27,6 +27,19 @@ interface ItemContext {
|
||||
readonly rightNativeEvidence: readonly Evidence[];
|
||||
readonly pairByLeft: ReadonlyMap<string, string>;
|
||||
readonly pairByRight: ReadonlyMap<string, string>;
|
||||
readonly leftRelationships: RelationshipIndex;
|
||||
readonly rightRelationships: RelationshipIndex;
|
||||
}
|
||||
|
||||
interface IndexedRelationship {
|
||||
readonly direction: "in" | "out";
|
||||
readonly relation: ApplicationEdge["relation"];
|
||||
readonly neighborId: string;
|
||||
}
|
||||
|
||||
interface RelationshipIndex {
|
||||
readonly nodeById: ReadonlyMap<string, ApplicationNode>;
|
||||
readonly adjacency: ReadonlyMap<string, readonly IndexedRelationship[]>;
|
||||
}
|
||||
|
||||
type OneSidedNode =
|
||||
@@ -53,7 +66,10 @@ type ComparisonItemSemantic<
|
||||
/** Classify matched, unmatched, and ambiguous nodes without inventing absence. */
|
||||
export const classifyJavaScriptApplicationVersions = (
|
||||
matching: ApplicationVersionMatchingProjection,
|
||||
context: Omit<ItemContext, "pairByLeft" | "pairByRight">,
|
||||
context: Omit<
|
||||
ItemContext,
|
||||
"pairByLeft" | "pairByRight" | "leftRelationships" | "rightRelationships"
|
||||
>,
|
||||
): ApplicationVersionItemProjection => {
|
||||
const pairByLeft = new Map(
|
||||
matching.pairs.map(({ left, right }) => [
|
||||
@@ -67,7 +83,13 @@ export const classifyJavaScriptApplicationVersions = (
|
||||
`pair:${left.node_id}:${right.node_id}`,
|
||||
]),
|
||||
);
|
||||
const fullContext: ItemContext = { ...context, pairByLeft, pairByRight };
|
||||
const fullContext: ItemContext = {
|
||||
...context,
|
||||
pairByLeft,
|
||||
pairByRight,
|
||||
leftRelationships: indexRelationships(context.leftGraph),
|
||||
rightRelationships: indexRelationships(context.rightGraph),
|
||||
};
|
||||
const leftItems = matching.unmatchedLeft.map((node) => {
|
||||
const candidates = matching.candidatesForLeft.get(node.node_id) ?? [];
|
||||
return unmatchedItem(
|
||||
@@ -339,37 +361,45 @@ const properties = (node: ApplicationNode) =>
|
||||
compareUnicodeCodePoints(canonicalJson(left), canonicalJson(right)),
|
||||
);
|
||||
|
||||
const indexRelationships = (
|
||||
graph: JavaScriptApplicationGraph,
|
||||
): RelationshipIndex => {
|
||||
const adjacency = new Map<string, IndexedRelationship[]>();
|
||||
const add = (nodeId: string, relationship: IndexedRelationship): void => {
|
||||
const existing = adjacency.get(nodeId);
|
||||
if (existing === undefined) adjacency.set(nodeId, [relationship]);
|
||||
else existing.push(relationship);
|
||||
};
|
||||
for (const edge of graph.edges) {
|
||||
add(edge.source_node_id, {
|
||||
direction: "out",
|
||||
relation: edge.relation,
|
||||
neighborId: edge.target_node_id,
|
||||
});
|
||||
if (edge.target_node_id !== edge.source_node_id)
|
||||
add(edge.target_node_id, {
|
||||
direction: "in",
|
||||
relation: edge.relation,
|
||||
neighborId: edge.source_node_id,
|
||||
});
|
||||
}
|
||||
return {
|
||||
nodeById: new Map(graph.nodes.map((value) => [value.node_id, value])),
|
||||
adjacency,
|
||||
};
|
||||
};
|
||||
|
||||
const relationshipSignature = (
|
||||
node: ApplicationNode,
|
||||
side: "left" | "right",
|
||||
context: ItemContext,
|
||||
): string => {
|
||||
const graph = side === "left" ? context.leftGraph : context.rightGraph;
|
||||
const { nodeById, adjacency } =
|
||||
side === "left" ? context.leftRelationships : context.rightRelationships;
|
||||
const paired = side === "left" ? context.pairByLeft : context.pairByRight;
|
||||
const nodeById = new Map(graph.nodes.map((value) => [value.node_id, value]));
|
||||
const signatures = graph.edges.flatMap((edge) => {
|
||||
if (edge.source_node_id === node.node_id)
|
||||
return [
|
||||
edgeSignature({
|
||||
direction: "out",
|
||||
relation: edge.relation,
|
||||
neighborId: edge.target_node_id,
|
||||
paired,
|
||||
nodeById,
|
||||
}),
|
||||
];
|
||||
if (edge.target_node_id === node.node_id)
|
||||
return [
|
||||
edgeSignature({
|
||||
direction: "in",
|
||||
relation: edge.relation,
|
||||
neighborId: edge.source_node_id,
|
||||
paired,
|
||||
nodeById,
|
||||
}),
|
||||
];
|
||||
return [];
|
||||
});
|
||||
const signatures = (adjacency.get(node.node_id) ?? []).map((relationship) =>
|
||||
edgeSignature({ ...relationship, paired, nodeById }),
|
||||
);
|
||||
return canonicalJson(signatures.sort(compareUnicodeCodePoints));
|
||||
};
|
||||
|
||||
|
||||
Reference in new issue
Block a user