How to Implement Fuzzy Search for Exercise Names in the Exercises Dataset

You can implement fuzzy search for exercise names by loading the data/exercises.json file into a Fuse.js index configured to search the name and aliases fields with a threshold of 0.4, enabling typo-tolerant client-side search without a backend.

The exercises-dataset repository by hasaneyldrm provides a static JSON catalog of fitness exercises. To help users locate exercises despite spelling errors or partial name matches, you can implement fuzzy search for exercise names using a lightweight JavaScript library. This approach indexes the dataset client-side and returns ranked results instantly as users type.

Architecture Overview

The implementation follows a three-layer client-side architecture. First, the application fetches the static dataset from [data/exercises.json](https://github.com/hasaneyldrm/exercises-dataset/blob/main/data/exercises.json). Second, it initializes a Fuse.js search index with targeted configuration options. Third, it binds the search interface to real-time user input, querying the index and rendering results without server round-trips.

This design works efficiently because the dataset is static and relatively small. By processing everything in the browser, you eliminate backend latency and reduce infrastructure complexity.

Step-by-Step Implementation

Load the Dataset

Begin by fetching the exercise data from the repository's main data file. The [data/exercises.json](https://github.com/hasaneyldrm/exercises-dataset/blob/main/data/exercises.json) file contains an array of exercise objects, each with properties like name, description, and aliases.

According to the repository structure, this file follows the schema defined in [data/exercises.schema.json](https://github.com/hasaneyldrm/exercises-dataset/blob/main/data/exercises.schema.json), ensuring consistent field names across entries.

const resp = await fetch('data/exercises.json');
const exercises = await resp.json();

Configure the Search Index

Initialize Fuse.js with specific options tuned for exercise name matching. Set the keys array to prioritize the name field while including aliases as secondary matches. A threshold of 0.4 provides optimal tolerance for typos without returning irrelevant results.

const fuse = new Fuse(exercises, {
  keys: [
    { name: 'name', weight: 0.7 },
    { name: 'aliases', weight: 0.3 }
  ],
  threshold: 0.4,
  includeScore: true
});

The weight values ensure exact name matches rank higher than alias matches, while includeScore enables relevance-based sorting.

Handle User Input

Bind an input event listener to capture search queries. Pass each query to fuse.search() and map the results to your UI. The method returns an array of objects containing the matched item and a match score.

const input = document.getElementById('search');
const list = document.getElementById('results');

input.addEventListener('input', () => {
  const query = input.value.trim();
  if (!query) {
    list.innerHTML = '';
    return;
  }
  
  const matches = fuse.search(query);
  list.innerHTML = matches.slice(0, 10)
    .map(m => `<li>${m.item.name} <small>(${m.score.toFixed(2)})</small></li>`)
    .join('');
});

Complete Implementation Example

Drop the following code into [index.html](https://github.com/hasaneyldrm/exercises-dataset/blob/main/index.html) or any page serving the dataset. This example includes the CDN import, data loading, index configuration, and UI rendering.

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/fuse.js@6.6.2"></script>
</head>
<body>
  <input id="search" placeholder="Search exercises..." />
  <ul id="results"></ul>

  <script type="module">
    // Load data from the repository's JSON file
    const resp = await fetch('data/exercises.json');
    const exercises = await resp.json();

    // Initialize fuzzy search index
    const fuse = new Fuse(exercises, {
      keys: [
        { name: 'name', weight: 0.7 },
        { name: 'aliases', weight: 0.3 }
      ],
      threshold: 0.4,
      includeScore: true
    });

    // Query handling
    const input = document.getElementById('search');
    const list = document.getElementById('results');

    input.addEventListener('input', () => {
      const query = input.value.trim();
      if (!query) {
        list.innerHTML = '';
        return;
      }
      
      const matches = fuse.search(query);
      list.innerHTML = matches.slice(0, 10)
        .map(m => `<li>${m.item.name} <small>(score: ${m.score.toFixed(2)})</small></li>`)
        .join('');
    });
  </script>
</body>
</html>

Key Configuration Parameters

Understanding the Fuse.js options ensures your fuzzy search for exercise names returns relevant results:

  • threshold: Controls match tolerance. A value of 0.4 means approximately one character in four can differ. Lower values enforce stricter matching.
  • keys: Defines searchable fields. The repository's data/exercises.json structure supports searching name and aliases fields.
  • includeScore: When true, returns match relevance scores (0.0 = perfect match, 1.0 = no match), allowing you to highlight or sort by confidence.

Summary

  • The exercises-dataset repository stores exercise definitions in data/exercises.json, making it ideal for client-side search implementations.
  • Fuse.js provides an efficient fuzzy matching engine that works directly in the browser without backend dependencies.
  • Configure the search index with weighted keys (name at 0.7, aliases at 0.3) and a threshold of 0.4 to balance typo tolerance with result accuracy.
  • Implement the search by fetching the JSON, initializing the Fuse instance, and binding the search() method to user input events.
  • This approach scales well for static datasets and can be embedded directly into index.html or similar demonstration pages.

Frequently Asked Questions

What is the best threshold setting for exercise name matching?

A threshold of 0.4 works optimally for short exercise names typical in the dataset. This setting allows the search to tolerate common typos (like "bench pres" matching "bench press") while filtering out unrelated results. For longer descriptive fields, you might increase the threshold to 0.5 or 0.6.

Can I search fields other than the exercise name?

Yes. The data/exercises.json entries contain multiple fields defined in data/exercises.schema.json. You can add description, equipment, or muscle_groups to the keys array with appropriate weights. Ensure you reference the actual property names as defined in the schema file.

No. Because the dataset is static and the entire data/exercises.json file loads into browser memory, all search processing happens client-side. This eliminates server costs and latency, though for datasets exceeding several thousand entries, you might consider server-side indexing or pagination.

How do I update the search when the dataset changes?

Since the search index builds at runtime by fetching data/exercises.json, simply updating that file in the repository automatically reflects changes on the next page load. If you cache the JSON locally, implement a cache-busting strategy by appending version parameters to the fetch URL.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →