本页内容

  • 前置条件
  • 第 1 步 - 配置防火墙
  • 第 2 步 - 安装 Meilisearch
  • 第 3 步 - 为 Meilisearch 创建系统用户
  • 第 4 步 - 配置 Meilisearch
  • 第 5 步 - 创建目录并赋予权限
  • 第 6 步 - 将 Meilisearch 作为服务运行
  • 第 7 步 - 安装 Nginx
  • 第 8 步 - 安装 SSL
  • 第 9 步 - 配置 Nginx
  • 第 10 步 - 在 Meilisearch 中加载示例数据
  • 第 11 步 - 使用受限密钥进行搜索
  • 第 12 步 - 通过示例数据进行搜索
  • 第 13 步 - 调整搜索排序与数据过滤
  • 第 14 步 - 总结

Meilisearch 是一个用 Rust 语言编写的开源搜索引擎。由于使用 Rust 编写,它运行时所需的资源更少,并且可以通过单个命令行二进制文件来运行。其安装过程比其他替代搜索引擎更简单,所需步骤也更少。它的特性包括模糊匹配和无模式(schema-less)索引。它还自带一个用于演示的 Web 前端。通过 JavaScript、Python、PHP、Ruby 等多种语言提供的各类库,它可以集成到各种 Web 应用中。

在本教程中,你将学习如何在 Debian 12 服务器上以生产环境方式安装 Meilisearch,并使用它执行一些简单的搜索。

前置条件

  • 一台运行 Debian 12 且至少配备 2GB 内存的服务器。
  • 一个拥有 sudo 权限的非 root 用户。
  • 已启用并正在运行的 UFW(简易防火墙)。
  • 一个指向你服务器的完全限定域名(FQDN),例如 meilisearch.example.com。如果你希望通过代理服务器使用 SSL 提供 Meilisearch 服务,这会很有用。
  • 所有软件包均已更新。 $ sudo apt update && sudo apt upgrade

一台运行 Debian 12 且至少配备 2GB 内存的服务器。

一个拥有 sudo 权限的非 root 用户。

已启用并正在运行的 UFW(简易防火墙)。

一个指向你服务器的完全限定域名(FQDN),例如 meilisearch.example.com。如果你希望通过代理服务器使用 SSL 提供 Meilisearch 服务,这会很有用。

所有软件包均已更新。

$ sudo apt update && sudo apt upgrade
  • 本教程需要几个必要的软件包。其中部分可能已在你的服务器上安装。 $ sudo apt install curl wget nano software-properties-common dirmngr apt-transport-https ca-certificates lsb-release debian-archive-keyring gnupg2 ufw unzip -y

本教程需要几个必要的软件包。其中部分可能已在你的服务器上安装。

$ sudo apt install curl wget nano software-properties-common dirmngr apt-transport-https ca-certificates lsb-release debian-archive-keyring gnupg2 ufw unzip -y

第 1 步 - 配置防火墙

在安装任何软件包之前,第一步是配置防火墙以允许 HTTP 和 HTTPS 连接。

检查防火墙状态。

$ sudo ufw status

你应该会看到类似以下的输出。

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)

允许 HTTP 和 HTTPS 端口。

$ sudo ufw allow http
$ sudo ufw allow https

再次检查状态以确认。

$ sudo ufw status
Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443/tcp                    ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443/tcp (v6)               ALLOW       Anywhere (v6)

第 2 步 - 安装 Meilisearch

安装 Meilisearch 有多种方式。我们将使用最简单的方法,即把二进制文件复制到服务器上。

安装 Meilisearch。

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

赋予二进制文件可执行权限。

$ chmod +x meilisearch

目前该二进制文件只能在下载它的目录中使用。为了能从任意位置使用它,请将二进制文件移动到 /usr/local/bin 目录。

$ sudo mv ./meilisearch /usr/local/bin/

确认 Meilisearch 已正确安装并可正常运行。

$ meilisearch --version
meilisearch 1.7.6

第 3 步 - 为 Meilisearch 创建系统用户

以 root 身份运行 Meilisearch 可能会带来安全问题。为避免此类问题,请创建一个专门用于运行 Meilisearch 的系统用户。

$ sudo useradd -d /var/lib/meilisearch -b /bin/false -m -r meilisearch

第 4 步 - 配置 Meilisearch

在继续之前,我们需要创建一个主密钥(master key),Meilisearch 会用它进行身份验证。你可以使用 OpenSSL 命令行工具来创建它。运行以下命令创建一个 30 字符长的主密钥。你也可以为你的主密钥选择任意长度,越长越好。

$ openssl rand -hex 30

你应该会收到一个类似的输出,其中包含一个 30 字符长的密钥。请复制这个值,因为后续步骤中会用到它。

65ed5fc15848f7ceb8e646d4928fcf79f494cec239a2874cacd118e42611

从 Meilisearch 的 GitHub 仓库获取最新的配置文件,并将其复制到 /etc 目录。

$ sudo sh -c 'curl https://raw.githubusercontent.com/meilisearch/meilisearch/latest/config.toml > /etc/meilisearch.toml'

打开该文件进行编辑。

$ sudo nano /etc/meilisearch.toml

更新文件中的以下行,以配置数据库路径、转储路径、快照目录和工作环境,并添加你之前生成用于身份验证的主密钥。

配置文件中更新后的值应如下所示。

env = "production"
master_key = "173e95f077590ed33dad89247247be8d8ce8b6722ccc87829aaefe3207be"
db_path = "/var/lib/meilisearch/data"
dump_dir = "/var/lib/meilisearch/dumps"
snapshot_dir = "/var/lib/meilisearch/snapshots"

Meilisearch 会匿名收集常规数据。你应使用以下选项将其禁用。取消该行注释即可停用 Meilisearch 的遥测功能。

no_analytics = true

默认情况下,Meilisearch 使用的内存不超过系统可用内存的三分之二。你可以通过取消注释并设置以下变量来控制它。你也可以以精确的字节数来指定该值,从而做到精确控制。

max_indexing_memory = "1 GiB"

Meilisearch 使用的 CPU 核心数不超过可用核心数的一半。不过,你可以通过取消注释并设置以下变量来控制这个值。

max_indexing_threads = 1

如果将此值设置为超过机器的 CPU 核心数,Meilisearch 将使用最大可用核心数。

另一个你需要了解的设置为 Meilisearch 可接受的最大负载大小。默认值设置为 100MB。你可以通过配置以下变量来修改它。

http_payload_size_limit = "100 MB"

完成后,按 Ctrl + X 并在提示时输入 Y 保存文件。

第 5 步 - 创建目录并赋予权限

创建 Meilisearch 用于存储其数据库、数据库转储和快照的目录。

$ sudo mkdir /var/lib/meilisearch/dumps -p
$ sudo mkdir /var/lib/meilisearch/snapshots

将这些目录的所有者和所属组设置为我们为 Meilisearch 创建的系统用户。

$ sudo chown -R meilisearch:meilisearch /var/lib/meilisearch

设置 Meilisearch 二进制文件的所有者和所属组。

$ sudo chown meilisearch:meilisearch /usr/local/bin/meilisearch

为该目录设置合适的权限。

$ sudo chmod 750 /var/lib/meilisearch

第 6 步 - 将 Meilisearch 作为服务运行

为了让 Meilisearch 随时可用于处理搜索请求,最好将其作为系统服务运行。为此,我们需要为它创建一个服务文件。

创建并打开 /etc/systemd/system/meilisearch.service 进行编辑。

$ sudo nano /etc/systemd/system/meilisearch.service

在其中粘贴以下代码。

[Unit]
Description=Meilisearch
After=systemd-user-sessions.service

[Service]
Type=simple
WorkingDirectory=/var/lib/meilisearch
ExecStart=/usr/local/bin/meilisearch --config-file-path /etc/meilisearch.toml
User=meilisearch
Group=meilisearch

[Install]
WantedBy=multi-user.target

按 Ctrl + X 并在提示时输入 Y 保存文件。

启用该服务。

$ sudo systemctl enable meilisearch

启动 Meilisearch 服务。

$ sudo systemctl start meilisearch 

检查服务状态

$ sudo systemctl status meilisearch

你应该会收到类似的输出。

? meilisearch.service - Meilisearch
     Loaded: loaded (/etc/systemd/system/meilisearch.service; enabled; preset: enabled)
     Active: active (running) since Fri 2024-05-03 03:02:53 UTC; 5s ago
   Main PID: 1008 (meilisearch)
      Tasks: 6 (limit: 2251)
     Memory: 23.0M
        CPU: 10ms
     CGroup: /system.slice/meilisearch.service
             ??1008 /usr/local/bin/meilisearch --config-file-path /etc/meilisearch.toml

May 03 03:02:53 meilisearch meilisearch[1008]: Commit date:                "unknown"
May 03 03:02:53 meilisearch meilisearch[1008]: Package version:        "1.7.6"
May 03 03:02:53 meilisearch meilisearch[1008]: Anonymous telemetry:        "Disabled"
May 03 03:02:53 meilisearch meilisearch[1008]: A master key has been set. Requests to Meilisearch won't be authorized unless you provide an authentication key.
May 03 03:02:53 meilisearch meilisearch[1008]: Check out Meilisearch Cloud!        https://www.meilisearch.com/cloud?utm_campaign=oss&utm_source=engine&utm_medium=cli
May 03 03:02:53 meilisearch meilisearch[1008]: Documentation:                        https://www.meilisearch.com/docs
May 03 03:02:53 meilisearch meilisearch[1008]: Source code:                        https://github.com/meilisearch/meilisearch
May 03 03:02:53 meilisearch meilisearch[1008]: Discord:                        https://discord.meilisearch.com
May 03 03:02:53 meilisearch meilisearch[1008]: 2024-05-03T03:02:53.891366Z  INFO actix_server::builder: starting 2 workers
May 03 03:02:53 meilisearch meilisearch[1008]: 2024-05-03T03:02:53.891396Z  INFO actix_server::server: Actix runtime found; starting in Actix runtime

Meilisearch 已安装并正在运行。接下来我们使用 Nginx 服务器作为反向代理将服务对外暴露,并使用 Let's Encrypt 通过 SSL 提供访问。

第 7 步 - 安装 Nginx

Debian 12 自带较旧版本的 Nginx。你需要下载官方的 Nginx 仓库来安装最新版本。

导入 Nginx 的签名密钥。

$ curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \
    | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null

添加 Nginx 主线(mainline)版本的仓库。

$ echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
http://nginx.org/packages/mainline/debian `lsb_release -cs` nginx" \
    | sudo tee /etc/apt/sources.list.d/nginx.list

更新系统仓库。

$ sudo apt update

安装 Nginx。

$ sudo apt install nginx

验证安装。在 Debian 系统上,以下命令需要配合 sudo 才能运行。

$ sudo nginx -v
nginx version: nginx/1.25.5

启动 Nginx 服务器。

$ sudo systemctl start nginx

检查服务状态。

$ sudo systemctl status nginx
? nginx.service - nginx - high performance web server
     Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
     Active: active (running) since Fri 2024-05-03 03:04:02 UTC; 5s ago
       Docs: https://nginx.org/en/docs/
    Process: 1699 ExecStart=/usr/sbin/nginx -c /etc/nginx/nginx.conf (code=exited, status=0/SUCCESS)
   Main PID: 1700 (nginx)
      Tasks: 3 (limit: 2251)
     Memory: 2.9M
        CPU: 7ms
     CGroup: /system.slice/nginx.service
             ??1700 "nginx: master process /usr/sbin/nginx -c /etc/nginx/nginx.conf"
             ??1701 "nginx: worker process"
             ??1702 "nginx: worker process"

May 03 03:04:02 meilisearch systemd[1]: Starting nginx.service - nginx - high performance web server...
May 03 03:04:02 meilisearch systemd[1]: Started nginx.service - nginx - high performance web server.

第 8 步 - 安装 SSL

我们需要安装 Certbot 来生成 SSL 证书。你可以使用 Debian 的仓库安装 Certbot,也可以通过 Snapd 工具获取最新版本。我们将使用 Snapd 版本。

