本文记录 MeiliSearch 的搭建及如何在 Hexo 博客上使用,原则上来说,MeiliSearch 在前端搜索上使用了公共开源的 instantsearch.js 项目,这个项目是由 Aligolia 维护,所以在前端页面上的使用流程与 Aligolia 大差不差。在后端部署层面,MeiliSearch 作为一个 Rust 项目支持的操作系统很多,同时也支持一键部署至相应云服务中。

一、部署

作为一个自部署搜索引擎,除了个人服务器外还支持部署到诸如 Railway, Koyeb 等这类云服务中,此部分查阅对应文档即可,本文侧重于个人服务器上的部署流程。

1. 程序安装

根据官方提供的安装命令,在一个你喜欢的目录下执行如下命令。

本文中将程序存放于 opt/meilisearch 目录,下不赘述
curl -L https://install.meilisearch.com | sh

实际上脚本是在判断操作系统环境,然后去 Github Releases 下载对应的发行包,所以这里你可以手动下载你服务器所需发行包后自行上传至相关目录,最后将程序名称更改为 meilisearch 即可。

2. 程序配置

一些基础的命令行配置,摘自:Configure Meilisearch at launch

CommandCLI optionRemark
自定义端口–http-addr更改程序端口
主密钥–master-key生产环境下必须配置,也可用来管理各类其他密钥
环境–env用于设置生产/开发环境,生产环境会关掉默认的 Web 搜索页面
分析–no-analyticsMeiliSearch 会上传一定的分析数据,收集数据列表

3. 反代运行

宝塔面板的网站选项卡更新出了其他项目选项,一切以偷懒为目的,此处使用这里进行配置。

点击添加通用项目,填写相应内容,下列为执行命令一项的内容举例:

执行命令
/opt/meilisearch/meilisearch --http-addr '127.0.0.1:8772' --master-key 'xxxx' --env production --no-analytics

注:宝塔这里的停止项目按钮似乎有点问题,有时候只能停网站,程序却还在运行。
自行根据端口号查找后关闭吧:sudo netstat -tunlp | grep 8772

二、数据集

Diagram illustration Meilisearch's document structure

类比的简单理解,MeiliSearch 里数据集合被称作 Documents,index 相当于表名,同时还需要一个 Primary key 区别数据。所以为了能在 Hexo 博客上使用该搜素引擎,流程就很明确了:

  1. 在 MeiliSearch 中创建表 indexs;

  2. 准备博客的所有内容数据 Documents(json/ndjson/csv);

  3. 设置需要搜索的内容。

第 1 和 3 步调用 MeiSearch 的相关接口即可,第 2 步的数据集合则需要我们自行准备,一般的该数据集合至少包含:标题内容地址以及 MeiliSearch 所需的主键

1. 主键

先解决主键,保证每篇文章拥有一个唯一值,秉着有现成就绝不自己写、能偷懒就偷懒的态度,找到了 chekun/hexo-uuid 这个插件,安装后能够在 post/page 页面中自动生成 uuid 值。

npm install hexo-uuid

注:hexo-uuid 实际上是使用 uuid.v1() 根据时间戳在 before_renderPost 阶段时生成写入。
对于 MeiliSearch,相同的主键在上传时视为更新,不同时视为新增。

2. 内容

在本地搜索时,用到了 hexo-generator-json-content,按照其说明,改吧改吧配置可以直接拿过来给 MeiSearch 使用,计划通

npm i hexo-generator-json-content

安装完成插件后,至少需要修改配置文件为如下内容:

blog/_config.yml
jsonContent: 
meta: false
pages: false
posts:
title: true
path: true
text: true
uuid: true

这里的 uuid 便是上面 hexo-uuid 在文章中所生成的唯一值,事实上拿 hexo-abbrlink 所生成的 abbrlink 也不是说不可以,只要保证唯一性即可。

3. 推送

在不修改默认设置的情况下,索引文件默认生成至 /blog/public/content.json 下。MeiliSearch 的上传接口为 /indexes/{index_uid}/documents,对应文档:Add or replace documents

此处利用 Github Action 在每次部署完成时使用 curl 命令推送文件。

index 为 hexo,主键指定为 uuid
curl -X POST 'https://yoursdomain.com/indexes/hexo/documents/?primaryKey=uuid' \
-H "Authorization: Bearer ${{secrets.MEILISEARCH_KEY}}" \
-H "Content-Type: application/json" \
--data-binary '@public/content.json'

三、主题适配

1. 引用文件

<script src="https://unpkg.com/@meilisearch/instant-meilisearch/dist/instant-meilisearch.umd.min.js"></script>
<script src="https://unpkg.com/instantsearch.js@4.44/dist/instantsearch.production.min.js"></script>

2. 实例化

MeiliSearch 仅在 SearchClient 阶段有所不同:

填入 MeiliSearch 服务端地址和 SearchKey
const search = instantsearch({
indexName: 'instant_search',
searchClient: instantMeiliSearch(
'https://integration-demos.meilisearch.com',
'99d1e034ed32eb569f9edc27962cccf90b736e4c5a70f7f5e76b9fab54d6a185'
),
})

MeiliSearch 可以利用 /keys 接口获取到 Default Search API Key。

Default Search API Key

3. Widgets

部分 Widgets 些许不同,MeiliSerch 可能不支持,相关列表见:Table Of Widgets

四、其它

1. 索引主键

其实索引主键还可以这样设置,简单粗暴的讲就是先删后传:不需要什么插件,直接使用 Hexo 的 _id 即可,然后上传前调用删除接口清空数据库(因为本身每次上传也是全量推送)。

blog/_config.yml
jsonContent: 
meta: false
pages: false
posts:
title: true
path: true
text: true
_id: true
Github Action
- name: Upload json
run: |
curl -X DELETE 'https://yoursdomain.com/indexes/hexo/documents' \
-H "Authorization: Bearer ${{secrets.MEILISEARCH_KEY}}"
curl -X POST 'https://yoursdomain.com/indexes/hexo/documents' \
-H "Authorization: Bearer ${{secrets.MEILISEARCH_KEY}}" \
-H "Content-Type: application/json" \
--data-binary '@public/content.json'

2. 索引设置

事实上,上传的字段共有四个,我们只需要对标题和内容进行搜索,另外两个不需要,相应接口文档:Update searchable attributes

需要主密钥认证
curl -X PUT 'https://search.szyink.com//indexes/hexo/settings/searchable-attributes' \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxx' \
--data-raw '["title", "text"]'

3. Postman

MeiliSearch 提供了一个 API 模板可以导入进 Postman 中,不然老用命令行多麻烦。

更改对应参数

4. 踩坑

适配时最尝试过 docs-searchbar.js 这个项目,他需要先利用 docs-scraper 抓取网站接口,然后在生成文档搜索。使用起来一言难尽,配置项特别少,很不灵活,强烈吐槽。

评论