Skip to main content
Glama
danielsimonjr

Enhanced Knowledge Graph Memory Server

SearchManager.ts12.4 kB
/** * Search Manager * * Orchestrates all search types (basic, ranked, boolean, fuzzy). * * @module search/SearchManager */ import type { KnowledgeGraph, SearchResult, SavedSearch } from '../types/index.js'; import type { GraphStorage } from '../core/GraphStorage.js'; import { BasicSearch } from './BasicSearch.js'; import { RankedSearch } from './RankedSearch.js'; import { BooleanSearch } from './BooleanSearch.js'; import { FuzzySearch } from './FuzzySearch.js'; import { SearchSuggestions } from './SearchSuggestions.js'; import { SavedSearchManager } from './SavedSearchManager.js'; /** * Unified search manager providing access to all search types. */ export class SearchManager { private basicSearch: BasicSearch; private rankedSearch: RankedSearch; private booleanSearcher: BooleanSearch; private fuzzySearcher: FuzzySearch; private searchSuggestions: SearchSuggestions; private savedSearchManager: SavedSearchManager; constructor(storage: GraphStorage, savedSearchesFilePath: string) { this.basicSearch = new BasicSearch(storage); this.rankedSearch = new RankedSearch(storage); this.booleanSearcher = new BooleanSearch(storage); this.fuzzySearcher = new FuzzySearch(storage); this.searchSuggestions = new SearchSuggestions(storage); this.savedSearchManager = new SavedSearchManager(savedSearchesFilePath, this.basicSearch); } // ==================== Basic Search ==================== /** * Perform a simple text-based search across entity names and observations. * * This is the primary search method that searches through entity names, * observations, and types using case-insensitive substring matching. * Optionally filter by tags and importance range. * * @param query - Text to search for (case-insensitive, searches names/observations/types) * @param tags - Optional array of tags to filter results (lowercase) * @param minImportance - Optional minimum importance value (0-10) * @param maxImportance - Optional maximum importance value (0-10) * @returns KnowledgeGraph containing matching entities and their relations * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // Simple text search * const results = await manager.searchNodes('Alice'); * * // Search with tag filter * const engineeringResults = await manager.searchNodes('project', ['engineering']); * * // Search with importance range * const importantResults = await manager.searchNodes('critical', undefined, 8, 10); * * // Combined filters * const filtered = await manager.searchNodes('bug', ['backend'], 5, 10); * ``` */ async searchNodes( query: string, tags?: string[], minImportance?: number, maxImportance?: number ): Promise<KnowledgeGraph> { return this.basicSearch.searchNodes(query, tags, minImportance, maxImportance); } /** * Open specific nodes by name. * * @param names - Array of entity names * @returns Knowledge graph with specified entities */ async openNodes(names: string[]): Promise<KnowledgeGraph> { return this.basicSearch.openNodes(names); } /** * Search by date range. * * @param startDate - Optional start date (ISO 8601) * @param endDate - Optional end date (ISO 8601) * @param entityType - Optional entity type filter * @param tags - Optional tags filter * @returns Filtered knowledge graph */ async searchByDateRange( startDate?: string, endDate?: string, entityType?: string, tags?: string[] ): Promise<KnowledgeGraph> { return this.basicSearch.searchByDateRange(startDate, endDate, entityType, tags); } // ==================== Ranked Search ==================== /** * Perform TF-IDF ranked search with relevance scoring. * * Uses Term Frequency-Inverse Document Frequency algorithm to rank results * by relevance to the query. Results are sorted by score (highest first). * This is ideal for finding the most relevant entities for a search query. * * @param query - Search query (analyzed for term frequency) * @param tags - Optional array of tags to filter results (lowercase) * @param minImportance - Optional minimum importance value (0-10) * @param maxImportance - Optional maximum importance value (0-10) * @param limit - Maximum number of results to return (default: 50, max: 200) * @returns Array of SearchResult objects sorted by relevance score (descending) * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // Basic ranked search * const results = await manager.searchNodesRanked('machine learning algorithms'); * results.forEach(r => { * console.log(`${r.entity.name} (score: ${r.score})`); * }); * * // Limit to top 10 most relevant results * const top10 = await manager.searchNodesRanked('database optimization', undefined, undefined, undefined, 10); * * // Ranked search with filters * const relevantImportant = await manager.searchNodesRanked( * 'security vulnerability', * ['security', 'critical'], * 8, * 10, * 20 * ); * ``` */ async searchNodesRanked( query: string, tags?: string[], minImportance?: number, maxImportance?: number, limit?: number ): Promise<SearchResult[]> { return this.rankedSearch.searchNodesRanked(query, tags, minImportance, maxImportance, limit); } // ==================== Boolean Search ==================== /** * Perform boolean search with AND, OR, NOT operators. * * Supports complex boolean logic for precise search queries. * Use AND/OR/NOT operators (case-insensitive) to combine search terms. * Parentheses are supported for grouping. * * @param query - Boolean query string (e.g., "alice AND bob", "frontend OR backend NOT legacy") * @param tags - Optional array of tags to filter results (lowercase) * @param minImportance - Optional minimum importance value (0-10) * @param maxImportance - Optional maximum importance value (0-10) * @returns KnowledgeGraph containing entities matching the boolean expression * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // AND operator - entities matching all terms * const both = await manager.booleanSearch('database AND performance'); * * // OR operator - entities matching any term * const either = await manager.booleanSearch('frontend OR backend'); * * // NOT operator - exclude terms * const excluding = await manager.booleanSearch('API NOT deprecated'); * * // Complex queries with grouping * const complex = await manager.booleanSearch('(react OR vue) AND (component OR hook) NOT legacy'); * ``` */ async booleanSearch( query: string, tags?: string[], minImportance?: number, maxImportance?: number ): Promise<KnowledgeGraph> { return this.booleanSearcher.booleanSearch(query, tags, minImportance, maxImportance); } // ==================== Fuzzy Search ==================== /** * Perform fuzzy search with typo tolerance. * * Uses Levenshtein distance to find entities that approximately match the query, * making it ideal for handling typos and variations in spelling. * Higher threshold values require closer matches. * * @param query - Search query (will match approximate spellings) * @param threshold - Similarity threshold from 0.0 (very lenient) to 1.0 (exact match). Default: 0.7 * @param tags - Optional array of tags to filter results (lowercase) * @param minImportance - Optional minimum importance value (0-10) * @param maxImportance - Optional maximum importance value (0-10) * @returns KnowledgeGraph containing entities with similar names/observations * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // Find entities even with typos * const results = await manager.fuzzySearch('databse'); // Will match "database" * * // Adjust threshold for strictness * const strict = await manager.fuzzySearch('optmization', 0.9); // Requires very close match * const lenient = await manager.fuzzySearch('optmization', 0.6); // More tolerant of differences * * // Fuzzy search with filters * const filtered = await manager.fuzzySearch('secrity', 0.7, ['important'], 7, 10); * ``` */ async fuzzySearch( query: string, threshold?: number, tags?: string[], minImportance?: number, maxImportance?: number ): Promise<KnowledgeGraph> { return this.fuzzySearcher.fuzzySearch(query, threshold, tags, minImportance, maxImportance); } // ==================== Search Suggestions ==================== /** * Get search suggestions for a query. * * @param query - Search query * @param maxSuggestions - Maximum suggestions to return * @returns Array of suggested terms */ async getSearchSuggestions(query: string, maxSuggestions?: number): Promise<string[]> { return this.searchSuggestions.getSearchSuggestions(query, maxSuggestions); } // ==================== Saved Searches ==================== /** * Save a search query for later reuse. * * Saved searches store query parameters and can be re-executed later. * The system tracks usage count and last used timestamp automatically. * * @param search - Search parameters (name, query, and optional filters) * @returns Newly created SavedSearch object with metadata * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // Save a simple search * const saved = await manager.saveSearch({ * name: 'High Priority Bugs', * query: 'bug', * tags: ['critical'], * minImportance: 8 * }); * * // Save a complex search * await manager.saveSearch({ * name: 'Recent Frontend Work', * query: 'component OR hook', * tags: ['frontend', 'react'], * searchType: 'boolean' * }); * ``` */ async saveSearch( search: Omit<SavedSearch, 'createdAt' | 'useCount' | 'lastUsed'> ): Promise<SavedSearch> { return this.savedSearchManager.saveSearch(search); } /** * List all saved searches. * * @returns Array of saved searches */ async listSavedSearches(): Promise<SavedSearch[]> { return this.savedSearchManager.listSavedSearches(); } /** * Get a saved search by name. * * @param name - Search name * @returns Saved search or null */ async getSavedSearch(name: string): Promise<SavedSearch | null> { return this.savedSearchManager.getSavedSearch(name); } /** * Execute a saved search by name. * * Runs a previously saved search with its stored parameters. * Automatically updates the search's useCount and lastUsed timestamp. * * @param name - The unique name of the saved search to execute * @returns KnowledgeGraph containing the search results * @throws Error if saved search not found * * @example * ```typescript * const manager = new SearchManager(storage, savedSearchesPath); * * // Execute a saved search * const results = await manager.executeSavedSearch('High Priority Bugs'); * console.log(`Found ${results.entities.length} high priority bugs`); * * // Handle missing saved search * try { * await manager.executeSavedSearch('NonExistent'); * } catch (error) { * console.error('Search not found'); * } * ``` */ async executeSavedSearch(name: string): Promise<KnowledgeGraph> { return this.savedSearchManager.executeSavedSearch(name); } /** * Delete a saved search. * * @param name - Search name * @returns True if deleted */ async deleteSavedSearch(name: string): Promise<boolean> { return this.savedSearchManager.deleteSavedSearch(name); } /** * Update a saved search. * * @param name - Search name * @param updates - Fields to update * @returns Updated saved search */ async updateSavedSearch( name: string, updates: Partial<Omit<SavedSearch, 'name' | 'createdAt' | 'useCount' | 'lastUsed'>> ): Promise<SavedSearch> { return this.savedSearchManager.updateSavedSearch(name, updates); } }

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/danielsimonjr/memory-mcp'

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