RavelloH's Blog

LOADing...



使用Meilisearch实现全站搜索

using-meilisearch-to-achieve-sitewide-search

技术/设计 6002

search


简介

Meilisearch 是一个开源的轻量级全文搜索引擎,支持中文分词、模糊搜索、拼写纠错等。

与之相似的竞品有:Elasticsearch、Typesense、Algolia等。其中,Elasticsearch 是老牌搜索服务,但是运行起来太笨重了,除非数据量很大,否则其余轻量级的实现要更好。

后两者 Typesense、Algolia 和本文的主角 Meilisearch 都是更轻量级别的存在,但是 Algolia 不开源,只能使用他们的云服务,而我不太喜欢被平台给局限住,所以也放弃了。

Typesense 和 Meilisearch 都是开源的同时也都提供云服务。很可惜,前者的文档集存在 RAM 里,后者则主要放在磁盘里,虽然性能上确实是前者更出色,但是很明显 RAM 可比存储空间贵的多。

另外,Meilisearch 的社区开发环境也更好。截至本文发布,Meilisearch 有52K stars, 296 watching, 2.1K forks, 201 contributors,而 Typesense 只有23.6K stars, 132 watching, 773 forks, 46 contributors

(另外,Meilisearch还是用我喜欢的Rust写的)

因此,本文主要讲 Meilisearch 的部署与使用。另附我找到的几个比较资料,或许能帮你选择合适自己的服务。

部署

Meilisearch 支持下载二进制和 Docker 部署两种方式。

二进制

另外,Meilisearch 还支持一键脚本安装:

curl -L https://install.meilisearch.com | sh

或者手动下载二进制文件:

Releases · meilisearch/meilisearch

下载完后,使用以下方式启动:

./meilisearch --master-key=YourMasterKey

其中,MasterKey 算是一个管理员密码,可以是 16 位以上的 UTF-8 字符串。获取 API 密钥需要通过此Key,访问管理后台也需要。

也可以自定义端口,默认是7700。

./meilisearch --http-addr '0.0.0.0:7700'

Docker

docker run -it --rm \
  -p 7700:7700 \
  getmeili/meilisearch \
  meilisearch --master-key='YourMasterKey' --http-addr '0.0.0.0:7700'

使用

使用也很简单,分4步,分别是查看当前的API Token、设置要搜索的数据类型、写入数据、搜索。 下面会用到很多curl,windows建议用Postman,直接粘贴进去就能解析。

查看当前API Token

curl -X GET 'https://Your_Meili_URL/keys' -H 'Authorization: YourMasterToken'

获取到的结果是:

{
    "results": [
        {
            "name": "Default Search API Key",
            "description": "Use it to search from the frontend",
            "key": "xxxxxxxx",
            "uid": "xxxxxxxx",
            "actions": [
                "search"
            ],
            "indexes": [
                "*"
            ],
            "expiresAt": null,
            "createdAt": "2025-06-25T11:08:45.729263258Z",
            "updatedAt": "2025-06-25T11:08:45.729263258Z"
        },
        {
            "name": "Default Admin API Key",
            "description": "Use it for anything that is not a search operation. Caution! Do not expose it on a public frontend",
            "key": "xxxxxxxx",
            "uid": "xxxxxxxx",
            "actions": [
                "*"
            ],
            "indexes": [
                "*"
            ],
            "expiresAt": null,
            "createdAt": "2025-06-25T11:08:45.726891008Z",
            "updatedAt": "2025-06-25T11:08:45.726891008Z"
        }
    ],
    "offset": 0,
    "limit": 20,
    "total": 2
}

简单来说会给你两个 Token,存在key字段里,上面是搜索用的,下面是管理用的。

设置数据类型

如果你想索引这样的一个东西:

model Post {
  id           Int      @id @default(autoincrement())
  title        String   @db.VarChar(50)
  content      String   @db.VarChar(200)
  userUid      Int?
  createdAt    DateTime @default(now())
  User         User?    @relation(fields: [userUid], references: [uid])
}

