Meilisearch 部署教程:给网站加上亚毫秒级全文搜索

搜索是大多数网站逃不掉的功能。MySQL 的 LIKE 在数据量过万之后就开始变慢,Elasticsearch 又重得让人望而却步,而 Meilisearch 正好填补了中间的空缺——用 Rust 写的轻量级搜索引擎,单容器就能跑,官方 demo 中搜索响应普遍在几十毫秒内。本教程按 GitHub 仓库 README 的事实为准,一步一步把 Meilisearch 用 Docker 部署起来,并把搜索接入到你的网站里。

Meilisearch 是什么

Meilisearch 是一个开源的搜索引擎,目标是「开箱即用 + 亚毫秒级响应」。它不是数据库,而是为了搜索而生的引擎:你把文档喂给它,它帮你建索引、提供 RESTful API 返回匹配结果。

从 README 的 Features 列表可以看到它的能力覆盖得相当全:混合搜索(语义 + 全文)、即时搜索(Search-as-you-type)、容错匹配(typo tolerance)、过滤与分面、排序、同义词、地理搜索、多语言(中文/日文/希伯来文/拉丁语系都有优化)、租户隔离、API Key 鉴权、文档关联、分片与复制等。

这意味着无论是电商商品搜索、博客全文检索、CRM 联系人查找,还是文档知识库,都能套上 Meilisearch。

Meilisearch 官方演示站点 Where2Watch 的搜索界面截图,展示即时搜索效果-1

前置准备

部署 Meilisearch 本身的要求不高,按 README 与社区实践,需要准备:

  • Docker:用于拉取官方镜像 meilisearch/meilisearch,单容器即可运行
  • 512M 内存起步:官方对最低内存的建议是小数据集 512M 起步,中等规模建议 1G 以上
  • 一个可用的端口:默认监听 7700,建议内网或反代后访问,不要直接暴露公网
  • 生产环境必须设置 Master Key:这是 Meilisearch 安全模型的硬性要求,没设 key 等同于公开可写

如果是云服务器,建议提前在安全组里把 7700 端口限制为只允许内部访问或反代服务器访问。

Docker 单容器部署

最简单的方式是用一行 docker run 跑起来。仓库 README 里推荐的命令形式如下:

docker run -d \
  -p 7700:7700 \
  -v meili:/meili_data \
  meilisearch/meilisearch

这条命令做了三件事:

  • -d 后台运行容器
  • -p 7700:7700 把宿主机 7700 映射到容器内的 7700
  • -v meili:/meili_data 把数据卷挂到容器内的 /meili_data,保证重启容器后索引数据不丢

容器启动后,访问 http://:7700 应该能看到 Meilisearch 的内置预览 UI。这个 UI 不只是展示用,还能直接在里面调试索引和搜索请求,开发阶段非常方便。

必须设置的环境变量

单容器跑起来只是第一步。生产部署前必须设置 MEILI_MASTER_KEY,否则任何人只要能访问到 7700 端口,就能往你的索引里塞数据、删数据、改数据——这是 README 里反复强调的安全要求。

生成一个强随机密码作为 master key:

openssl rand -base64 32

把生成的字符串填入环境变量:

docker run -d \
  -p 7700:7700 \
  -v meili:/meili_data \
  -e MEILI_MASTER_KEY=你的强随机密码 \
  --name meilisearch \
  meilisearch/meilisearch

除了 master key,还有一些常用的环境变量可以根据需要设置(具体参数请参考官方文档):

环境变量 作用
MEILI_MASTER_KEY 管理 API key,访问管理接口时必须带
MEILI_ENV 运行环境:developmentproduction,生产建议设 production
MEILI_NO_ANALYTICS 是否关闭遥测,true 表示关闭
MEILI_HTTP_ADDR 监听地址,默认 0.0.0.0:7700
MEILI_DB_PATH 索引数据目录,默认 /meili_data

索引文档:把数据喂给 Meilisearch

Meilisearch 用「Index(索引)」来组织文档,类似数据库的表。一个 index 里放的是同一类文档,比如 booksproductsarticles

下面演示怎么建一个 books 索引并往里塞两条数据。先用 curl 加文档:

curl -X POST 'http://localhost:7700/indexes/books/documents?primaryKey=id' \
  -H 'Content-Type: application/json' \
  --data-binary '[
    { "id": 1, "title": "老人与海", "author": "海明威" },
    { "id": 2, "title": "百年孤独", "author": "马尔克斯" }
  ]'
  • /indexes/books/documents:往 books 索引写文档
  • primaryKey=id:告诉引擎用 id 字段做主键
  • 请求体是一个 JSON 数组,每条记录就是一篇文档

文档提交后,Meilisearch 会异步建索引,几百到几千条几乎瞬间完成,几万条以上会稍等几秒。可以查询任务状态确认是否完成:

