Hugo 集成 Algolia 搜索踩坑 – 2023 版

原创
2023/05/03 18:56
阅读数 976

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

前言

去年开始,我开始维护持续集成和持续部署工具 Drone的中文文档站Drone.cool,有将网站内容集成到Algolia的诉求,但现网HugowithAlgolia的资料非常有限,经搜索,留存有数篇文章,按照内容操作,部分能梳理生成索引的JSON,但不支持Algolia命令行上传。于是把HugoAlgolia的集成重新梳理了一遍。

KickOff! Algolia

Algolia 是一款快速、可靠和易于使用的搜索服务,旨在提高应用程序和网站的搜索体验,具有先进的搜索和过滤功能,可提供高质量的搜索结果和排名。此外,Algolia 提供了一系列工具和 API,使得搜索和查询数据变得更加容易和灵活。

注册 Algolia

官网地址:https://www.algolia.com,注册帐号后,通过https://www.algolia.com/account/plan/create?from=dashboard创建一个「Free Application」。

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

随后,选择存储的数据中心,可以根据实际地理位置就近进行选择,Algolia 也会根据网络情况推荐选用哪个数据中心,便于提供更快的搜索服务。

中国大陆的网站一般建议选择新加坡 (Singapore) 或香港 (Hong-Kong) 的数据中心。但目前这几个节点都需要联系官方开通,嫌麻烦的话随机选一个就好,实测网络也没有多差。

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

点击「Review」后进入确认界面,接受使用条款并创建即可。一般情况下小网站 Algolia 提供的免费额度是充足的,无需太过担心不够用的问题。

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

获取 Application ID 和 API Key

在 Dashboard 上点击应用,可以获得应用的 Application ID,点击「Search」导航栏后,进入搜索配置,创建一个索引。

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

点击左下角「Setting」菜单,在设置中找到「Team and Access」->「API Keys」,可以获取到对应应用的四个 Key,分别如下:

  • Application ID:应用唯一标识符。它用于在使用 Algolia 的 API 时识别我们的网站。
  • Search-Only API Key:用于在应用或前端代码中使用搜索服务时调用的公共 API 密钥。只可用于搜索查询和向 Insights API 发送数据。
  • Admin API Key:用于创建、更新和删除索引数据。也可以用它来管理 API 密钥。
  • Usage API Key:用于访问 API 用量和日志 Endpoint。

Hugo 集成 Algolia 搜索踩坑 - 2023 版-诺墨的博客站

API Keys

安装 Algolia CLI,配置本地 Profile

Algolia CLI 安装参考官网文档中GET STARTED,我使用的 macOS,操作如下:

brew install algolia/algolia-cli/algolia

在本地添加 Profile 配置并设置为默认

➜ algolia profile add
? Name: example-profile
? Application ID: CW7TR03BVW
? Admin API Key: a57581****************0a74b8
? Set as default profile? No
✓ Profile 'example-profile' (CW7TR03BVW) added successfully.

至此,可以使用 Algolia CLI 进行上传操作了。此外,在 Web 上,你还可以对索引 (Index)、查询建议 (Query Suggestions)、查询分类 (Query Categorization) 等功能进行配置,这有利于在后期搜索中充分展示文档,优化搜索结果,具体细节可以自行在 Web 上进行摸索。

Hugo集成 Algolia

Hugo中集成 Algolia,有多种方式,现网的实践一般是用Hugo的模板引擎生成一个JSON,或使用第三方开发的小工具如hugo-algolia进行集成。由于第三方工具维护问题,多数工具已经跑不起来了,所以还是选择了原厂支持——用 Hugo 的模板引擎生成一个JSON,然后用 Algolia CLI 上传。

使用模板引擎生成 algolia.json