它包含一个主键:id,两个你想索引的东西:title,content。 那么,你首先应该创建这个项:

(这里的API Token既可以用MasterKey,也能用Default Admin API Key)

curl -X POST 'https://Your_Meili_URL/indexes' \
  -H 'Authorization: Bearer API_TOKEN' \
  -H 'Content-Type: application/json' \
  --data '{
    "uid": "posts",
    "primaryKey": "id"
}'

结果:

{

    "taskUid": 0,
    "indexUid": "posts",
    "status": "enqueued",
    "type": "indexCreation",
    "enqueuedAt": "2025-06-25T12:37:59.414437837Z"

}

然后,设置可被搜索的字段:

curl -X PUT 'https://Your_Meili_URL/indexes/posts/settings/searchable-attributes' \
  -H 'Authorization: Bearer API_KEY' \
  -H 'Content-Type: application/json' \
  --data '[
    "title", "content"
  ]'

你也可以设置一些可以用于排序的字段:

curl -X PUT 'https://Your_Meili_URL/indexes/posts/settings/sortable-attributes' \
  -H 'Authorization: Bearer API_KEY' \
  -H 'Content-Type: application/json' \
  --data '["createdAt"]'

类似的,设置用于过滤的字段:

curl -X PUT 'https://Your_Meili_URL/indexes/posts/settings/filterable-attributes' \
  -H 'Authorization: Bearer API_KEY' \
  -H 'Content-Type: application/json' \
  --data '["userUid"]'

写入数据

现在就可以写入数据了。可以用curl,或者是官方SDK:

curl -X POST 'https://Your_Meili_URL/indexes/posts/documents' \
  -H 'Authorization: Bearer API_KEY' \
  -H 'Content-Type: application/json' \
  --data '[
    {
      "id": 1,
      "createdAt": "2025-06-25T00:00:00Z",
      "title": "中文标题",
      "content": "中文内容",
      "userUid": 1,
    }
  ]'
import { MeiliSearch } from 'meilisearch';
import { Post } from '@/generated/prisma';

const client = new MeiliSearch({
  host: process.env.MEILI_HOST || "",
  apiKey: process.env.MEILI_API_KEY, 
})

const index = client.index('posts')

async function addSingleDocument(post: Post) {
  await index.addDocuments([post])
}

await addSingleDocument(post)

搜索

搜索也是,可以用curl,或者是官方SDK:

参数 说明
q 要搜索的关键词
limit 返回的最大结果数
offset 跳过的结果数(用于分页)
filter 过滤条件(可选)
sort 排序条件(可选)
curl -X POST 'https://Your_Meili_URL/indexes/posts/search' \
  -H 'Authorization: Bearer API_KEY' \
  -H 'Content-Type: application/json' \
  --data '{
    "q": "关键词",
    "limit": 10,
    "offset": 0,
    "filter": "userUid = 1 AND title = xxx",
    "sort": ["createdAt:desc"]
}'
import { MeiliSearch } from 'meilisearch';

const client = new MeiliSearch({
  host: process.env.MEILI_HOST || "",
  apiKey: process.env.MEILI_API_KEY, 
})

async function searchPosts(query) {
  const index = client.index('posts')
  const result = await index.search(query, {
    limit: 10
  })
  console.log(result.hits)
}

searchPosts('中文')
INFO

框架状态


URL:
来源: ---
此页访问量:
此页访问人数:
此页平均滞留:
网络连接状态: 离线
Cookie状态: 已禁用
页面加载状态:
站点运行时长: ---

00:00


    无正在播放的音乐
    00:00/00:00


    账号
    User avatar
    未登录未设置描述...
    尚未登录,部分功能受限
    立刻 登录 注册
     未登录
    刷新进程离线
    当前未存储有效的TOKEN

    通知中心

    总计0条通知,0条未读通知
    当前未登录,无法查看通知


    - Mind stuff, that's what they say when the verses fly -