Skip to main content
Glama
n-r-w

KnowledgeGraph MCP Server

by n-r-w
multiple-search-performance.test.ts9.59 kB
import { KnowledgeGraphManager } from '../../core.js'; import { PerformanceUtils } from './performance-utils.js'; // Skip global test setup for performance tests jest.mock('../setup.ts', () => ({ beforeEach: jest.fn(), afterEach: jest.fn() })); describe('Multiple Search Performance Tests', () => { let knowledgeGraphManager: KnowledgeGraphManager; const testProject = 'multiple_search_perf_test'; beforeAll(async () => { knowledgeGraphManager = new KnowledgeGraphManager(); // Create test entities for performance testing const testEntities = [ { name: 'JavaScript_Framework', entityType: 'technology', observations: ['Popular web development language', 'Used for frontend and backend'] }, { name: 'React_Library', entityType: 'technology', observations: ['Frontend JavaScript library', 'Component-based architecture'] }, { name: 'Node_Runtime', entityType: 'technology', observations: ['Server-side JavaScript runtime', 'Built on Chrome V8 engine'] }, { name: 'TypeScript_Language', entityType: 'technology', observations: ['Typed superset of JavaScript', 'Compiles to plain JavaScript'] }, { name: 'Next_Framework', entityType: 'technology', observations: ['React-based web framework', 'Full-stack capabilities'] }, { name: 'Express_Framework', entityType: 'technology', observations: ['Minimal Node.js web framework', 'Fast and unopinionated'] }, { name: 'MongoDB_Database', entityType: 'technology', observations: ['NoSQL document database', 'JSON-like documents'] }, { name: 'PostgreSQL_Database', entityType: 'technology', observations: ['Relational database system', 'ACID compliant'] }, { name: 'Docker_Platform', entityType: 'technology', observations: ['Containerization platform', 'Application deployment'] }, { name: 'Kubernetes_Orchestrator', entityType: 'technology', observations: ['Container orchestration', 'Scalable deployments'] }, { name: 'AWS_Cloud', entityType: 'technology', observations: ['Amazon cloud platform', 'Comprehensive cloud services'] }, { name: 'Git_VCS', entityType: 'technology', observations: ['Version control system', 'Distributed development'] }, { name: 'VSCode_Editor', entityType: 'technology', observations: ['Code editor by Microsoft', 'Extensible and lightweight'] }, { name: 'Jest_Testing', entityType: 'technology', observations: ['JavaScript testing framework', 'Snapshot testing'] }, { name: 'Webpack_Bundler', entityType: 'technology', observations: ['Module bundler', 'Asset optimization'] } ]; await knowledgeGraphManager.createEntities(testEntities, testProject); // Warm-up: Perform a few searches to initialize connections and caches await knowledgeGraphManager.searchNodes('warmup', { searchMode: 'exact' }, testProject); await knowledgeGraphManager.searchNodes(['warmup1', 'warmup2'], { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); }); afterAll(async () => { // Clean up test data const entityNames = [ 'JavaScript_Framework', 'React_Library', 'Node_Runtime', 'TypeScript_Language', 'Next_Framework', 'Express_Framework', 'MongoDB_Database', 'PostgreSQL_Database', 'Docker_Platform', 'Kubernetes_Orchestrator', 'AWS_Cloud', 'Git_VCS', 'VSCode_Editor', 'Jest_Testing', 'Webpack_Bundler' ]; await knowledgeGraphManager.deleteEntities(entityNames, testProject); await knowledgeGraphManager.close(); }); test('should benchmark single vs multiple query performance', async () => { const singleQueries = ['JavaScript', 'React', 'Node', 'TypeScript', 'Next']; // Increased sample size for more stable results const iterations = 10; // Benchmark single queries (sequential) const singleQueryBenchmark = await PerformanceUtils.runBenchmark(async () => { const results = []; for (const query of singleQueries) { const result = await knowledgeGraphManager.searchNodes(query, { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); results.push(result); } return results; }, iterations); // Benchmark multiple queries (batched) const multipleQueryBenchmark = await PerformanceUtils.runBenchmark(async () => { return await knowledgeGraphManager.searchNodes(singleQueries, { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); }, iterations); console.log('\n=== Multiple Search Performance Results ==='); console.log('Single Queries (Sequential):'); console.log(PerformanceUtils.formatBenchmarkResults(singleQueryBenchmark)); console.log('\nMultiple Queries (Batched):'); console.log(PerformanceUtils.formatBenchmarkResults(multipleQueryBenchmark)); // Environment-aware performance thresholds const isCI = process.env.CI === 'true' || process.env.NODE_ENV === 'test'; const isContinuousIntegration = process.env.GITHUB_ACTIONS === 'true' || process.env.JENKINS_URL || process.env.BUILDKITE; // Use median for more stable comparison (less affected by outliers) const performanceRatio = multipleQueryBenchmark.medianTime / singleQueryBenchmark.medianTime; // Adjust thresholds based on environment let maxRatio: number; if (isContinuousIntegration || isCI) { maxRatio = 5.0; // Very lenient for CI environments } else { maxRatio = 3.0; // More lenient than original 2.0 for local development } console.log(`\nPerformance Analysis:`); console.log(`- Performance Ratio (median): ${performanceRatio.toFixed(2)}x`); console.log(`- Environment: ${isContinuousIntegration || isCI ? 'CI/Test' : 'Local'}`); console.log(`- Threshold: ${maxRatio}x`); expect(performanceRatio).toBeLessThan(maxRatio); // Both should complete within reasonable time expect(singleQueryBenchmark.avgTime).toBeLessThan(2000); // 2 seconds (more lenient) expect(multipleQueryBenchmark.avgTime).toBeLessThan(2000); // 2 seconds (more lenient) }); test('should scale efficiently with increasing query count', async () => { const baseQueries = ['JavaScript', 'React']; const mediumQueries = ['JavaScript', 'React', 'Node', 'TypeScript', 'Next']; const largeQueries = ['JavaScript', 'React', 'Node', 'TypeScript', 'Next', 'Express', 'MongoDB', 'PostgreSQL', 'Docker', 'Kubernetes']; // Increased iterations for more stable results const iterations = 5; // Benchmark different query sizes const smallBenchmark = await PerformanceUtils.runBenchmark(async () => { return await knowledgeGraphManager.searchNodes(baseQueries, { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); }, iterations); const mediumBenchmark = await PerformanceUtils.runBenchmark(async () => { return await knowledgeGraphManager.searchNodes(mediumQueries, { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); }, iterations); const largeBenchmark = await PerformanceUtils.runBenchmark(async () => { return await knowledgeGraphManager.searchNodes(largeQueries, { searchMode: 'fuzzy', fuzzyThreshold: 0.3 }, testProject); }, iterations); console.log('\n=== Query Scaling Performance ==='); console.log(`2 queries: ${smallBenchmark.medianTime.toFixed(2)}ms (median)`); console.log(`5 queries: ${mediumBenchmark.medianTime.toFixed(2)}ms (median)`); console.log(`10 queries: ${largeBenchmark.medianTime.toFixed(2)}ms (median)`); // Use median for more stable scaling comparison const scalingFactor = largeBenchmark.medianTime / smallBenchmark.medianTime; // Environment-aware scaling thresholds const isCI = process.env.CI === 'true' || process.env.NODE_ENV === 'test'; const maxScalingFactor = isCI ? 15 : 10; // More lenient for CI console.log(`Scaling factor: ${scalingFactor.toFixed(2)}x (threshold: ${maxScalingFactor}x)`); expect(scalingFactor).toBeLessThan(maxScalingFactor); // All should complete within reasonable time (more lenient for CI) const maxTime = isCI ? 3000 : 2000; // 3 seconds for CI, 2 seconds for local expect(largeBenchmark.avgTime).toBeLessThan(maxTime); }); test('should handle empty and single query arrays efficiently', async () => { // Test empty array const emptyResult = await knowledgeGraphManager.searchNodes([], { searchMode: 'exact' }, testProject); expect(emptyResult.entities).toHaveLength(0); // Test single query in array (should be equivalent to string query) const arrayResult = await knowledgeGraphManager.searchNodes(['JavaScript'], { searchMode: 'exact' }, testProject); const stringResult = await knowledgeGraphManager.searchNodes('JavaScript', { searchMode: 'exact' }, testProject); expect(arrayResult.entities).toHaveLength(stringResult.entities.length); if (arrayResult.entities.length > 0 && stringResult.entities.length > 0) { expect(arrayResult.entities[0]?.name).toBe(stringResult.entities[0]?.name); } }); test('should deduplicate results correctly in multiple queries', async () => { // Search with overlapping terms that should return same entities const overlappingQueries = ['JavaScript', 'Script', 'Java']; const result = await knowledgeGraphManager.searchNodes(overlappingQueries, { searchMode: 'fuzzy', fuzzyThreshold: 0.2 }, testProject); // Check for duplicates const entityNames = result.entities.map(e => e.name); const uniqueNames = new Set(entityNames); expect(entityNames.length).toBe(uniqueNames.size); // No duplicates expect(result.entities.length).toBeGreaterThan(0); // Should find results }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/n-r-w/knowledgegraph-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server