在 Hugo 的配置文件中添加如下模板渲染输出配置(一般是config.toml,我使用的 YAML 所以是config.yaml

outputs:
  home:
    - Algolia

outputFormats:
  Algolia:
    baseName: "algolia"
    isPlainText: true
    mediaType: "application/json"
    notAlternative: true

themes/default/layouts/_default/下创建一个名为list.algolia.json的文件,文件内容如下:

{{- $.Scratch.Add "index" slice -}}
{{- $section := $.Site.GetPage "section" .Section }}
{{- /*  range .Site.AllPages  */ -}}
{{- range where .Site.Pages "IsPage" true -}}
    {{- if and (ne .Type "page") (eq .Kind "page") -}}
        {{- $.Scratch.Add
            "index" (
                dict "objectID" .RelPermalink 
                "hierarchy" (
                    dict "lvl0" .Type
                    "lvl1" .Description
                )
                "type" "content"
                "tags" .Params.Tags
                "content" .Title
                "url" .RelPermalink
                "Weight" .Weight
            ) 
        }}
    {{- end -}}
{{- end -}}
{{- $.Scratch.Get "index" | jsonify -}}

执行hugo命令后会在public目录下生成algolia.json文件,内容为被压缩后的单行有效JSON。其数据结构可以根据网站自身需要进行自定义,通过后期 Index 配置实现多样化的数据结构和展示,在这里贴出的结构是一个比较适合多数网站的结构。

将索引上传至 Algolia

生成algolia.json后,你可以将JSON文件内容通过 Algolia Web 通过文件或手动粘贴 JSON 上传,均可完成索引导入。但使用 Algolia-CLI 时,官方使用了ndjson格式而非json格式,这也是现网除了官方文档,没有一篇 Hugo 相关的文章提及到的坑。

使用algolia objects import命令上传索引,以下是命令参数的释义:

➜  algolia objects import --help
Import objects to the specified index from a file / the standard input.
The file must contains one single JSON object per line (newline delimited JSON objects - ndjson format: https://ndjson.org/).


Usage:
  algolia objects import <index> -F <file> [flags]

Flags:
      --auto-generate-object-id-if-not-exist   如果不存在,自动生成对象ID
  -b, --batch-size int                         指定上传批量大小(默认为1000)。
  -F, --file file                              从文件中读取要导入的记录(使用"-"从标准输入读取)。
  -h, --help                                   帮助

Inherited Flags
      --admin-api-key string    Admin API key,
      --application-id string   Application ID
  -p, --profile string          本地配置好的 Profile
      --search-hosts strings    The list of search hosts as CSV

Examples
...

这里有几处要注意:

  • 考虑 JSON 文件后期会越来越大,指定-b参数时可以设置大一点。
  • --application-id--admin-api-key--profile可以不指定,会默认调用本地默认的Profile,上文已设置过。

JSON?ndJSON?

在执行algolia objects import example-index -F public/algolia.json -b 9999999后,会出现形如Importing records ⡿could not send intermediate batch: Algolia API error [400] body of batch should be an object and not an array near line:1 column:43的错误提示。

查阅 Algolia API 文档https://www.algolia.com/doc/api-reference/api-methods/save-objects/?client=CLI#examples,发现使用了ndjson格式而非json(笔者注:其实上文在 Object Import 时 shell 的帮助提及到过)。

ndJSON知识补漏

[ndJSON](https://normalcoder.com/blog/ndjson/)(New-line Delimited JSON)是一个比较新的标准,本身结构简单,在一个.ndjson后缀文件中,逐行存储一个传统 JSON 对象,使用换行符(0x0A)分隔。其 MIME 类型是application/x-ndjson

以下是一个JSON数组,包含了若干个人的信息,每个人的信息都是一个对象。每个对象都有相同的属性,包括姓名、年龄、婚姻状况、爱好和住址。

[
  {
    "name": "John Smith",
    "age": 30,
    "isMarried": true,
    "hobbies": ["reading", "swimming", "traveling"],
    "address": {
      "street": "123 Main St",
      "city": "New York",
      "state": "NY",
      "zip": "10001"
    }
  },
  {
    "name": "Jane Doe",
    "age": 25,
    "isMarried": false,
    "hobbies": ["hiking", "cooking", "painting"],
    "address": {
      "street": "456 Park Ave",
      "city": "Los Angeles",
      "state": "CA",
      "zip": "90001"
    }
  }
]

相同的数据,使用[ndJSON](https://normalcoder.com/blog/ndjson/)进行存储,其数据表现为:

{"name": "John Smith", "age": 30, "isMarried": true, "hobbies": ["reading", "swimming", "traveling"], "address": {"street": "123 Main St", "city": "New York", "state": "NY", "zip": "10001"}}
{"name": "Jane Doe", "age": 25, "isMarried": false, "hobbies": ["hiking", "cooking", "painting"], "address": {"street": "456 Park Ave", "city": "Los Angeles", "state": "CA", "zip": "90001"}}

JSON 和 nsJSON 相对比,两者区别于数据存储方式不同。JSON通常用于存储单个数据对象,而[ndJSON](https://normalcoder.com/blog/ndjson/)则用于存储多个数据对象,每个对象都以单独的行表示。在处理大量数据时,nsJSON的优势更为明显,因为它可以逐行读取数据,并且不需要将整个文件读入内存中。

将 JSON 转为 ndJSON

无奈,ndjson现网的工具也是少之又少……,几经周折,找到一个 NPM 包json-to-ndjson,可以将JSON转为ndJSON。于是:

npm install -g json-to-ndjson

转换格式

json-to-ndjson public/algolia.json -o public/algolia.ndjson

在此尝试导入索引对象:

➜ algolia objects import example-index -F public/algolia.ndjson -b 999999
✓ Successfully imported 819 objects to drone_cool in 1.827148884s

最后,将上述的过程整理一下,使用一行命令完成 Hugo 网站编译、索引生成、转换和上传,最后将public目录丢到网站部署即可。

rm -fr public/ && hugo && json-to-ndjson public/algolia.json -o public/algolia.ndjson && algolia objects import drone_cool -F public/algolia.ndjson -b 9999999 && rm public/algolia.*

完事儿,收工!

后续

在倒腾集成的过程,想过直接使用模板引擎渲染的方式,直接输出 ndJSON 格式的文件。但 Hugo 的outputFormatsmediaType不支持 “application/x-ndjson”,无奈作罢。

生命的意义在于折腾不止,既然知道了 Hugo 不支持ndJSON渲染,可以给 Hugo 提个 Issue Pull Request 了…

展开阅读全文
加载中
点击引领话题📣 发布并加入讨论🔥
0 评论
0 收藏
0
分享
返回顶部
顶部