Skip to content
Snippets Groups Projects
Commit 064aa217 authored by Dorus's avatar Dorus
Browse files

feat: corrected graph udf

parent cd821dc1
No related branches found
No related tags found
No related merge requests found
Pipeline #147063 passed
import type { BackendQueryFormat, BackendQueryResultFormat, GraphQueryResultMetaFromBackend, NodeStruct } from 'ts-common';
import { log } from '../../logger';
import louvain from 'graphology-communities-louvain';
function applyFilter(op: string, value: number, threshold: number) {
......@@ -41,7 +40,7 @@ export const runUdfs = async (
);
for (const udf of query.udf) {
log.warn('Running UDF', query.udf, allUniqueNodes);
console.log('Running UDF', query.udf, allUniqueNodes);
const leftLabel = allUniqueNodes[udf.leftId].label;
const rightLabel = udf.rightId ? allUniqueNodes[udf.rightId].label : undefined;
......@@ -61,7 +60,7 @@ export const runUdfs = async (
nodeMap[edge.from] = nodeMap[edge.from] + 1;
}
log.warn('nodeMap', nodeMap, udf.right, query.udf);
console.log('nodeMap', nodeMap, udf.right, query.udf);
// Apply the operation filter based on degree
//
result.nodes = nodes.filter(node => {
......@@ -74,37 +73,89 @@ export const runUdfs = async (
const nodeIds = new Set(result.nodes.map(node => node._id));
result.edges = edges.filter(edge => nodeIds.has(edge.from) && nodeIds.has(edge.to));
}
else if (udf.type == "community_detection") {
const { Graph } = require('graphology');
const graph = new Graph();
result.nodes.forEach(node => graph.addNode(node._id));
result.edges.forEach(edge => graph.addEdge(edge.from, edge.to));
if (udf.type === 'community_detection') {
const nodes = result.nodes;
const edges = result.edges;
// Detect communities and community size
const communities = louvain(graph);
const communitySizes: Record<string, number> = {};
Object.values(communities).forEach(communityId => {
communitySizes[communityId] = (communitySizes[communityId] || 0) + 1;
// convert graph to adjacency list
const adjacencyList = {};
nodes.forEach(node => {
adjacencyList[node._id] = [];
});
// Filter nodes based on community size
result.nodes = result.nodes.filter(node => {
if (node.label !== leftLabel) return true;
const nodeCommunity = communities[node._id];
const communitySize = communitySizes[nodeCommunity] || 0;
edges.forEach(edge => {
adjacencyList[edge.from].push(edge.to);
adjacencyList[edge.to].push(edge.from);
});
const communities = {};
nodes.forEach(node => {
communities[node._id] = node._id;
});
let changed = true;
const maxIterations = 10;
let iterations = 0;
while (changed && iterations < maxIterations) {
changed = false;
iterations++;
for (const nodeId in adjacencyList) {
const neighbors = adjacencyList[nodeId];
if (neighbors.length === 0) continue;
// Count neighbors in each community
const communityCounts = {};
neighbors.forEach(neighborId => {
const communityId = communities[neighborId];
communityCounts[communityId] = (communityCounts[communityId] || 0) + 1;
});
// Find the community with the most neighbors
let bestCommunity = communities[nodeId];
let maxCount = 0;
for (const communityId in communityCounts) {
if (communityCounts[communityId] > maxCount) {
maxCount = communityCounts[communityId];
bestCommunity = communityId;
}
}
// Move to the best community if it's different
if (bestCommunity !== communities[nodeId]) {
communities[nodeId] = bestCommunity;
changed = true;
}
}
}
// Count nodes in each community
const communitySizes = {};
for (const nodeId in communities) {
const communityId = communities[nodeId];
communitySizes[communityId] = (communitySizes[communityId] || 0) + 1;
}
result.nodes = nodes.filter(node => {
const communityId = communities[node._id];
const communitySize = communitySizes[communityId] || 0;
// filter communities based on size
return applyFilter(udf.op, communitySize, udf.right);
});
// Filter edges
// Update edges to only include those connecting remaining nodes
const nodeIds = new Set(result.nodes.map(node => node._id));
result.edges = result.edges.filter(edge =>
nodeIds.has(edge.from) && nodeIds.has(edge.to)
);
result.edges = edges.filter(edge => nodeIds.has(edge.from) && nodeIds.has(edge.to));
}
}
log.warn(result.nodes.length, result.edges.length);
console.log(result.nodes.length, result.edges.length);
return result;
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment