The type of the documents being indexed.
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
]
// Create a search engine that indexes the 'title' and 'text' fields for
// full-text search. Search results will include 'title' and 'category' (plus the
// id field, that is always stored and returned)
const miniSearch = new MiniSearch({
fields: ['title', 'text'],
storeFields: ['title', 'category']
})
// Add documents to the index
miniSearch.addAll(documents)
// Search for documents:
let results = miniSearch.search('zen art motorcycle')
// => [
// { id: 2, title: 'Zen and the Art of Motorcycle Maintenance', category: 'fiction', score: 2.77258 },
// { id: 4, title: 'Zen and the Art of Archery', category: 'non-fiction', score: 1.38629 }
// ]
Configuration options
// Create a search engine that indexes the 'title' and 'text' fields of your
// documents:
const miniSearch = new MiniSearch({ fields: ['title', 'text'] })
// Your documents are assumed to include a unique 'id' field, but if you want
// to use a different field for document identification, you can set the
// 'idField' option:
const miniSearch = new MiniSearch({ idField: 'key', fields: ['title', 'text'] })
// The full set of options (here with their default value) is:
const miniSearch = new MiniSearch({
// idField: field that uniquely identifies a document
idField: 'id',
// extractField: function used to get the value of a field in a document.
// By default, it assumes the document is a flat object with field names as
// property keys and field values as string property values, but custom logic
// can be implemented by setting this option to a custom extractor function.
extractField: (document, fieldName) => document[fieldName],
// tokenize: function used to split fields into individual terms. By
// default, it is also used to tokenize search queries, unless a specific
// `tokenize` search option is supplied. When tokenizing an indexed field,
// the field name is passed as the second argument.
tokenize: (string, _fieldName) => string.split(SPACE_OR_PUNCTUATION),
// processTerm: function used to process each tokenized term before
// indexing. It can be used for stemming and normalization. Return a falsy
// value in order to discard a term. By default, it is also used to process
// search queries, unless a specific `processTerm` option is supplied as a
// search option. When processing a term from a indexed field, the field
// name is passed as the second argument.
processTerm: (term, _fieldName) => term.toLowerCase(),
// searchOptions: default search options, see the `search` method for
// details
searchOptions: undefined,
// fields: document fields to be indexed. Mandatory, but not set by default
fields: undefined
// storeFields: document fields to be stored and returned as part of the
// search results.
storeFields: []
})
Static
Readonly
wildcardThe special wildcard symbol that can be passed to MiniSearch#search to match all documents
The number of documents discarded since the most recent vacuuming
A number between 0 and 1 giving an indication about the proportion of documents that are discarded, and can therefore be cleaned up by vacuuming. A value close to 0 means that the index is relatively clean, while a higher value means that the index is relatively dirty, and vacuuming could release memory.
Total number of documents available to search
Is true
if a vacuuming operation is ongoing, false
otherwise
Number of terms in the index
Adds a document to the index
The document to be indexed
Adds all the given documents to the index
An array of documents to be indexed
Adds all the given documents to the index asynchronously.
Returns a promise that resolves (to undefined
) when the indexing is done.
This method is useful when index many documents, to avoid blocking the main
thread. The indexing is performed asynchronously and in chunks.
An array of documents to be indexed
Configuration options
Optional
chunkA promise resolving to undefined
when the indexing is done
Provide suggestions for the given search query
The result is a list of suggested modified search queries, derived from the given search query, each with a relevance score, sorted by descending score.
By default, it uses the same options used for search, except that by
default it performs prefix search on the last term of the query, and
combine terms with 'AND'
(requiring all query terms to match). Custom
options can be passed as a second argument. Defaults can be changed upon
calling the MiniSearch constructor, by passing a
autoSuggestOptions
option.
// Get suggestions for 'neuro':
miniSearch.autoSuggest('neuro')
// => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 0.46240 } ]
// Get suggestions for 'zen ar':
miniSearch.autoSuggest('zen ar')
// => [
// { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
// { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 }
// ]
// Correct spelling mistakes using fuzzy search:
miniSearch.autoSuggest('neromancer', { fuzzy: 0.2 })
// => [ { suggestion: 'neuromancer', terms: [ 'neuromancer' ], score: 1.03998 } ]
// Get suggestions for 'zen ar', but only within the 'fiction' category
// (assuming that 'category' is a stored field):
miniSearch.autoSuggest('zen ar', {
filter: (result) => result.category === 'fiction'
})
// => [
// { suggestion: 'zen archery art', terms: [ 'zen', 'archery', 'art' ], score: 1.73332 },
// { suggestion: 'zen art', terms: [ 'zen', 'art' ], score: 1.21313 }
// ]
Query string to be expanded into suggestions
Search options. The supported options and default values
are the same as for the MiniSearch#search method, except that by
default prefix search is performed on the last term in the query, and terms
are combined with 'AND'
.
A sorted array of suggestions sorted by relevance score.
Discards the document with the given ID, so it won't appear in search results
It has the same visible effect of MiniSearch.remove (both cause the document to stop appearing in searches), but a different effect on the internal data structures:
MiniSearch#remove requires passing the full document to be removed as argument, and removes it from the inverted index immediately.
MiniSearch#discard instead only needs the document ID, and works by marking the current version of the document as discarded, so it is immediately ignored by searches. This is faster and more convenient than MiniSearch#remove, but the index is not immediately modified. To take care of that, vacuuming is performed after a certain number of documents are discarded, cleaning up the index and allowing memory to be released.
After discarding a document, it is possible to re-add a new version, and only the new version will appear in searches. In other words, discarding and re-adding a document works exactly like removing and re-adding it. The MiniSearch.replace method can also be used to replace a document with a new version.
Repetite calls to this method would leave obsolete document references in the index, invisible to searches. Two mechanisms take care of cleaning up: clean up during search, and vacuuming.
Upon search, whenever a discarded ID is found (and ignored for the results), references to the discarded document are removed from the inverted index entries for the search terms. This ensures that subsequent searches for the same terms do not need to skip these obsolete references again.
In addition, vacuuming is performed automatically by default (see the
autoVacuum
field in Options) after a certain number of
documents are discarded. Vacuuming traverses all terms in the index,
cleaning up all references to discarded documents. Vacuuming can also be
triggered manually by calling MiniSearch#vacuum.
The ID of the document to be discarded
Discards the documents with the given IDs, so they won't appear in search results
It is equivalent to calling MiniSearch#discard for all the given IDs, but with the optimization of triggering at most one automatic vacuuming at the end.
Note: to remove all documents from the index, it is faster and more convenient to call MiniSearch.removeAll with no argument, instead of passing all IDs to this method.
Returns the stored fields (as configured in the storeFields
constructor
option) for the given document ID. Returns undefined
if the document is
not present in the index.
The document ID
Removes the given document from the index.
The document to remove must NOT have changed between indexing and removal, otherwise the index will be corrupted.
This method requires passing the full document to be removed (not just the ID), and immediately removes the document from the inverted index, allowing memory to be released. A convenient alternative is MiniSearch#discard, which needs only the document ID, and has the same visible effect, but delays cleaning up the index until the next vacuuming.
The document to be removed
Removes all the given documents from the index. If called with no arguments, it removes all documents from the index.
Optional
documents: readonly T[]The documents to be removed. If this argument is omitted, all documents are removed. Note that, for removing all documents, it is more efficient to call this method with no arguments than to pass all documents.
It replaces an existing document with the given updated version
It works by discarding the current version and adding the updated one, so it is functionally equivalent to calling MiniSearch#discard followed by MiniSearch#add. The ID of the updated document should be the same as the original one.
Since it uses MiniSearch#discard internally, this method relies on vacuuming to clean up obsolete document references from the index, allowing memory to be released (see MiniSearch#discard).
The updated document to replace the old version with
Search for documents matching the given search query.
The result is a list of scored document IDs matching the query, sorted by descending score, and each including data about which terms were matched and in which fields.
// Search for "zen art motorcycle" with default options: terms have to match
// exactly, and individual terms are joined with OR
miniSearch.search('zen art motorcycle')
// => [ { id: 2, score: 2.77258, match: { ... } }, { id: 4, score: 1.38629, match: { ... } } ]
// Search only in the 'title' field
miniSearch.search('zen', { fields: ['title'] })
// Boost a field
miniSearch.search('zen', { boost: { title: 2 } })
// Search for "moto" with prefix search (it will match documents
// containing terms that start with "moto" or "neuro")
miniSearch.search('moto neuro', { prefix: true })
// Search for "ismael" with fuzzy search (it will match documents containing
// terms similar to "ismael", with a maximum edit distance of 0.2 term.length
// (rounded to nearest integer)
miniSearch.search('ismael', { fuzzy: 0.2 })
// Mix of exact match, prefix search, and fuzzy search
miniSearch.search('ismael mob', {
prefix: true,
fuzzy: 0.2
})
// Perform fuzzy and prefix search depending on the search term. Here
// performing prefix and fuzzy search only on terms longer than 3 characters
miniSearch.search('ismael mob', {
prefix: term => term.length > 3
fuzzy: term => term.length > 3 ? 0.2 : null
})
// Combine search terms with AND (to match only documents that contain both
// "motorcycle" and "art")
miniSearch.search('motorcycle art', { combineWith: 'AND' })
There is also an AND_NOT combinator, that finds documents that match the first term, but do not match any of the other terms. This combinator is rarely useful with simple queries, and is meant to be used with advanced query combinations (see later for more details).
// Filter only results in the 'fiction' category (assuming that 'category'
// is a stored field)
miniSearch.search('motorcycle art', {
filter: (result) => result.category === 'fiction'
})
Searching for an empty string (assuming the default tokenizer) returns no results. Sometimes though, one needs to match all documents, like in a "wildcard" search. This is possible by passing the special value MiniSearch.wildcard as the query:
// Return search results for all documents
miniSearch.search(MiniSearch.wildcard)
Note that search options such as filter
and boostDocument
are still
applied, influencing which results are returned, and their order:
// Return search results for all documents in the 'fiction' category
miniSearch.search(MiniSearch.wildcard, {
filter: (result) => result.category === 'fiction'
})
It is possible to combine different subqueries with OR, AND, and AND_NOT, and even with different search options, by passing a query expression tree object as the first argument, instead of a string.
// Search for documents that contain "zen" and ("motorcycle" or "archery")
miniSearch.search({
combineWith: 'AND',
queries: [
'zen',
{
combineWith: 'OR',
queries: ['motorcycle', 'archery']
}
]
})
// Search for documents that contain ("apple" or "pear") but not "juice" and
// not "tree"
miniSearch.search({
combineWith: 'AND_NOT',
queries: [
{
combineWith: 'OR',
queries: ['apple', 'pear']
},
'juice',
'tree'
]
})
Each node in the expression tree can be either a string, or an object that
supports all SearchOptions fields, plus a queries
array field for
subqueries.
Note that, while this can become complicated to do by hand for complex or deeply nested queries, it provides a formalized expression tree API for external libraries that implement a parser for custom query languages.
Search query
Search options. Each option, if not given, defaults to the corresponding value of searchOptions
given to the constructor, or to the library default.
Allows serialization of the index to JSON, to possibly store it and later deserialize it with MiniSearch.loadJSON.
Normally one does not directly call this method, but rather call the
standard JavaScript JSON.stringify()
passing the MiniSearch
instance, and JavaScript will internally call this method. Upon
deserialization, one must pass to MiniSearch.loadJSON the same
options used to create the original instance that was serialized.
// Serialize the index:
let miniSearch = new MiniSearch({ fields: ['title', 'text'] })
miniSearch.addAll(documents)
const json = JSON.stringify(miniSearch)
// Later, to deserialize it:
miniSearch = MiniSearch.loadJSON(json, { fields: ['title', 'text'] })
A plain-object serializable representation of the search index.
Triggers a manual vacuuming, cleaning up references to discarded documents from the inverted index
Vacuuming is only useful for applications that use the MiniSearch#discard or MiniSearch#replace methods.
By default, vacuuming is performed automatically when needed (controlled by
the autoVacuum
field in Options), so there is usually no need to
call this method, unless one wants to make sure to perform vacuuming at a
specific moment.
Vacuuming traverses all terms in the inverted index in batches, and cleans up references to discarded documents from the posting list, allowing memory to be released.
The method takes an optional object as argument with the following keys:
batchSize
: the size of each batch (1000 by default)
batchWait
: the number of milliseconds to wait between batches (10 by
default)
On large indexes, vacuuming could have a non-negligible cost: batching avoids blocking the thread for long, diluting this cost so that it is not negatively affecting the application. Nonetheless, this method should only be called when necessary, and relying on automatic vacuuming is usually better.
It returns a promise that resolves (to undefined) when the clean up is completed. If vacuuming is already ongoing at the time this method is called, a new one is enqueued immediately after the ongoing one, and a corresponding promise is returned. However, no more than one vacuuming is enqueued on top of the ongoing one, even if this method is called more times (enqueuing multiple ones would be useless).
Configuration options for the batch size and delay. See VacuumOptions.
Static
getReturns the default value of an option. It will throw an error if no option with the given name exists.
Name of the option
The default value of the given option
// Get default tokenizer
MiniSearch.getDefault('tokenize')
// Get default term processor
MiniSearch.getDefault('processTerm')
// Unknown options will throw an error
MiniSearch.getDefault('notExisting')
// => throws 'MiniSearch: unknown option "notExisting"'
Static
loadJSONDeserializes a JSON index (serialized with JSON.stringify(miniSearch)
)
and instantiates a MiniSearch instance. It should be given the same options
originally used when serializing the index.
// If the index was serialized with:
let miniSearch = new MiniSearch({ fields: ['title', 'text'] })
miniSearch.addAll(documents)
const json = JSON.stringify(miniSearch)
// It can later be deserialized like this:
miniSearch = MiniSearch.loadJSON(json, { fields: ['title', 'text'] })
An instance of MiniSearch deserialized from the given JSON.
Static
loadJSONAsyncAsync equivalent of MiniSearch.loadJSON
This function is an alternative to MiniSearch.loadJSON that returns a promise, and loads the index in batches, leaving pauses between them to avoid blocking the main thread. It tends to be slower than the synchronous version, but does not block the main thread, so it can be a better choice when deserializing very large indexes.
A Promise that will resolve to an instance of MiniSearch deserialized from the given JSON.
MiniSearch is the main entrypoint class, implementing a full-text search engine in memory.