即输即搜,支持拼写容错、分面筛选和结果排序——运行在 Algolia 全球网络上。通过一次 API 调用即可索引记录,再引入 React/Vue/JS UI 库即可完成。全球任意位置查询延迟低于 100ms。
tsvector / tsquery)——需求简单且已在使用 Postgres 时的轻量方案。Algolia 最适合的场景:独立 SaaS 产品,希望用几个小时的工作打造出 Linear 或 Stripe 文档那样的搜索体验。
前往 algolia.com ↗ 注册账号。Build 套餐(免费)包含 10K 条记录 + 每月 10K 次请求——对于小型应用或文档站点来说已经足够。
Dashboard 中可以看到你的 Application ID 和四个 API 密钥:
ALGOLIA_APP_ID=ABCD1234
ALGOLIA_ADMIN_KEY=xxxxxxxxxxxxxxxxxxxxxxxx # backend only
ALGOLIA_SEARCH_KEY=xxxxxxxxxxxxxxxxxxxxxxxx # safe in browser
NEXT_PUBLIC_ALGOLIA_SEARCH_KEY=xxxxxxxxxxxxxx # ditto, for Next.js
Algolia 中的"索引"是一组记录的集合。每条记录是一个 JSON 对象——任何你希望出现在搜索结果中的内容都可以作为记录。
对于博客:每篇文章是一条记录。对于电商:每个商品是一条记录。对于 SaaS:可能有一个用于文档的索引、一个用于用户的索引、一个用于标签的索引。
每条记录需要一个 objectID(你的唯一标识符——数据库主键即可)。Algolia 会自动索引其他所有顶层字段。
{
"objectID": "post-123",
"title": "How to deploy to Vercel",
"body": "First, install the CLI...",
"author": "Jane",
"tags": ["deploy", "vercel"],
"published_at": 1714521600
}
npm install algoliasearch
import { algoliasearch } from "algoliasearch";
const client = algoliasearch(
process.env.ALGOLIA_APP_ID,
process.env.ALGOLIA_ADMIN_KEY // admin key, BACKEND ONLY
);
// Save / replace a single record
await client.saveObject({
indexName: "posts",
body: {
objectID: "post-123",
title: "How to deploy to Vercel",
body: "First, install the CLI...",
tags: ["deploy", "vercel"],
},
});
// Bulk replace (faster for initial import)
await client.saveObjects({
indexName: "posts",
objects: arrayOfPosts,
});
可以按计划定期执行(每隔 N 分钟),或在每次涉及可索引内容的数据库写入时触发。JS API 客户端文档 ↗。
进入 Dashboard → 你的索引 → Configuration。最重要的两项设置:
title 排在第一位,body 排在第二位。文档 ↗。popularity 或 published_at)来决定同分情况下的排序。排序规则文档 ↗。也可以通过 API 配置:
await client.setSettings({
indexName: "posts",
indexSettings: {
searchableAttributes: ["title", "body", "tags"],
customRanking: ["desc(published_at)"],
},
});
import { algoliasearch } from "algoliasearch";
const client = algoliasearch(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY // search-only key; safe in browser
);
const { hits } = await client.searchSingleIndex({
indexName: "posts",
searchParams: { query: "vercel deploy" },
});
请使用只读搜索密钥,而非 Admin 密钥。搜索密钥仅限读取操作,可以安全地打包进前端 JS 中。
要实现即输即搜效果,无需自己从头开发。Algolia 的 InstantSearch 库已经处理好防抖、分面筛选、分页,并负责渲染结果。
React:
npm install algoliasearch react-instantsearch
import { liteClient } from "algoliasearch/lite";
import { InstantSearch, SearchBox, Hits } from "react-instantsearch";
const searchClient = liteClient(
process.env.NEXT_PUBLIC_ALGOLIA_APP_ID,
process.env.NEXT_PUBLIC_ALGOLIA_SEARCH_KEY
);
export function Search() {
return (
<InstantSearch searchClient={searchClient} indexName="posts">
<SearchBox />
<Hits hitComponent={({ hit }) => <div>{hit.title}</div>} />
</InstantSearch>
);
}
其他框架版本:Vue InstantSearch ↗、原生 JS InstantSearch ↗、Docusaurus DocSearch ↗(开源文档免费使用)。
若需要"按分类 / 标签 / 价格区间筛选结果",需先将属性声明为分面字段:
await client.setSettings({
indexName: "posts",
indexSettings: {
attributesForFaceting: ["tags", "author", "filterOnly(published)"],
},
});
然后在 InstantSearch 中使用:
import { RefinementList, HierarchicalMenu } from "react-instantsearch";
<RefinementList attribute="tags" />
<RefinementList attribute="author" />
这些组件会自动渲染复选框并应用筛选条件。RefinementList 文档 ↗。
你可能不希望手动推送每一条记录。常见的两种方案:
saveObject。简单直接,但会增加响应延迟。针对 Postgres,Algolia 提供了一个 Postgres 连接器 ↗,可自动处理同步(付费功能)。
author_bio 搜索,就不要添加它,否则会稀释 title/body 的匹配权重。client.deleteObject()。这一步容易遗漏,会导致"我明明删了那篇文章,搜索结果里还能看到"的问题。如果费用难以承受:
tsvector + GIN 索引免费且够用。Meilisearch 和 Typesense 都提供兼容 Algolia 的 API,因此 InstantSearch UI 组件只需更换客户端即可直接使用。