Featured image of post 自建 Meilisearch:轻量级全文搜索引擎,完美替代 Elasticsearch

自建 Meilisearch:轻量级全文搜索引擎,完美替代 Elasticsearch

在 VPS 上快速部署 Meilisearch 自建搜索引擎,毫秒级响应、易用的 API、超低资源占用,是 Elasticsearch 的最佳轻量级替代方案。

为什么选择 Meilisearch?

在构建网站或应用时,搜索功能几乎是必选项。但提到搜索引擎,很多人第一反应就是 Elasticsearch。说实话,Elasticsearch 确实功能强大,但它也有明显的缺点:

  • 资源占用高:最低需要 1GB+ 内存,对于小 VPS 来说压力很大
  • 部署复杂:需要 JVM 运行时,配置繁琐
  • 运维成本高:集群管理、索引调优都需要专业知识
  • 费用不菲:即便是开源版,在云上运行成本也不低

Meilisearch 是一个用 Rust 编写的开源搜索引擎,它的核心理念是:让搜索变得简单,让每个人都能拥有自己的搜索引擎。相比 Elasticsearch,它具有以下显著优势:

特性MeilisearchElasticsearch
内存占用~50MB(空闲)~1GB+
部署方式单二进制文件 / DockerJVM + 复杂配置
学习曲线极低,API 直观陡峭
搜索速度毫秒级毫秒级
中文支持内置分词器需配置插件
资源需求512MB 内存即可运行建议 2GB+
运维复杂度几乎为零较高

核心特性

1. 闪电般的搜索速度

Meilisearch 基于 Rust 开发,充分利用了内存映射和 SIMD 指令集优化。即使是百万级文档,也能在 10 毫秒内返回搜索结果。

2. 开箱即用的用户体验

  • 拼写容错:自动纠正用户输入的错别字
  • ** фасет搜索**:支持多维度筛选和排序
  • 多语言支持:内置 20+ 种语言的分词器,包括中文
  • 向量搜索:支持语义搜索(Meilisearch v0.28+)

3. 极简的 API 设计

Meilisearch 的 API 设计非常直观,几乎所有操作都可以通过 HTTP 请求完成,无需复杂的客户端库。

环境准备

系统要求

  • 操作系统:Ubuntu 22.04 / 24.04 或 Debian 12
  • 内存:最低 512MB(推荐 1GB+)
  • 磁盘:至少 5GB 可用空间
  • Docker:用于容器化部署(推荐)

初始化环境

# 更新系统
sudo apt update && sudo apt upgrade -y

# 安装 Docker
curl -fsSL https://get.docker.com | sudo sh

# 将当前用户加入 docker 组
sudo usermod -aG docker $USER
newgrp docker

# 验证 Docker 安装
docker --version

部署 Meilisearch

方式一:Docker 部署(推荐)

# 创建数据持久化目录
mkdir -p ~/meilisearch/data

# 启动 Meilisearch 容器
docker run -d \
  --name meilisearch \
  -p 7700:7700 \
  -v ~/meilisearch/data:/meili_data \
  -e MEILI_MASTER_KEY=myMasterKey123 \
  -e MEILI_NO_ANALYTICS=true \
  -e MEILI_ENV=production \
  meilisearch/meilisearch:latest

# 查看运行状态
docker ps | grep meilisearch
docker logs -f meilisearch

方式二:直接下载二进制文件

# 下载 Meilisearch
curl -L https://meilisearch.com/install.sh | bash

# 启动服务
./meilisearch --master-key myMasterKey123 --no-analytics

配置反向代理(可选)

为了安全性,建议通过 Nginx 反向代理暴露 Meilisearch:

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

    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/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;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

基础使用指南

1. 创建索引和导入数据

Meilisearch 的核心概念是 索引(Index),每个索引类似于数据库中的一张表。

# 创建一个索引并导入数据
curl -X POST 'http://localhost:7700/indexes/products/documents' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary @'products.json'

products.json 示例:

[
  {
    "id": 1,
    "name": "机械键盘",
    "category": "数码",
    "price": 299,
    "description": "RGB背光机械键盘, Cherry轴体"
  },
  {
    "id": 2,
    "name": "无线鼠标",
    "category": "数码",
    "price": 89,
    "description": "蓝牙无线鼠标,静音设计"
  },
  {
    "id": 3,
    "name": "显示器支架",
    "category": "配件",
    "price": 159,
    "description": "可调角度显示器支架,铝合金材质"
  }
]

2. 执行搜索

# 基本搜索
curl 'http://localhost:7700/indexes/products/search' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{"q": "键盘"}'

# 搜索结果
# {
#   "hits": [
#     {
#       "id": 1,
#       "name": "机械键盘",
#       "category": "数码",
#       "price": 299,
#       "description": "RGB背光机械键盘, Cherry轴体"
#     }
#   ],
#   "query": "键盘",
#   "offset": 0,
#   "limit": 20,
#   "processingTimeMs": 1
# }

3. 配置 searchable attributes

