Skip to content

Improve client side search logic - #58

Merged
pierosavi merged 10 commits into
mainfrom
search-improvements
Oct 9, 2026
Merged

pierosavi merged 10 commits into
mainfrom
search-improvements

Conversation

@pierosavi

Copy link
Copy Markdown
Member

Closes OHF-Device-Database/backlog-items#166

Replaces the plain includes() filtering in the global search popover and the category/manufacturer filter modal and sheet with fuzzy search via fuse.js.

What we get

  • Typos and accents are tolerated: "samsnug", "xiomi", "hausgerate" find Samsung, Xiaomi and BSH Hausgeräte.
  • Word order and extra words don't matter: "aqara xiaomi" and "samsung tv" still work.
  • Results are ranked by how well they match, then by submission count.
  • Matching text is highlighted with <mark>.
  • Category names typed into the global search are turned into a category filter, in the user's language: "hue lighting" searches "hue" in Lighting, "beleuchtung hue" does the same in German. This also applies to the device results shown in the popover and to the browse page.

Trade offs

Category extraction is strict, because a wrong category silently hides results. Short words must match exactly and only one typo is forgiven, so "printer" does not become Printing (but "print" and "printing" do), and manufacturer names that contain a category word ("Philips Lighting", "Victron Energy") are narrowed to that category.

@netlify

netlify Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

✅ Deploy Preview for device-database-preview ready!

Name Link
🔨 Latest commit 375cc13
🔍 Latest deploy log https://app.netlify.com/projects/device-database-preview/deploys/6ac8f5fe4c12830008243b99
😎 Deploy Preview https://deploy-preview-58--device-database-preview.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@pierosavi

Copy link
Copy Markdown
Member Author

Side note:

While validating this with AI it suggested a dependency-free version (~300 lines of logic): split labels into words, strip accents, and compare each typed word against each label word by exact match, prefix, one edit (counting swapped letters as a single edit), or shared stem. Measured on the live manufacturer list it was noticeably more precise: swapped-letter typos like "ikae" found IKEA directly, "aeotech" returned only Aeotec instead of 32 hits, highlights were always whole words or clean prefixes, and wrong category extractions on manufacturer names dropped from 21 to 7 in German and 59 to 20 in Spanish.

I went with fuse.js anyway, since the custom code is harder to read and maintain for anyone not familiar with edit distances, and the fuse.js version is already a big improvement. To keep in mind if any of the quirks mentioned above start bothering us/the users.

Comment thread src/islands/device-search.ts
Comment thread src/utilities/search.ts
Comment thread src/utilities/search.ts
Comment on lines +106 to +133
export const highlight = (
text: string,
term: string,
): (string | TemplateResult)[] => {
const ranges = tokens(term)
.flatMap((token) => {
const { isMatch, indices } = Fuse.match(token, text, OPTIONS);
return isMatch ? (indices ?? []) : [];
})
.toSorted(([a], [b]) => a - b);

const parts: (string | TemplateResult)[] = [];
let at = 0;
for (const [start, end] of ranges) {
if (end < at) {
continue;
}
const from = Math.max(start, at);
parts.push(
text.slice(at, from),
html`<mark>${text.slice(from, end + 1)}</mark>`,
);
at = end + 1;
}
parts.push(text.slice(at));

return parts;
};

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image

highlighting results are weird when term is a single letter 😅

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is connected to the minMatchCharLength issue but I updated the highlighter logic to stop on first occurrence or longest segment of typo tolerance check

Comment thread src/utilities/search.ts Outdated
Comment on lines +10 to +11
// avoids single-character highlight fragments on fuzzy matches
minMatchCharLength: 2,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably be customizable per search-site, as a one character search does seem legitimate with a small set of options (e.g. categories)

Image

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed minMatchCharLength. I wanted to use it to tidy highlights but it also filtered out results

Comment thread src/utilities/search.ts
@PhilipTrauner

Copy link
Copy Markdown
Collaborator

the search box already feels much nicer to use 🙌
some nits, but overall this is great!

@pierosavi
pierosavi merged commit 8a77ef9 into main Oct 9, 2026
7 checks passed
@pierosavi
pierosavi deleted the search-improvements branch October 9, 2026 15:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

client-side search improvements

2 participants