How Fuzzy Search Differs from Semantic Search in the Egonex Knowledge Graph
Fuzzy search in Egonex uses Fuse.js for approximate string matching against node text fields, while semantic search computes cosine similarity between dense vector embeddings to capture conceptual meaning.
The Egonex Understand-Anything plugin provides two distinct search modes for exploring the knowledge graph. Understanding how fuzzy search differs from semantic search in the Egonex knowledge graph helps developers choose the right approach for typo-tolerant lookups versus meaning-based discovery. Both engines are implemented in the core package, but they differ fundamentally in algorithms, data requirements, and use cases.
Algorithmic Foundations
The two search modes employ fundamentally different approaches to matching queries against graph nodes.
Fuzzy Search Implementation
Fuzzy search relies on Fuse.js to perform approximate string matching. The engine tokenizes the query, builds an extended "OR" query (e.g., converting auth contrl into auth | contrl), and scores results by textual similarity. This approach indexes the node fields name, tags, summary, and languageNotes with descending weights (0.4 → 0.1) according to the source code in packages/core/src/search.ts.
The search method returns a list of {nodeId, score} objects where score represents the Fuse-derived relevance (0 indicates a perfect match). This method requires no pre-computed embeddings and operates purely on textual data present in the graph.
Semantic Search Implementation
Semantic search computes cosine similarity between dense vector embeddings of graph nodes and the query embedding. Implemented in packages/core/src/embedding-search.ts, the custom SemanticSearchEngine stores node embeddings in a Map structure and calculates similarity using the cosineSimilarity function (lines 14-30).
Unlike fuzzy matching, this approach captures semantic relationships, synonyms, and paraphrases by comparing high-dimensional vectors. The engine returns the top-k nodes whose similarity exceeds a configurable threshold, enabling discovery of conceptually related nodes that share little lexical overlap.
Implementation Details and File Structure
The architecture separates concerns between text-based and vector-based search:
| File | Purpose |
|---|---|
packages/core/src/search.ts |
Implements the fuzzy SearchEngine using Fuse.js (lines 14-25, 36-59) |
packages/core/src/embedding-search.ts |
Implements SemanticSearchEngine and cosineSimilarity for vector-based search (lines 14-30, 37-78) |
packages/dashboard/src/store.ts |
Holds the UI state (searchMode), creates the appropriate engine, and dispatches searches (lines 111-112, 519-531) |
packages/dashboard/src/components/SearchBar.tsx |
UI component that lets the user type a query and switch between fuzzy/semantic modes (lines 217-289) |
Data Requirements and Performance Characteristics
Each search mode presents distinct trade-offs in data preparation and computational overhead.
Fuzzy Search Advantages and Limitations
Strengths:
- Fast, deterministic execution with no external model dependencies
- Excellent for exact-ish name and tag lookups with typo tolerance
- Zero preprocessing required—works immediately on graph text fields
Limitations:
- Cannot capture relationships not expressed in searchable strings
- Scores derive from string distance metrics, not semantic meaning
- Misses conceptual connections between synonyms or related terms
Semantic Search Advantages and Limitations
Strengths:
- Captures semantic similarity across languages and paraphrases
- Surfaces conceptually related nodes despite minimal lexical overlap
- Enables discovery based on meaning rather than exact text matching
Limitations:
- Requires embedding generation, incurring computational cost
- Quality depends entirely on the embedding model
- Empty or low-quality embeddings produce poor or irrelevant results
Runtime Switching and UI Integration
The dashboard implements a runtime toggle between these modes using Zustand state management. In packages/dashboard/src/store.ts (lines 111-112), the store maintains searchMode: "fuzzy" | "semantic" with "fuzzy" as the default.
When users switch modes via the search bar UI (packages/dashboard/src/components/SearchBar.tsx), the application instantiates the appropriate engine. For semantic mode, the dashboard creates a SemanticSearchEngine instance (if embeddings exist) and calls its .search method; otherwise, it falls back to the fuzzy SearchEngine.
Practical Code Examples
Fuzzy Search Implementation
import { SearchEngine } from "@understand-anything/core/search";
// `graph.nodes` is an array of GraphNode objects.
const fuzzyEngine = new SearchEngine(graph.nodes);
// Basic query – fuzzy-matches name / summary / tags.
const fuzzyResults = fuzzyEngine.search("auth contrl", {
limit: 10,
types: ["function"], // optional filter
});
Semantic Search Implementation
import {
SemanticSearchEngine,
cosineSimilarity,
} from "@understand-anything/core/embedding-search";
// `embeddings` is a Record<string, number[]> keyed by node ID.
const semanticEngine = new SemanticSearchEngine(graph.nodes, embeddings);
// Assume `queryEmbedding` is obtained from an LLM for the user query.
const semanticResults = semanticEngine.search(queryEmbedding, {
limit: 10,
threshold: 0.6, // only return > 60% similarity
types: ["function"], // optional node-type filter
});
Toggle Implementation in Dashboard Store
// ... in the Zustand store definition
searchMode: "fuzzy", // default
// Switch mode (e.g. from UI)
setSearchMode: (mode) => set({ searchMode: mode }),
// When performing a search:
const engine = get().searchEngine!;
const mode = get().searchMode;
if (mode === "semantic" && engine instanceof SemanticSearchEngine) {
const results = engine.search(queryEmbedding);
// …
} else {
const results = engine.search(queryString);
// …
}
Summary
- Fuzzy search in
packages/core/src/search.tsuses Fuse.js for approximate string matching against node text fields (name, tags, summary, languageNotes), providing fast, typo-tolerant results without requiring embeddings. - Semantic search in
packages/core/src/embedding-search.tsimplements vector-based cosine similarity comparison to capture conceptual meaning, requiring pre-computed embeddings but enabling cross-lingual and synonym-aware discovery. - The dashboard store (
packages/dashboard/src/store.ts) manages runtime switching between modes via Zustand, defaulting to fuzzy search for immediate results while allowing semantic mode for deeper meaning-based exploration. - Algorithmic choice depends on use case: fuzzy for exact lookups with tolerance for typos, semantic for conceptual relationships and language-agnostic similarity.
Frequently Asked Questions
How does the Egonex knowledge graph handle the transition between fuzzy and semantic search modes?
The transition occurs through the Zustand store defined in packages/dashboard/src/store.ts. The store maintains a searchMode state that toggles between "fuzzy" and "semantic" values. When the mode changes, the application instantiates the appropriate engine—either the Fuse.js-based SearchEngine or the vector-based SemanticSearchEngine—and routes queries accordingly, allowing seamless switching without page reloads.
What specific fields does the fuzzy search engine index in the Egonex knowledge graph?
According to the implementation in packages/core/src/search.ts, the fuzzy search engine indexes four specific node fields: name (weight 0.4), tags (weight 0.3), summary (weight 0.2), and languageNotes (weight 0.1). These descending weights ensure that matches in node names rank higher than matches in supplementary notes.
Why might semantic search return poor results in the Egonex Understand-Anything plugin?
Semantic search quality depends entirely on the availability and quality of pre-computed embeddings for each graph node. If nodes lack embeddings, were processed with a low-quality model, or contain empty vectors, the cosineSimilarity calculation in packages/core/src/embedding-search.ts cannot establish meaningful relationships. Additionally, the configurable threshold (typically 0.6) may filter out results if the query embedding diverges significantly from stored node vectors.
Can I use both search modes simultaneously in the Egonex dashboard?
The current implementation in packages/dashboard/src/store.ts treats these modes as mutually exclusive via the searchMode state. However, the architecture allows you to instantiate both SearchEngine and SemanticSearchEngine concurrently in custom implementations, merging results from both fuzzyEngine.search() and semanticEngine.search() calls to create hybrid ranking systems.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →