# How Fuzzy and Semantic Search Are Implemented in the Understand-Anything Dashboard

> Discover how the Understand Anything dashboard integrates fuzzy and semantic search using Fuse.js and cosine distance. Learn about the unified SearchResult interface and Zustand store.

- Repository: [Egonex/Understand-Anything](https://github.com/Egonex-AI/Understand-Anything)
- Tags: internals
- Published: 2026-06-10

---

**The Understand-Anything dashboard implements dual search modes—fuzzy keyword matching via Fuse.js and semantic vector similarity via cosine distance—unified through a common `SearchResult` interface managed by a Zustand store.**

The Understand-Anything project provides an interactive dashboard for exploring codebases, where finding relevant nodes quickly requires robust search capabilities. This article examines how the repository implements both **fuzzy and semantic search** to accommodate exact keyword matching and conceptual similarity retrieval, ensuring developers can locate code regardless of terminology mismatches.

## Fuzzy Search Implementation with Fuse.js

The fuzzy search engine relies on the **Fuse.js** library to perform weighted keyword matching against node metadata. Located in [`packages/core/src/search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/search.ts), the `SearchEngine` class indexes graph nodes and supports extended search syntax for partial matches.

### SearchEngine Configuration and Weights

The engine initializes with `FUSE_OPTIONS` that define searchable fields and their relevance weights. The configuration prioritizes node names (0.4), followed by tags (0.3), summaries (0.2), and language-specific notes (0.1), with a match threshold of 0.4.

```typescript
// packages/core/src/search.ts
import Fuse, { type IFuseOptions } from "fuse.js";
import type { GraphNode } from "./types.js";

const FUSE_OPTIONS: IFuseOptions<GraphNode> = {
  keys: [
    { name: "name", weight: 0.4 },
    { name: "tags", weight: 0.3 },
    { name: "summary", weight: 0.2 },
    { name: "languageNotes", weight: 0.1 },
  ],
  threshold: 0.4,
  includeScore: true,
  ignoreLocation: true,
  useExtendedSearch: true,
};

export class SearchEngine {
  private fuse: Fuse<GraphNode>;

  constructor(nodes: GraphNode[]) {
    this.fuse = new Fuse(nodes, FUSE_OPTIONS);
  }

  search(query: string, options?: SearchOptions): SearchResult[] {
    const trimmed = query.trim();
    if (!trimmed) return [];

    const extendedQuery = trimmed.split(/\s+/).join(" | ");
    const rawResults = this.fuse.search(extendedQuery);
    /* …filter by type, slice by limit… */
    return rawResults.slice(0, limit).map(r => ({
      nodeId: r.item.id,
      score: r.score ?? 0,
    }));
  }
}

```

### Extended Query Syntax

The `search` method transforms user input into an extended query format by joining terms with the `|` operator. This allows "auth contrl" to match entries containing either term, improving recall for imprecise inputs.

## Semantic Search via Vector Embeddings

For conceptual retrieval, the **semantic search** implementation in [`packages/core/src/embedding-search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/embedding-search.ts) computes cosine similarity between query embeddings and pre-computed node embeddings. This enables finding semantically related content even without keyword overlap.

### Cosine Similarity Calculation

The `cosineSimilarity` function calculates the dot product between two vectors normalized by their magnitudes, returning values between -1 and 1. The engine treats higher similarity as better matches, converting scores so that lower values indicate higher relevance (consistent with the fuzzy search scoring).

```typescript
// packages/core/src/embedding-search.ts
import type { GraphNode } from "./types.js";

export function cosineSimilarity(a: number[], b: number[]): number {
  // dot product + magnitudes → cosine
  // returns 0 for zero-magnitude vectors
}

export class SemanticSearchEngine {
  private nodes: GraphNode[];
  private embeddings: Map<string, number[]>;

  constructor(nodes: GraphNode[], embeddings: Record<string, number[]>) {
    this.nodes = nodes;
    this.embeddings = new Map(Object.entries(embeddings));
  }

  search(queryEmbedding: number[], options?: SemanticSearchOptions): SearchResult[] {
    const limit = options?.limit ?? 10;
    const threshold = options?.threshold ?? 0;
    const typeFilter = options?.types;
    const scored: Array<{ nodeId: string; score: number }> = [];

    for (const node of this.nodes) {
      if (typeFilter && !typeFilter.includes(node.type)) continue;
      const embedding = this.embeddings.get(node.id);
      if (!embedding) continue;

      const similarity = cosineSimilarity(queryEmbedding, embedding);
      if (similarity >= threshold) {
        scored.push({ nodeId: node.id, score: 1 - similarity });
      }
    }

    scored.sort((a, b) => a.score - b.score);
    return scored.slice(0, limit);
  }
}

```

### Type Filtering and Thresholds

The `SemanticSearchEngine` supports optional filtering by node type and minimum similarity thresholds. Results are sorted by ascending score (where 0 represents perfect similarity) and sliced according to the specified limit.

## Dashboard Integration and State Management

The dashboard unifies both engines through a **Zustand** store defined in [`packages/dashboard/src/store.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/dashboard/src/store.ts). The `useDashboardStore` hook manages the active search mode and routes queries to the appropriate engine.

### Zustand Store Architecture

The store maintains `searchMode` state (`"fuzzy"` or `"semantic"`) and instantiates a `SearchEngine` when the graph loads via `setGraph`. The `setSearchQuery` action delegates to the active engine's search method, normalizing results into the common `SearchResult` format.

```typescript
// packages/dashboard/src/store.ts
export const useDashboardStore = create<DashboardStore>()((set, get) => ({
  searchMode: "fuzzy",
  setSearchMode: (mode) => set({ searchMode: mode }),

  setSearchQuery: (query) => {
    const engine = get().searchEngine;
    const mode = get().searchMode;
    
    if (!engine || !query.trim()) {
      set({ searchQuery: query, searchResults: [] });
      return;
    }
    
    // Line 528: SemanticSearchEngine will be used when mode is "semantic" 
    // and embeddings are present
    const searchResults = engine.search(query);
    set({ searchQuery: query, searchResults });
  },
}));

```

### Runtime Mode Switching

When users toggle search modes through the UI, the `setSearchMode` action updates state immediately. While the current implementation uses the fuzzy engine for both modes, the architecture supports hot-swapping to `SemanticSearchEngine` when vector embeddings are available, as noted in the source comments.

## Summary

- **Fuse.js powers fuzzy search** in [`packages/core/src/search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/search.ts), applying weighted field matching with a 0.4 threshold and extended query syntax.
- **Cosine similarity drives semantic search** in [`packages/core/src/embedding-search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/embedding-search.ts), comparing vector embeddings stored in a `Map<string, number[]>`.
- **Unified interface** via `SearchResult` (`nodeId` + `score`) allows seamless UI rendering regardless of search mode.
- **Zustand store** in [`packages/dashboard/src/store.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/dashboard/src/store.ts) orchestrates engine selection, query execution, and state persistence.
- **Lower scores indicate better matches** in both engines, ensuring consistent result ranking across fuzzy and semantic modes.

## Frequently Asked Questions

### What library does Understand-Anything use for fuzzy search?

The project uses **Fuse.js** to handle fuzzy keyword matching. The `SearchEngine` class in [`packages/core/src/search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/search.ts) configures Fuse with field-specific weights for names, tags, summaries, and language notes, enabling tolerant matching of incomplete or misspelled queries.

### How does semantic search calculate similarity between queries and nodes?

Semantic search computes **cosine similarity** between the query embedding and pre-computed node embeddings. Implemented in [`packages/core/src/embedding-search.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/core/src/embedding-search.ts), the `cosineSimilarity` function measures the angle between vectors, returning a value that the `SemanticSearchEngine` converts to a score where lower values represent higher relevance.

### Can the dashboard filter search results by node type?

Yes, both search engines support type filtering. The fuzzy engine accepts a `types` array in its `SearchOptions`, while the `SemanticSearchEngine` checks `options.types` during iteration, skipping nodes that don't match the specified types before calculating similarity scores.

### Where is the search mode state managed in the dashboard?

The **Zustand** store in [`packages/dashboard/src/store.ts`](https://github.com/Egonex-AI/Understand-Anything/blob/main/packages/dashboard/src/store.ts) manages the `searchMode` state (`"fuzzy"` or `"semantic"`). The `setSearchMode` action updates this state, while `setSearchQuery` routes execution to the currently active engine, with architecture prepared to instantiate `SemanticSearchEngine` when semantic mode and embeddings are both available.