Searches the index using the passed query.
Queries should be a string, multiple words are allowed and will lead to an AND based query, e.g. idx.search('foo bar')
will run a search for documents containing both 'foo' and 'bar'.
All query tokens are passed through the same pipeline that document tokens are passed through, so any language processing involved will be run on every query term.
Each query term is expanded, so that the term 'he' might be expanded to 'hello' and 'help' if those terms were already included in the index.
Matching documents are returned as an array of objects, each object contains the matching document ref, as set for this index, and the similarity score for this document against the query.
Source
lunr.Index.prototype.search = function (query) {
var queryTokens = this.pipeline.run(this.tokenizerFn(query)),
queryVector = new lunr.Vector,
documentSets = [],
fieldBoosts = this._fields.reduce(function (memo, f) { return memo + f.boost }, 0)
var hasSomeToken = queryTokens.some(function (token) {
return this.tokenStore.has(token)
}, this)
if (!hasSomeToken) return []
queryTokens
.forEach(function (token, i, tokens) {
var tf = 1 / tokens.length * this._fields.length * fieldBoosts,
self = this
var set = this.tokenStore.expand(token).reduce(function (memo, key) {
var pos = self.corpusTokens.indexOf(key),
idf = self.idf(key),
similarityBoost = 1,
set = new lunr.SortedSet
// if the expanded key is not an exact match to the token then
// penalise the score for this key by how different the key is
// to the token.
if (key !== token) {
var diff = Math.max(3, key.length - token.length)
similarityBoost = 1 / Math.log(diff)
}
// calculate the query tf-idf score for this token
// applying an similarityBoost to ensure exact matches
// these rank higher than expanded terms
if (pos > -1) queryVector.insert(pos, tf * idf * similarityBoost)
// add all the documents that have this key into a set
// ensuring that the type of key is preserved
var matchingDocuments = self.tokenStore.get(key),
refs = Object.keys(matchingDocuments),
refsLen = refs.length
for (var i = 0; i < refsLen; i++) {
set.add(matchingDocuments[refs[i]].ref)
}
return memo.union(set)
}, new lunr.SortedSet)
documentSets.push(set)
}, this)
var documentSet = documentSets.reduce(function (memo, set) {
return memo.intersect(set)
})
return documentSet
.map(function (ref) {
return { ref: ref, score: queryVector.similarity(this.documentVector(ref)) }
}, this)
.sort(function (a, b) {
return b.score - a.score
})
}