优化搜索体验的关键是正确配置可搜索字段:

# 设置可搜索字段和排序规则
curl -X PATCH 'http://localhost:7700/indexes/products' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{
    "searchableAttributes": ["name", "description", "category"],
    "sortableAttributes": ["price"],
    "rankingRules": [
      "words",
      "typo",
      "proximity",
      "attribute",
      "sort",
      "exactness"
    ]
  }'

高级功能

1. 中文分词配置

Meilisearch 内置了对中文的良好支持,但为了确保最佳效果,可以自定义分词器:

# 设置中文分词
curl -X PATCH 'http://localhost:7700/indexes/products' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{
    "dictionary": ["中文", "专业术语"]
  }'

Facets 允许用户对搜索结果进行多维度筛选:

# 搜索并启用 facets
curl 'http://localhost:7700/indexes/products/search' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{
    "q": "显示器",
    "facets": ["category", "price"]
  }'

3. 向量搜索(语义搜索)

Meilisearch v0.28+ 支持向量搜索,可以实现语义级别的搜索:

# 启用向量搜索
curl -X PATCH 'http://localhost:7700/indexes/products' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{
    "vectorStore": true
  }'

# 使用向量搜索
curl 'http://localhost:7700/indexes/products/search' \
  --header 'Authorization: Bearer myMasterKey123' \
  --header 'Content-Type: application/json' \
  --data-binary '{
    "q": "电脑周边设备",
    "vector": [0.1, 0.2, 0.3, ...]
  }'

4. 数据备份与恢复

# 创建备份
curl -X POST 'http://localhost:7700/backups' \
  --header 'Authorization: Bearer myMasterKey123'

# 列出备份
curl 'http://localhost:7700/backups' \
  --header 'Authorization: Bearer myMasterKey123'

# 恢复备份
curl -X POST 'http://localhost:7700/backups/20240101-120000' \
  --header 'Authorization: Bearer myMasterKey123'

与前端集成

1. Vue.js 集成示例

<template>
  <div class="search-container">
    <input v-model="query" @input="search" placeholder="搜索..." />
    <ul v-if="results.length">
      <li v-for="item in results" :key="item.id">
        {{ item.name }} - ¥{{ item.price }}
      </li>
    </ul>
  </div>
</template>

<script setup>
import { ref } from 'vue'

const query = ref('')
const results = ref([])

const search = async () => {
  const res = await fetch('http://localhost:7700/indexes/products/search', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer myMasterKey123',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ q: query.value })
  })
  const data = await res.json()
  results.value = data.hits
}
</script>

2. Next.js API 集成

// app/api/search/route.ts
export async function POST(request: Request) {
  const { query } = await request.json()
  
  const res = await fetch('http://localhost:7700/indexes/products/search', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer myMasterKey123',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({ q: query })
  })
  
  const data = await res.json()
  return Response.json(data)
}

性能优化建议

1. 合理设置索引字段

  • 只将需要的字段设为 searchableAttributes
  • 将用于排序的字段设为 sortableAttributes
  • 定期清理不使用的索引

2. 监控资源使用

# 查看 Meilisearch 资源使用
docker stats meilisearch

# 查看搜索性能
curl 'http://localhost:7700/stats' \
  --header 'Authorization: Bearer myMasterKey123'

3. 使用 Redis 缓存

对于高频搜索,可以在 Meilisearch 前面加一层 Redis 缓存:

# 安装 Redis
sudo apt install redis-server -y
sudo systemctl enable redis-server
sudo systemctl start redis-server

常见问题

Q1: Meilisearch 能替代 Elasticsearch 吗?

对于 中小型项目(文档数 < 1000 万),Meilisearch 完全可以替代 Elasticsearch。但对于大规模数据场景,Elasticsearch 的分布式能力仍然不可替代。

Q2: 中文搜索效果如何?

Meilisearch 内置中文分词支持,但对于专业术语和领域词汇,建议自定义 dictionary 以获得更好的效果。

Q3: 如何保证数据安全?

  • 始终设置 MASTER_KEY 进行身份验证
  • 通过反向代理和 SSL 加密传输
  • 定期备份数据
  • 限制访问 IP 白名单

Q4: Meilisearch 的局限性?

  • 不支持分布式部署(单节点架构)
  • 大数据量下性能不如 Elasticsearch
  • 生态相对较小,社区插件较少

总结

Meilisearch 以其 极简的部署方式、极低的资源占用、极快的搜索速度,成为了自托管搜索场景的理想选择。无论是个人博客、小型电商平台还是内部知识库,Meilisearch 都能提供出色的搜索体验。

对于预算有限的 VPS 用户来说,用 Meilisearch 替代 Elasticsearch 是一个明智的选择——既能获得优秀的搜索功能,又能节省可观的资源成本。

行动建议:现在就部署你的第一个 Meilisearch 实例,体验毫秒级搜索的魅力!

📺 看视频版教程 → DuckDB Lab YouTube

Subscribe for more DuckDB & AI automation tutorials