1
0
mirror of synced 2025-12-22 03:16:52 -05:00
Files
docs/lib/search/lunr-search.js
Kevin Heis 57e1a1b9c1 End Lunr AB test (#19155)
* Revert "Start an AB test with Lunr search results as treatment (#18993)"

This reverts commit 3d621ba715.

* Update lunr-search.js
2021-05-06 18:04:28 +00:00

91 lines
2.8 KiB
JavaScript

const path = require('path')
const lunr = require('lunr')
require('lunr-languages/lunr.stemmer.support')(lunr)
require('lunr-languages/tinyseg')(lunr)
require('lunr-languages/lunr.ja')(lunr)
require('lunr-languages/lunr.es')(lunr)
require('lunr-languages/lunr.pt')(lunr)
require('lunr-languages/lunr.de')(lunr)
const { get } = require('lodash')
const readFileAsync = require('../readfile-async')
const { namePrefix } = require('./config')
const { decompress } = require('./compress')
const LUNR_DIR = './indexes'
const lunrIndexes = new Map()
const lunrRecords = new Map()
module.exports = async function loadLunrResults ({ version, language, query, limit }) {
const indexName = `${namePrefix}-${version}-${language}`
if (!lunrIndexes.has(indexName) || !lunrRecords.has(indexName)) {
lunrIndexes.set(indexName, await loadLunrIndex(indexName))
lunrRecords.set(indexName, await loadLunrRecords(indexName))
}
const results = lunrIndexes.get(indexName)
.search(query)
.slice(0, limit)
.map((result) => {
const record = lunrRecords.get(indexName)[result.ref]
return {
url: result.ref,
breadcrumbs: field(result, record, 'breadcrumbs'),
heading: field(result, record, 'heading'),
title: field(result, record, 'title'),
content: field(result, record, 'content'),
// don't highlight the topics array
topics: record.topics
}
})
return results
}
async function loadLunrIndex (indexName) {
const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}.json.br`)
// Do not set to 'utf8' on file reads
return readFileAsync(filePath)
.then(decompress)
.then(JSON.parse)
.then(lunr.Index.load)
}
async function loadLunrRecords (indexName) {
const filePath = path.posix.join(__dirname, LUNR_DIR, `${indexName}-records.json.br`)
// Do not set to 'utf8' on file reads
return readFileAsync(filePath)
.then(decompress)
.then(JSON.parse)
}
// Highlight a match within an attribute field
function field (result, record, name) {
const text = record[name]
if (!text) return text
// First, get a list of all the positions of the matching tokens
const positions = Object.values(result.matchData.metadata)
.map(fields => get(fields, [name, 'position']))
.filter(Boolean)
.flat()
.sort((a, b) => a[0] - b[0])
.map(([start, length]) => [start, start + length])
.map(([start, end], i, a) => [i && a[i - 1][1], start, end])
// If this field has no token matches, no highlighting
if (!positions.length) return text
// Highlight the text
return positions
.map(([prev, start, end], i) => [
text.slice(prev, start),
mark(text.slice(start, end)),
i === positions.length - 1 && text.slice(end)
])
.flat()
.filter(Boolean)
.join('')
}
function mark (text) {
return `<mark>${text}</mark>`
}