久趣下载站

当前位置: 首页 » 游戏攻略 » 优化DevNow搜索组件及选择lunr.js的原因

优化DevNow搜索组件及选择lunr.js的原因

前言

国庆假期即将结束,这次没有出游,而是在北京看了一些房子,因为现在的房子即将到期,我们找到了一个通透度更好、采光更好的新房子。

对搜索库的横向对比

我们计划优化DevNow的搜索组件,以支持摘要和文章内容搜索。为了做出明智的决定,我们进行了fuse.js、lunr、flexsearch、minisearch、search-index、js-search和elasticlunr等搜索库的对比。

下载趋势和star排名如下图所示:


选择 Lunr 的原因

lunr.js是一个轻量级的JavaScript库,用于实现客户端全文搜索功能。它基于倒排索引,可在不依赖服务器的情况下快速检索出匹配的文档。lunr.js的核心优势在于其简单易用的API接口,仅需几行代码即可为静态网页添加强大的搜索功能。

lunr.js的工作机制主要分为两个阶段:索引构建和查询处理。首先,lunr.js会根据预定义的规则构建一个倒排索引,该索引包含了所有文档的关键字及其出现的位置信息。接着,在用户输入查询字符串后,lunr.js会根据索引快速找到包含这些关键字的文档,并按照相关度排序返回结果。

为了提高搜索效率和准确性,lunr.js还支持多种高级特性,比如同义词扩展、短语匹配以及布尔运算等。这些功能使得开发者能够根据具体应用场景定制搜索算法,提供更加个性化的用户体验。此外,lunr.js还允许用户自定义权重分配策略,以更好地反映文档的重要程度。

DevNow 中接入 Lunr

我们将使用Astro的API端点进行构建。在静态生成的站点中,自定义端点在构建时被调用以生成静态文件。如果选择启用SSR模式,自定义端点将成为根据请求调用的实时服务器端点。静态和SSR端点的定义类似,但SSR端点支持附加额外功能。

构造索引文件

// search-index.json.js
import { latestPosts } from '@/utils/content';
import lunr from 'lunr';
import MarkdownIt from 'markdown-it';
const stemmerSupport = await import('lunr-languages/lunr.stemmer.support.js');
const zhPlugin = await import('lunr-languages/lunr.zh.js');
// 初始化 stemmer 支持
stemmerSupport.default(lunr);
// 初始化中文插件
zhPlugin.default(lunr);
const md = new MarkdownIt();

let documents = latestPosts.map((post) => {
  return {
    slug: post.slug,
    title: post.data.title,
    description: post.data.desc,
    content: md.render(post.body)
  };
});
export const LunrIdx = lunr(function () {
  this.use(lunr.zh);
  this.ref('slug');
  this.field('title');
  this.field('description');
  this.field('content');
  documents.forEach((doc) => {
    this.add(doc);
  }, this);
});
export async function GET() {
  return new Response(JSON.stringify(LunrIdx), {
    status: 200,
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

构建搜索内容

// search-docs.json.js
import { latestPosts } from '@/utils/content';
import MarkdownIt from 'markdown-it';
const md = new MarkdownIt();
let documents = latestPosts.map((post) => {
  return {
    slug: post.slug,
    title: post.data.title,
    description: post.data.desc,
    content: md.render(post.body),
    category: post.data.category
  };
});
export async function GET() {
  return new Response(JSON.stringify(documents), {
    status: 200,
    headers: {
      'Content-Type': 'application/json'
    }
  });
}

重构搜索组件

// 核心代码
import { debounce } from 'lodash-es';
import lunr from 'lunr';
// 省略部分代码...

过程中遇到的问题

基于 shadcn/ui Command 搜索展示

如果自定义搜索方式和内容,需要关闭Command组件中的自动过滤功能,否则搜索结果无法正常展示。

上调函数最大持续时间

当文档较多时,构建的索引文件和内容文件可能会比较大,导致请求超时(504)。因此需要上调Vercel的超时策略,可以在项目设置中适当上调,默认为10秒。

前端搜索的优劣

以下是lunr.js和Algolia的特性对比:


特性 Lunr.js Algolia

适合使用 Lunr.js 的场景

  • 小型静态网站:适合内容较少(如几十篇文章或文档)的网站,Lunr.js可以提供不错的搜索体验,无需复杂的后端服务。
  • 不依赖外部服务:如果不希望依赖第三方服务(如Algolia),并且希望完全控制搜索的实现,Lunr.js是一个不错的选择。

适合使用 Algolia 的场景

  • 大规模数据网站:如果网站有大量内容(成千上万条数据),Algolia的后端搜索服务可以提供更好的性能和更快的响应时间。
  • 需要高级搜索功能:如果需要拼写纠错、自动补全、过滤器等功能,Algolia提供的搜索能力远超Lunr.js。

总结

基于Lunr.js的前端搜索方案适合小型、静态、预算有限且无私密数据的网站。但如果网站规模较大、搜索需求复杂或有隐私保护要求,Algolia这样专业的搜索服务会提供更好的性能和功能。

猜你喜欢
本类排行