Top Related Projects
JS Search is an efficient, client-side search library for JavaScript and JSON objects
Next-Generation full text search library for Browser and Node.js
Lightweight fuzzy-search, in JavaScript
A bit like Solr, but much smaller and not as bright
A persistent, network resilient, full text search library for the browser and Node.js
Based on lunr.js, but more flexible and customized.
Quick Overview
MiniSearch is a lightweight, in-memory full-text search engine written in JavaScript. It's designed to be easy to use and integrate into both browser and Node.js environments, offering a simple yet powerful API for indexing and searching documents.
Pros
- Lightweight and fast, with minimal dependencies
- Supports multiple search strategies, including prefix search and fuzzy matching
- Customizable tokenization and term processing
- Works in both browser and Node.js environments
Cons
- Limited to in-memory storage, not suitable for very large datasets
- Lacks some advanced features found in larger search engines
- May require additional effort for complex search scenarios
Code Examples
- Creating an index and adding documents:
import MiniSearch from 'minisearch'
const documents = [
{ id: 1, title: 'Moby Dick', text: 'Call me Ishmael. Some years ago...' },
{ id: 2, title: 'Pride and Prejudice', text: 'It is a truth universally acknowledged...' }
]
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title']
})
miniSearch.addAll(documents)
- Performing a search:
const results = miniSearch.search('pride prejudice')
console.log(results)
// [{ id: 2, score: 2.77, title: 'Pride and Prejudice' }]
- Using fuzzy search:
const fuzzyResults = miniSearch.search('prde', { fuzzy: 0.2 })
console.log(fuzzyResults)
// [{ id: 2, score: 1.41, title: 'Pride and Prejudice' }]
Getting Started
To use MiniSearch in your project, first install it via npm:
npm install minisearch
Then, in your JavaScript file:
import MiniSearch from 'minisearch'
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title']
})
// Add documents to the index
miniSearch.addAll([
{ id: 1, title: 'Document 1', text: 'This is the first document' },
{ id: 2, title: 'Document 2', text: 'This is the second document' }
])
// Perform a search
const results = miniSearch.search('first document')
console.log(results)
This basic setup allows you to create an index, add documents, and perform searches. You can further customize the search behavior and indexing options based on your specific needs.
Competitor Comparisons
JS Search is an efficient, client-side search library for JavaScript and JSON objects
Pros of js-search
- Supports multiple search strategies (prefix, substring, exact match)
- Allows custom tokenization and stemming
- Provides a more flexible API for advanced use cases
Cons of js-search
- Larger bundle size compared to minisearch
- Less actively maintained (last update was in 2021)
- Slower indexing and search performance for large datasets
Code Comparison
minisearch:
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title', 'category']
})
miniSearch.addAll(documents)
const results = miniSearch.search('query')
js-search:
const search = new JsSearch.Search('id')
search.addIndex('title')
search.addIndex('text')
search.addDocuments(documents)
const results = search.search('query')
Both libraries offer simple APIs for basic search functionality, but js-search provides more options for customization at the cost of a slightly more verbose setup. minisearch has a more concise API and better performance for most use cases.
Next-Generation full text search library for Browser and Node.js
Pros of FlexSearch
- Higher performance and faster search capabilities
- More flexible and customizable, with support for multiple languages and complex search scenarios
- Smaller bundle size, making it more lightweight for client-side applications
Cons of FlexSearch
- Steeper learning curve due to its extensive configuration options
- Less straightforward implementation for simple use cases
- May require more setup and configuration for basic search functionality
Code Comparison
MiniSearch basic usage:
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title']
})
miniSearch.addAll(documents)
const results = miniSearch.search('query')
FlexSearch basic usage:
const index = new FlexSearch.Index({
preset: "score",
doc: {
id: "id",
field: ["title", "content"]
}
})
index.add(documents)
const results = index.search("query")
Both libraries offer simple APIs for basic search functionality, but FlexSearch provides more advanced options for customization and performance optimization. MiniSearch's API is more straightforward for simple use cases, while FlexSearch offers greater flexibility at the cost of increased complexity.
Lightweight fuzzy-search, in JavaScript
Pros of Fuse
- More flexible scoring and ranking options
- Supports fuzzy searching with customizable threshold
- Wider browser compatibility, including older versions
Cons of Fuse
- Slower performance for large datasets
- Higher memory usage
- Less suitable for real-time search suggestions
Code Comparison
Fuse:
const fuse = new Fuse(list, {
keys: ['title', 'author.firstName']
})
const result = fuse.search('old man')
MiniSearch:
const miniSearch = new MiniSearch({
fields: ['title', 'author']
})
miniSearch.addAll(documents)
const results = miniSearch.search('old man')
Key Differences
- Fuse focuses on flexibility and ease of use, while MiniSearch prioritizes performance and memory efficiency
- MiniSearch offers built-in prefix search and auto-suggestions, which Fuse lacks
- Fuse provides more granular control over search parameters and scoring
Use Cases
- Choose Fuse for smaller datasets or when fuzzy searching is crucial
- Opt for MiniSearch when dealing with large datasets or requiring real-time search functionality
Community and Maintenance
- Both projects are actively maintained and have strong community support
- Fuse has a larger user base and more frequent updates
- MiniSearch offers more detailed documentation and examples
A bit like Solr, but much smaller and not as bright
Pros of Lunr.js
- More mature project with a larger community and ecosystem
- Supports stemming and stop word removal out of the box
- Offers more advanced query syntax for complex searches
Cons of Lunr.js
- Larger file size, which may impact load times for client-side applications
- Generally slower indexing and search performance compared to MiniSearch
- Less flexible configuration options for fine-tuning search behavior
Code Comparison
MiniSearch:
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title']
})
miniSearch.addAll(documents)
const results = miniSearch.search('query')
Lunr.js:
const idx = lunr(function () {
this.field('title')
this.field('text')
this.ref('id')
documents.forEach(doc => this.add(doc))
})
const results = idx.search('query')
Both libraries offer simple APIs for creating indexes and performing searches. MiniSearch provides a more straightforward approach to adding documents and configuring fields, while Lunr.js uses a function-based configuration style. The core functionality is similar, but the syntax and method names differ slightly between the two libraries.
A persistent, network resilient, full text search library for the browser and Node.js
Pros of search-index
- Supports persistent storage and can handle larger datasets
- Offers more advanced querying capabilities, including faceted search
- Provides real-time indexing and search updates
Cons of search-index
- More complex setup and configuration compared to MiniSearch
- Larger package size and potentially higher memory usage
- Steeper learning curve for beginners
Code Comparison
MiniSearch:
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title', 'category']
})
miniSearch.addAll(documents)
const results = miniSearch.search('query')
search-index:
const si = require('search-index')
const { index, search } = await si()
await index(documents)
const results = await search({
AND: ['query']
})
Summary
MiniSearch is a lightweight, in-memory search engine suitable for smaller datasets and client-side applications. search-index offers more advanced features and scalability for larger datasets, but with increased complexity. Choose MiniSearch for simplicity and small to medium-sized projects, and search-index for more robust, server-side search capabilities.
Based on lunr.js, but more flexible and customized.
Pros of elasticlunr.js
- More advanced search features, including fuzzy search and field-specific boosting
- Better support for indexing and searching multiple fields
- More mature project with a longer development history
Cons of elasticlunr.js
- Larger file size and potentially slower performance compared to MiniSearch
- Less active development and maintenance in recent years
- More complex API and configuration options
Code Comparison
MiniSearch:
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title', 'category']
})
miniSearch.addAll(documents)
const results = miniSearch.search('query')
elasticlunr.js:
const index = elasticlunr(function () {
this.addField('title')
this.addField('text')
this.setRef('id')
})
documents.forEach(doc => index.addDoc(doc))
const results = index.search('query')
Both libraries offer simple APIs for indexing and searching documents, but elasticlunr.js requires more explicit configuration of fields and references. MiniSearch provides a more concise approach to adding documents and performing searches, while elasticlunr.js offers more granular control over the indexing process.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual CopilotREADME
MiniSearch
MiniSearch
is a tiny but powerful in-memory fulltext search engine written in
JavaScript. It is respectful of resources, and it can comfortably run both in
Node and in the browser.
Try out the demo application.
Find the complete documentation and API reference
here,
and more background about MiniSearch
, including a comparison with other
similar libraries, in this blog
post.
MiniSearch
follows semantic versioning,
and documents releases and changes in the
changelog.
Use case
MiniSearch
addresses use cases where full-text search features are needed
(e.g. prefix search, fuzzy search, ranking, boosting of fieldsâ¦), but the data
to be indexed can fit locally in the process memory. While you won't index the
whole Internet with it, there are surprisingly many use cases that are served
well by MiniSearch
. By storing the index in local memory, MiniSearch
can
work offline, and can process queries quickly, without network latency.
A prominent use-case is real time search "as you type" in web and mobile applications, where keeping the index on the client enables fast and reactive UIs, removing the need to make requests to a search server.
Features
-
Memory-efficient index, designed to support memory-constrained use cases like mobile browsers.
-
Exact match, prefix search, fuzzy match, field boosting.
-
Auto-suggestion engine, for auto-completion of search queries.
-
Modern search result ranking algorithm.
-
Documents can be added and removed from the index at any time.
-
Zero external dependencies.
MiniSearch
strives to expose a simple API that provides the building blocks to
build custom solutions, while keeping a small and well tested codebase.
Installation
With npm
:
npm install minisearch
With yarn
:
yarn add minisearch
Then require
or import
it in your project:
// If you are using import:
import MiniSearch from 'minisearch'
// If you are using require:
const MiniSearch = require('minisearch')
Alternatively, if you prefer to use a <script>
tag, you can require MiniSearch
from a CDN:
<script src="https://cdn.jsdelivr.net/npm/minisearch@7.1.0/dist/umd/index.min.js"></script>
In this case, MiniSearch
will appear as a global variable in your project.
Finally, if you want to manually build the library, clone the repository and run
yarn build
(or yarn build-minified
for a minified version + source maps).
The compiled source will be created in the dist
folder (UMD, ES6 and ES2015
module versions are provided).
Usage
Basic usage
// A collection of documents for our examples
const documents = [
{
id: 1,
title: 'Moby Dick',
text: 'Call me Ishmael. Some years ago...',
category: 'fiction'
},
{
id: 2,
title: 'Zen and the Art of Motorcycle Maintenance',
text: 'I can see by my watch...',
category: 'fiction'
},
{
id: 3,
title: 'Neuromancer',
text: 'The sky above the port was...',
category: 'fiction'
},
{
id: 4,
title: 'Zen and the Art of Archery',
text: 'At first sight it must seem...',
category: 'non-fiction'
},
// ...and more
]
let miniSearch = new MiniSearch({
fields: ['title', 'text'], // fields to index for full-text search
storeFields: ['title', 'category'] // fields to return with search results
})
// Index all documents
miniSearch.addAll(documents)
// Search with default options
let results = miniSearch.search('zen art motorcycle')
// => [
// { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', category: 'fiction', score: 2.77258, match: { ... } },
// { id: 4, title: 'Zen and the Art of Archery', category: 'non-fiction', score: 1.38629, match: { ... } }
// ]
Search options
MiniSearch
supports several options for more advanced search behavior:
// Search only specific fields
miniSearch.search('zen', { fields: ['title'] })
// Boost some fields (here "title")
miniSearch.search('zen', { boost: { title: 2 } })
// Prefix search (so that 'moto' will match 'motorcycle')
miniSearch.search('moto', { prefix: true })
// Search within a specific category
miniSearch.search('zen', {
filter: (result) => result.category === 'fiction'
})
// Fuzzy search, in this example, with a max edit distance of 0.2 * term length,
// rounded to nearest integer. The mispelled 'ismael' will match 'ishmael'.
miniSearch.search('ismael', { fuzzy: 0.2 })
// You can set the default search options upon initialization
miniSearch = new MiniSearch({
fields: ['title', 'text'],
searchOptions: {
boost: { title: 2 },
fuzzy: 0.2
}
})
miniSearch.addAll(documents)
// It will now by default perform fuzzy search and boost "title":
miniSearch.search('zen and motorcycles')
Auto suggestions
MiniSearch
can suggest search queries given an incomplete query:
miniSearch.autoSuggest('zen ar')
// => [ { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
// { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 } ]
The autoSuggest
method takes the same options as the search
method, so you
can get suggestions for misspelled words using fuzzy search:
miniSearch.autoSuggest('neromancer', { fuzzy: 0.2 })
// => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 1.03998 } ]
Suggestions are ranked by the relevance of the documents that would be returned by that search.
Sometimes, you might need to filter auto suggestions to, say, only a specific
category. You can do so by providing a filter
option:
miniSearch.autoSuggest('zen ar', {
filter: (result) => result.category === 'fiction'
})
// => [ { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 } ]
Field extraction
By default, documents are assumed to be plain key-value objects with field names
as keys and field values as simple values. In order to support custom field
extraction logic (for example for nested fields, or non-string field values that
need processing before tokenization), a custom field extractor function can be
passed as the extractField
option:
// Assuming that our documents look like:
const documents = [
{ id: 1, title: 'Moby Dick', author: { name: 'Herman Melville' }, pubDate: new Date(1851, 9, 18) },
{ id: 2, title: 'Zen and the Art of Motorcycle Maintenance', author: { name: 'Robert Pirsig' }, pubDate: new Date(1974, 3, 1) },
{ id: 3, title: 'Neuromancer', author: { name: 'William Gibson' }, pubDate: new Date(1984, 6, 1) },
{ id: 4, title: 'Zen in the Art of Archery', author: { name: 'Eugen Herrigel' }, pubDate: new Date(1948, 0, 1) },
// ...and more
]
// We can support nested fields (author.name) and date fields (pubDate) with a
// custom `extractField` function:
let miniSearch = new MiniSearch({
fields: ['title', 'author.name', 'pubYear'],
extractField: (document, fieldName) => {
// If field name is 'pubYear', extract just the year from 'pubDate'
if (fieldName === 'pubYear') {
const pubDate = document['pubDate']
return pubDate && pubDate.getFullYear().toString()
}
// Access nested fields
return fieldName.split('.').reduce((doc, key) => doc && doc[key], document)
}
})
The default field extractor can be obtained by calling
MiniSearch.getDefault('extractField')
.
Tokenization
By default, documents are tokenized by splitting on Unicode space or punctuation
characters. The tokenization logic can be easily changed by passing a custom
tokenizer function as the tokenize
option:
// Tokenize splitting by hyphen
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
tokenize: (string, _fieldName) => string.split('-')
})
Upon search, the same tokenization is used by default, but it is possible to
pass a tokenize
search option in case a different search-time tokenization is
necessary:
// Tokenize splitting by hyphen
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
tokenize: (string) => string.split('-'), // indexing tokenizer
searchOptions: {
tokenize: (string) => string.split(/[\s-]+/) // search query tokenizer
}
})
The default tokenizer can be obtained by calling
MiniSearch.getDefault('tokenize')
.
Term processing
Terms are downcased by default. No stemming is performed, and no stop-word list
is applied. To customize how the terms are processed upon indexing, for example
to normalize them, filter them, or to apply stemming, the processTerm
option
can be used. The processTerm
function should return the processed term as a
string, or a falsy value if the term should be discarded:
let stopWords = new Set(['and', 'or', 'to', 'in', 'a', 'the', /* ...and more */ ])
// Perform custom term processing (here discarding stop words and downcasing)
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
processTerm: (term, _fieldName) =>
stopWords.has(term) ? null : term.toLowerCase()
})
By default, the same processing is applied to search queries. In order to apply
a different processing to search queries, supply a processTerm
search option:
let miniSearch = new MiniSearch({
fields: ['title', 'text'],
processTerm: (term) =>
stopWords.has(term) ? null : term.toLowerCase(), // index term processing
searchOptions: {
processTerm: (term) => term.toLowerCase() // search query processing
}
})
The default term processor can be obtained by calling
MiniSearch.getDefault('processTerm')
.
API Documentation
Refer to the API documentation for details about configuration options and methods.
Browser and Node compatibility
MiniSearch
supports all browsers and NodeJS versions implementing the ES6
(ES2015) JavaScript standard. That includes all modern browsers and NodeJS
versions.
Contributing
Contributions to MiniSearch
are welcome. Please read the contributions
guidelines.
Reading the design
document is
also useful to understand the project goals and the technical implementation.
Top Related Projects
JS Search is an efficient, client-side search library for JavaScript and JSON objects
Next-Generation full text search library for Browser and Node.js
Lightweight fuzzy-search, in JavaScript
A bit like Solr, but much smaller and not as bright
A persistent, network resilient, full text search library for the browser and Node.js
Based on lunr.js, but more flexible and customized.
Convert designs to code with AI
Introducing Visual Copilot: A new AI model to turn Figma designs to high quality code using your components.
Try Visual Copilot