curl 'http://localhost:7700/tasks?indexUids=books&limit=1' \
  -H "Authorization: Bearer 你的强随机密码"

搜索 API:把搜索结果拿回来

索引建好之后,搜索就一行请求的事。Meilisearch 的搜索端点是 /indexes//search

curl -X POST 'http://localhost:7700/indexes/books/search' \
  -H 'Content-Type: application/json' \
  -d '{ "q": "海" }'

返回结果大概长这样:

{
  "hits": [
    { "id": 1, "title": "老人与海", "author": "海明威" }
  ],
  "query": "海",
  "processingTimeMs": 1
}

hits 是命中的文档列表,processingTimeMs 是处理耗时——README 里宣传的「亚毫秒级响应」在这个字段里就能直接看到。

前端集成时只需要发个 POST 请求,把 q 参数换成用户输入的关键词即可。后端 SDK 方面,Meilisearch 官方提供了 JavaScript、Python、Go、Rust、PHP、Ruby、Java 等多种语言版本。

搜索 API 返回 JSON 结果的终端截图,包含 hits 数组与 processingTimeMs 字段-2

反向代理 + HTTPS:不要把 7700 直接暴露公网

直接把 7700 端口暴露在公网是非常危险的做法,哪怕设了 master key,也容易成为攻击目标。生产环境强烈建议用 Nginx 做反向代理,终止 HTTPS,再把请求转发给 7700。

一个最小可用的 Nginx 配置示例:

server {
    listen 443 ssl;
    server_name search.yourdomain.com;

    ssl_certificate     /etc/letsencrypt/live/search.yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/search.yourdomain.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:7700;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
    }
}

这样公网只能访问 443,由 Nginx 加密;7700 仍然只监听在 127.0.0.1,外部网络根本摸不到。

如果想让搜索端点对外开放给浏览器调用(不需要鉴权),又想让管理端点(/keys/indexes/*/settings 等)带鉴权,可以在 Nginx 层做路径分流:用 if 判断 $request_uri 是否以 /keys/indexes/*/documents 开头,是的话要求带上 Authorization 头,否则 401。

数据持久化与备份

上面 docker run 命令里的 -v meili:/meili_data 是数据卷,由 Docker 自动管理目录,容器删掉重建后索引依然在。但仅靠 Docker volume 不算备份——机器宕机或磁盘损坏照样丢数据。

最稳的备份方式是把整个 /meili_data 目录定期 tar 打包传到对象存储或异地机器。建议至少做到:

  • 每日全量备份:用 cron 跑 tar -czf meili-$(date +%F).tar.gz /var/lib/docker/volumes/meili/_data
  • 大版本升级前手动备份一次:README 提示大版本之间可能有 breaking changes,提前备份有备无患
  • 恢复演练:把备份文件解压到一个新目录,挂到临时容器里跑一次,确认能正常搜索

常见坑

生产环境实际用下来,几个最容易踩的坑:

生产没设 master key:这是 README 反复强调的,但在内网测试环境很容易忽略。一旦开放到公网,没设 key 等同于公开可写,攻击者能塞垃圾数据、消耗磁盘。建议把「未设 master key」作为上线 checklist 的硬性项。

版本升级没看 release notes:Meilisearch 迭代很快,主版本号变化(如 0.x → 1.x)通常意味着 schema、配置项或 API 行为有破坏性变更。升级前先看官方 release notes,确认是否需要 reindex。任何时候升级前先备份

中文搜索效果差:Meilisearch 默认对中文是按字符切分的,对于”南京市长江大桥”这种容易歧义的句子表现一般。README 里也提到中文有专门优化,但更精细的分词通常需要配合 jieba 等分词器在写入前预处理,或者使用 Meilisearch 提供的可配置分词选项。具体配置建议以官方文档为准。

7700 端口直接暴露公网:前面说过,攻击面太大。即使设了 master key,密码也可能被探测或泄露。多一层反代 + HTTPS,多一层保险。

忽略索引任务队列的积压:大批量写入时,建议监控 /tasks 端点的队列长度。如果任务堆积持续增长,说明磁盘 IO 或 CPU 跟不上,需要扩容或减小批量。

收尾

至此 Meilisearch 就部署完了:一个 Docker 容器挂着一个数据卷,前面是 Nginx 反代处理 HTTPS,后端业务通过 RESTful API 把搜索接入到网站。整个栈足够轻量,单台 2 核 4G 的机器就能支撑中等规模站点的搜索请求。

如果还想进一步了解 Meilisearch 在实际项目中的表现,包括它在不同数据规模、不同查询场景下的优缺点对比,可以看这篇评测:Meilisearch 评测:自托管搜索方案对比

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。