How to Add Synonyms to MiniSearch

Adding synonym support to MiniSearch with a few lines of code.
2024-04-08
~
3 min read

MiniSearch is a great library if you need to add search capability to your website. It works well on the backend and in the browser for small to moderate-sized data sets. It supports prefix and fuzzy search, has query auto-completion and no external dependencies.

One feature that MiniSearch doesn’t have out of the box is synonyms. Your data set most likely has a few terms that don’t produce the results you users would expect. You can fix those by defining synonyms to include additional terms in the results.

MiniSearch supports complex queries, which makes searching with synonyms possible. The idea is to pass in different versions of your query with all the possible substitutions.

When building devreading.com, I needed to add synonyms for a few search terms. In a few cases, I needed to replace multiple terms with a single one (artificial intelligence → AI). That required a bit of additional complexity. In the end, I extracted the code into a npm module that you can use on top of MiniSearch if you need synonym support.

Here’s how it works.

Introducing minisearch-synonyms

minisearch-synonyms is a tiny npm package with no external dependencies. You can use it to expand your MiniSearch queries to include synonyms with just a few lines of code.

First, add it to your project alongside the minisearch package:

npm install minisearch-synonyms

Then, set up all the groups of synonymous search terms that you need:

const synonyms = new MiniSearchSynonyms([
    ['ai', 'artificial intelligence'],
    ['windows', 'win32', 'win'],
    ['macos', 'osx'],
]);

In case your synonyms aren’t static, or you’d prefer to manage them from different modules in your app, you can add and remove them dynamically like so:

synonyms.addSynonyms(['ai', 'artificial intelligence']);

/* Will remove the entire group. */
synonyms.removeSynonyms('ai');

Every time you invoke .search() on your MiniSearch instance, pass your query through MiniSearchSynonyms first. Here’s an example:


const expandedQuery = synonyms.expandQuery('the dangers of artificial intelligence');
const results = ms.search(expandedQuery);

The expandQuery function will find all search terms that have synonyms and generate alternative queries with all the variants. In the example above, the final query would look like this:

{
   combineWith: "OR",
   queries: [
     "the dangers of ai",
     "the dangers of artificial intelligence".
   ],
}

The results will include documents that match either of the queries.

Limitations

MiniSearchSynonyms only works on simple string queries. Expanding a query combination won’t work. It would be cool to extend the library to add support for processing complex AND/OR queries in the future.

Alternative Solutions

Another solution that Luca (the creator of MiniSearch) proposed to achieve synonym support involves adding an extra synonyms field to each document when building the index. These will then match during searches.

The downside of this solution is that you have to rebuild your index every time you want to add a synonym. Your index will also be a tad larger with the extra words.

The upside is that you don’t have to think about synonyms when making searches, and the result order won’t be affected by the presence of multiple queries.

Final Thoughts

minisearch-synonyms is available under the MIT licence. Feel free to use it anywhere you wish.

If you run into any issues, please let me know by opening an issue on the repo on GitHub.

Thanks to Luca Ongaro for building such a great tool!