Debian 12 默认并没有安装 Snapd。请安装 Snapd 软件包。

$ sudo apt install -y snapd

运行以下命令以确保你的 Snapd 版本是最新的。

$ sudo snap install core && sudo snap refresh core

安装 Certbot。

$ sudo snap install --classic certbot

使用以下命令,通过创建指向 /usr/bin 目录的符号链接,确保 Certbot 命令可以运行。

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

验证 Certbot 是否正常工作。

$ certbot --version
certbot 2.10.0

运行以下命令以生成 SSL 证书。

$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m 
[email protected]
 -d meilisearch.example.com

上述命令会将证书下载到你服务器上的 /etc/letsencrypt/live/meilisearch.example.com 目录。

生成 Diffie-Hellman 组证书。

$ sudo openssl dhparam -dsaparam -out /etc/ssl/certs/dhparam.pem 4096

查看 systemd 定时器列表。Certbot 会自动安装并启动一个用于续期的定时器。

$ sudo systemctl list-timers

你会看到 snap.certbot.renew.service 是被安排运行的定时服务之一。

NEXT                        LEFT           LAST                        PASSED    UNIT                        ACTIVATES                   ---------------------------------------------------------------------------------------------------------------------------------------  
Fri 2024-05-03 17:17:15 UTC 14h left      Fri 2024-05-03 02:54:42 UTC 11min ago apt-daily.timer              apt-daily.service
Fri 2024-05-03 06:42:20 UTC 3h 36min left Fri 2024-05-03 02:54:42 UTC 11min ago apt-daily-upgrade.timer      apt-daily-upgrade.service
Fri 2024-05-03 10:39:00 UTC 7h left       -                           -         snap.certbot.renew.timer     snap.certbot.renew.service

对该流程进行一次空运行(dry run),以检查 SSL 续期是否正常工作。

$ sudo certbot renew --dry-run

如果没有看到任何错误,说明一切就绪。你的证书将自动续期。

第 9 步 - 配置 Nginx

打开 /etc/nginx/nginx.conf 文件进行编辑。

$ sudo nano /etc/nginx/nginx.conf

在 include /etc/nginx/conf.d/*.conf; 这一行之前添加以下行。

server_names_hash_bucket_size 64;

按 Ctrl + X 并在提示时输入 Y 保存文件。

创建并打开 /etc/nginx/conf.d/meilisearch.conf 文件进行编辑。

$ sudo nano /etc/nginx/conf.d/meilisearch.conf

在其中粘贴以下代码。将 meilisearch.example.com 替换为你自己的域名。

server {

    listen 443 ssl;
    listen [::]:443 ssl;

    http2 on;
    http3 on;
    quic_retry on;

    server_name meilisearch.example.com;

    access_log  /var/log/nginx/meilisearch.access.log;
    error_log   /var/log/nginx/meilisearch.error.log;

    ssl_certificate      /etc/letsencrypt/live/meilisearch.example.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/meilisearch.example.com/privkey.pem;
    ssl_trusted_certificate /etc/letsencrypt/live/meilisearch.example.com/chain.pem;

    ssl_session_timeout  5m;
    ssl_session_cache shared:MozSSL:10m;
    ssl_session_tickets off;
    ssl_early_data on;

    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384;
    ssl_ecdh_curve X25519:prime256v1:secp384r1:secp521r1;
    ssl_stapling on;
    ssl_stapling_verify on;
    ssl_dhparam /etc/ssl/certs/dhparam.pem;

    location / {
        proxy_pass http://localhost: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;
    }
}
# enforce HTTPS
server {
    listen 80;
    listen [::]:80;
    server_name  meilisearch.example.com;
    return 301   https://$host$request_uri;
}

按 Ctrl + X 并在提示时输入 Y 保存文件。

验证你的 Nginx 配置。

$ sudo nginx -t

重启 Nginx 服务器。

$ sudo systemctl restart nginx

Meilisearch 现已运行,并可通过 URL https://meilisearch.example.com 访问。打开该 URL 时,你应该会看到以下文本。

{"status":"Meilisearch is running"}

该 URL 只能用于通过命令行进行搜索。如果你想通过前端访问 Meilisearch,则需要将其与另一个 CMS 或软件集成才能实现,这超出了本教程的范围。Meilisearch 自带一个内置前端界面,但它仅在以开发目的使用时才有效。你可以在配置文件中将实例的运行环境改为 development,并重启 Meilisearch 来启用该界面。它看起来大致如下。

在 Debian 12 上安装并配置 Meilisearch 搜索引擎

对于生产环境,你需要将 Meilisearch 与另一个 CMS 集成。

让我们开始使用它来索引一些文档,并用它进行搜索。

第 10 步 - 在 Meilisearch 中加载示例数据

Meilisearch 项目提供了一个 JSON 格式的示例电影文件,其中的数据抓取自 The Movie Database(TMDB)。下载该文件。

$ wget https://www.meilisearch.com/movies.json

你可以运行 tail 命令查看部分数据。输出应如下所示。

$ tail -n 3 movies.json

{"id":460070,"title":"J.T. LeRoy","overview":"A young woman named Savannah Knoop spends six years pretending to be a transgender writer named JT Leroy, the made-up literary persona of her sister-in-law.","genres":["Drama"],"poster":"https://image.tmdb.org/t/p/w500/43ffZhMCWQhzMneGP4kDWoPV48X.jpg","release_date":1556236800},
{"id":460071,"title":"Lizzie","overview":"Massachusetts, 1892. An unmarried woman of 32 and a social outcast, Lizzie lives a claustrophobic life under her father's cold and domineering control. When Bridget Sullivan, a young maid, comes to work for the family, Lizzie finds a sympathetic, kindred spirit, and a secret intimacy soon blossoms into a wicked plan.","genres":["Crime","Drama","Thriller"],"poster":"https://image.tmdb.org/t/p/w500/z2iuBcwznen3kC9z4LeOzBSz1BB.jpg","release_date":1536883200}
]

如你所见,每条独立的记录都包含一个 id、标题、海报图片链接、电影简介、上映日期以及类型列表。上映日期采用 EPOCH(时间戳)格式。

让我们通过 HTTP POST 请求,使用 curl 将数据加载到 Meilisearch 中。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/documents' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 65ed5fc15848f7ceb8e646d4928fcf79f494cec239a2874cacd118e42611' \
  --data-binary @movies.json

我们来逐一了解该命令的参数:

  • -X POST - 指定我们执行的是 HTTP POST 请求并发送数据。
  • -H Content-Type - 指定文件的内容类型。
  • -H Authorization: Bearer - 用于在请求中携带主密钥。
  • --data-binary - 指定要包含的二进制文件。

这里我们正在 /indexes/movies/documents 位置创建一个新的 Meilisearch 索引。你应该会收到类似的输出,提示请求已入队。Meilisearch 会异步处理所有请求。

{"taskUid":0,"indexUid":"movies","status":"enqueued","type":"documentAdditionOrUpdate","enqueuedAt":"2024-05-03T03:12:55.599798591Z"}

你也可以将 URL http://localhost:7700 替换为 https://meilisearch.example.com 来运行上述命令,效果完全相同。本教程中的所有命令都可以这样操作,但为简便起见,我们将继续使用 http://localhost:7700 这个 URL。

运行以下命令以检查请求的状态。

$ curl -X GET 'http://localhost:7700/indexes/movies/tasks/0'

你应该会收到类似的输出。

{"uid":0,"indexUid":"movies","status":"succeeded","type":"documentAddition","details":{"receivedDocuments":19547,"indexedDocuments":19546},"duration":"PT29.866920116S","enqueuedAt":"2024-05-03T03:13:18.233702815Z","startedAt":"2024-05-03T03:19:45.370142371Z","finishedAt":"2024-05-03T03:20:05.108395540Z"}

这告诉我们任务已完成,电影数据库现已完全建立索引,可供使用。

第 11 步 - 使用受限密钥进行搜索

我们还需要一个名为 jq 的工具,它可以帮助以可读的方式格式化命令行中的 JSON。运行以下命令来安装它。

$ sudo apt install -y jq

尽管我们已在配置文件中添加了主密钥,但在每次请求时仍需要再次传递它。在继续之前,我们需要一个限制性更强的密钥来启用只读模式。Meilisearch 默认会创建一个只读密钥。让我们来获取它。

$ curl -X GET 'http://localhost:7700/keys' -H 'Authorization: Bearer 65ed5fc15848f7ceb8e646d4928fcf79f494cec239a2874cacd118e42611' | jq

你应该会看到类似的输出。

{
  "results": [
    {
      "name": "Default Search API Key",
      "description": "Use it to search from the frontend",
      "key": "591e51d2f6700ead7ba134a7aed0966d72e2022e43847caf48df3e4800c9279a",
      "uid": "d004073b-b813-4016-82cb-7995df5149f6",
      "actions": [
        "search"
      ],
      "indexes": [
        "*"
      ],
      "expiresAt": null,
      "createdAt": "2024-05-03T03:02:53.887256411Z",
      "updatedAt": "2024-05-03T03:02:53.887256411Z"
    },
    {
      "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": "0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196",
      "uid": "b4fc2f96-4347-4750-9ba6-2da73c26e2bd",
      "actions": [
        "*"
      ],
      "indexes": [
        "*"
      ],
      "expiresAt": null,
      "createdAt": "2024-05-03T03:02:53.886580786Z",
      "updatedAt": "2024-05-03T03:02:53.886580786Z"
    }
  ],
  "offset": 0,
  "limit": 20,
  "total": 2
}

从今往后,我们将使用默认的搜索 API 密钥(Default Search API Key)来执行搜索。

第 12 步 - 通过示例数据进行搜索

使用 Meilisearch 进行搜索有两种方式:你可以通过命令行使用 API,也可以使用 Web 界面。Web 界面功能相当有限,且仅在你以开发环境使用 Meilisearch 时才有效,而 API 是推荐使用的方式。由于我们已按生产环境配置了搜索,我们将只使用命令行方式。

通过 API 搜索类似于通过 HTTP POST 请求上传数据。你向 API 的 /search 端点发起请求。例如,让我们搜索所有标题中包含 saint 一词的电影。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 591e51d2f6700ead7ba134a7aed0966d72e2022e43847caf48df3e4800c9279a' \
  --data-binary '{ "q": "saint" }' | jq

你应该会收到类似以下以 JSON 格式输出的结果。

{
  "hits": [
    {
      "id": 25248,
      "title": "Saint Ralph",
      "overview": "This Canadian made comedy/drama, set in Hamilton, Ontario in 1954, is a sweet and - at times - goofy story that becomes increasingly poignant as the minutes tick by.  It's the fictional tale of a wayward 9th grader, Ralph (Adam Butcher), who is secretly living on his own while his widowed, hospitalized mother remains immersed in a coma. Frequently in trouble with Father Fitzpatrick (Gordon Pinsent), the principal of his all-boys, Catholic school, Ralph is considered something of a joke among peers until he decides to pull off a miracle that could save his mother, i.e., winning the Boston Marathon.  Coached by a younger priest and former runner, Father Hibbert (Campbell Scott), whose cynicism has been lifted by the boy's pure hope, Ralph applies himself to his unlikely mission, fending off naysayers and getting help along a very challenging path from sundry allies and friends.",
      "genres": [
        "Comedy",
        "Drama"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/3MdWgqUunIBWnc7mYi2dtZrD54Y.jpg",
      "release_date": 1123200000
    },
    {
      "id": 26894,
      "title": "Saint Sinner",
      "overview": "In 1815 a monk, Tomas Alcala, unwittingly unleashes two female succubi, Munkar and Nakir, upon an unsuspecting 21st century. He is chosen by God to travel through the centuries and stop the demons' rampage.",
      "genres": [
        "Fantasy",
        "Horror",
        "Science Fiction",
        "TV Movie"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/cxljKsfUI6PVFPIgPvsesUWHai4.jpg",
      "release_date": 1035590400
    },
    {
      "id": 27023,
      "title": "Saint John of Las Vegas",
      "overview": "An ex-gambler is lured back into the game by a veteran insurance-fraud investigator.",
      "genres": [
        "Comedy"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/kN4Vur1SccouDR0k3tmJXJHdrXw.jpg",
      "release_date": 1264723200
    },
  ...

为了测试 Meilisearch 的模糊匹配特性——即可以使用发音相近的词语来找到准确的搜索结果。当你出现拼写错误但仍期望得到正确结果时,这一特性非常有用。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 591e51d2f6700ead7ba134a7aed0966d72e2022e43847caf48df3e4800c9279a' \
  --data-binary '{ "q": "seint" }' | jq

在这里,我们将 saint 误拼为 seint,而 Meilisearch 仍然会返回包含 saint 一词的记录。

{
  "hits": [
    {
      "id": 10105,
      "title": "Saints and Soldiers",
      "overview": "Five American soldiers fighting in Europe during World War II struggle to return to Allied territory after being separated from U.S. forces during the historic Malmedy Massacre.",
      "genres": [
        "War",
        "Drama",
        "Action",
        "Adventure",
        "History"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/efhqxap8fLi4v1GEXVvakey0z3S.jpg",
      "release_date": 1063238400
    },
    {
      "id": 25248,
      "title": "Saint Ralph",
      "overview": "This Canadian made comedy/drama, set in Hamilton, Ontario in 1954, is a sweet and - at times - goofy story that becomes increasingly poignant as the minutes tick by.  It's the fictional tale of a wayward 9th grader, Ralph (Adam Butcher), who is secretly living on his own while his widowed, hospitalized mother remains immersed in a coma. Frequently in trouble with Father Fitzpatrick (Gordon Pinsent), the principal of his all-boys, Catholic school, Ralph is considered something of a joke among peers until he decides to pull off a miracle that could save his mother, i.e., winning the Boston Marathon.  Coached by a younger priest and former runner, Father Hibbert (Campbell Scott), whose cynicism has been lifted by the boy's pure hope, Ralph applies himself to his unlikely mission, fending off naysayers and getting help along a very challenging path from sundry allies and friends.",
      "genres": [
        "Comedy",
        "Drama"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/3MdWgqUunIBWnc7mYi2dtZrD54Y.jpg",
      "release_date": 1123200000
    },
    {
      "id": 26894,
      "title": "Saint Sinner",
      "overview": "In 1815 a monk, Tomas Alcala, unwittingly unleashes two female succubi, Munkar and Nakir, upon an unsuspecting 21st century. He is chosen by God to travel through the centuries and stop the demons' rampage.",
      "genres": [
        "Fantasy",
        "Horror",
        "Science Fiction",
        "TV Movie"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/cxljKsfUI6PVFPIgPvsesUWHai4.jpg",
      "release_date": 1035590400
    },
 …

第 13 步 - 调整搜索排序与数据过滤

如果搜索引擎知道如何根据特定字段的重要性对结果进行排序或赋予权重,就能返回更好的结果。Meilisearch 提供了一组默认的偏置规则,你可以对其进行配置以改善搜索结果。

但首先,我们需要检查 Meilisearch 设置的排序规则。

$ curl -X GET 'http://localhost:7700/indexes/movies/settings/ranking-rules' -H 'Authorization: Bearer 0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196'

你将得到以下输出。

["words","typo","proximity","attribute","sort","exactness"]
  • words - 结果按匹配词项数量递减排序。
  • typo - 结果按拼写错误数量递增排序。拼写错误更少的查询会排在更前面。
  • proximity - 结果按匹配词项之间的距离递增排序。
  • attribute - 结果按属性排序规则排序。
  • sort - 结果按查询时决定的参数进行排序。
  • exactness - 结果按匹配词与查询词的相似度排序。

你可以在 Meilisearch 官方文档中阅读更多关于相关性的内容。

发出以下命令以更改偏置规则的顺序。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/settings/ranking-rules' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196' \
  --data-binary '[
      "words",
      "typo",
      "proximity",
      "release_date:asc",
      "attribute",
      "sort",
      "exactness",
      "rank:desc"
  ]'

现在让我们对搜索结果进行过滤。首先,我们让 Meilisearch 只使用某些属性来执行搜索,并将 id 等无意义的属性排除在外。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/settings' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196' \
  --data-binary '{
      "searchableAttributes": [
          "title",
          "overview",
          "genres"
      ]
  }'

这里,我们仅使用 title(标题)、overview(简介)和 genres(类型)属性进行搜索,这将带来更好的结果。

接下来,我们可以对搜索结果进行格式化,使其只显示某些属性,而隐藏其他属性。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/settings/displayedAttributes' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196' \
  --data-binary '[
          "title",
          "overview",
          "genres",
          "release_date"
      ]'

这只会将我们包含在查询中的属性随结果一起显示。

最后,你还可以提供一组可用于过滤或排序的属性。这包括使用 < 或 > 等数学运算符进行的数值过滤,以及通过是否包含在指定集合中进行的过滤。这也被称为分面搜索(faceted search)。

$ curl \
  -X PATCH 'http://localhost:7700/indexes/movies/settings' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 0f3cdcfe5d9a56273d6c708f068a82382a97b629b70f4962f969687b5e327196' \
  --data-binary '{
      "filterableAttributes": [
          "genres",
          "release_date"
      ],
      "sortableAttributes": [
          "release_date"
      ]
  }'

我们可以组合所有这些规则,执行如下所示的查询。

$ curl \
  -X POST 'http://localhost:7700/indexes/movies/search' \
  -H 'Content-Type: application/json' \
  -H 'Authorization: Bearer 591e51d2f6700ead7ba134a7aed0966d72e2022e43847caf48df3e4800c9279a' \
  --data-binary '{ "q": "house", "sort": ["release_date:desc"], "filter": "genres = Horror" }' | jq

这里我们查找所有属于 Horror(恐怖)类型、标题中包含 house 一词的电影,并按从新到旧的顺序排列。你应该会收到类似的输出。

{
  "hits": [
    {
      "id": 440559,
      "title": "Housesitters",
      "overview": "Angie and Izzy get a housesitting gig that seems too good to be true. Gruesome supernatural hijinks ensue.",
      "genres": [
        "Comedy",
        "Horror"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/9Gnu0PBdYzyd7ZkO74XK0xCH0iY.jpg",
      "release_date": 1524873600
    },
    {
      "id": 449550,
      "title": "Housewife",
      "overview": "Housewife is centered on Holly whose mother murdered her sister and father when she was seven. 20 years later and slowly losing her grip on the difference between reality and nightmares, she runs into a celebrity psychic who claims that he is destined to help her.",
      "genres": [
        "Horror"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/ohHxS7PIRQb9O6KTrDtqYshYGts.jpg",
      "release_date": 1504828800
    },
    {
      "id": 392703,
      "title": "House of Darkness",
      "overview": "Inspired by true events, the supernatural thriller \"House of Darkness\" recounts the mysterious case of a San Francisco family who claimed that a dark force was responsible for the tragic events that unfolded.  Trying to save their struggling marriage Kelly (Sara Fletcher, \"Adulthood\"), her husband Brian (Gunner Wright, \"J. Edgar\") and their daughter Sarah (Mykayla Sohn, \"The Chosen\") move to a rural farmhouse in search of some serenity. Unbeknownst to them, nearly every family that has lived in the house has suffered some form of tragedy, dating back nearly 100 years. Shortly after their arrival, Kelly begins to sense that her husband’s behavior is growing increasingly strange and violent. Kelly also comes to discover the voices she’s hearing echoing through the halls, are not coming from her daughter. Will Kelly and her family be the next victims of the dark forces in the house?",
      "genres": [
        "Horror",
        "Thriller",
        "TV Movie"
      ],
      "poster": "https://image.tmdb.org/t/p/w500/ueQM9RsT0HLL2RuuiLmD07j8lKB.jpg",
      "release_date": 1460851200
    },
…

第 14 步 - 总结

你已成功在 Debian 12 服务器上以生产环境方式安装并配置了 Meilisearch。你还执行了一些基本的搜索,并学习了如何通过排序和过滤来优化搜索结果。如果你有任何疑问,请在下方评论区留言。