IkeqIkeq

The whole problem with the world is that fools and fanatics are always so certain of themselves, but wiser people so full of doubts.

May 17, 20191296 words in 6 min


Inside 主题集成 Algolia 搜索

No matter the use case, we aim to solve our customer’s toughest challenges and help them create meaningful digital experiences.

老生常谈,Algolia 成立于 2012 年,致力于为企业和个人提供消费级的搜索服务,目前非商业用途的个人项目免费使用

Algolia

本文分 3 个部分介绍 Inside 主题如何集成 Algolia:

  • 上传搜索数据
  • 配置 Inside 主题
  • 优化 Algolia 返回结果(可选)

上传搜索数据

使用之前,需要去官网注册(支持 Github 授权登录),登录后进入 dashboard 页面,然后:

  1. 新建 Indices(本例中叫 demo);
  2. 选择并上传本地生成的 json 文件。

本地生成的 json 文件指,主题先配置为本地搜索,然后执行 hexo g,会在 api 文件夹生成 c2VhcmNo.json 文件(c2VhcmNosearch 的 base64 编码),选择并上传即可。

配置 Inside 主题

为了保证扩展性,以不变应万变(也可能是懒),主题采取通用配置来支持集成第三方搜索,从技术角度讲,主题提供了一套机制,可以让你配置一个完整的 HTTP 请求。

以 Algolia 为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
search:
adapter:
# 分页
per_page: 10
# LOGO 图,可选
logo: //cdn.worldvectorlogo.com/logos/algolia.svg
# 请求对象
request:
url: https://{APPLICATION_ID}-dsn.algolia.net/1/indexes/{INDEX}/query
method: post
# 字符串差值 :query, :per_page, :current
body: '{"query":":query","hitsPerPage":":per_page","page":":current"}'
headers:
X-Algolia-API-Key: {API_KEY}
X-Algolia-Application-Id: {APPLICATION_ID}
Content-Type: application/json; charset=UTF-8

{APPLICATION_ID}{INDEX}{API_KEY} 需要替换为具体的值。

request 对象有4个参数:

  • url: 搜索接口
  • method: 请求方式,GET or POST,不区分大小写
  • headers: 请求头,视搜索接口而定
  • body: 请求参数,格式视搜索接口和 Content-Type 而定,支持字符串差值如下:
差值 描述
:query 搜索的字符串
:per_page 分页大小
:current 当前页码

至此,我们尝试搜索,接口已经可以正常返回了,

Algolia response original

但需要显示到前端,还需要配置 keys (request.adapter.keys),其作用是能够让主题从接口返回的数据中正确获取到所需的值,见下表:

key 描述
data 搜索结果的文章列表
current 当前页码
total 总页数
hits 总条数
time 耗时

对于上图的返回结果而言,配置如下:

1
2
3
4
5
6
keys:
data: hits
current: page
total: nbPage
hits: nbHits
time: processingTimeMS

刷新页面后重新搜索,前端已经可以显示结果了,但似乎还没完,显示出来的是整篇文章,且没有关键词高亮,我们来看一眼返回结果,

Algolia hits

数据结构大致如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"hits": [
{
"title":"",
"date":"",
"content":"",
"_highlightResult": {
"title": {
"value":""
},
"content": {
"value":""
}
}
}
]
}

hits[] 中的每一项除了 _highlightResult 字段外,其他的都是我们上传的原始数据,Algolia 不会修改原始数据,而是将匹配结果放在 _highlightResult 字段中。主题默认取原始数据的 titlecontent 字段(因为原始数据是主题生成的,所以知道怎么取),为了应对上述的这种情况,提供两个额外的 key

key 描述
title 具体某一条的标题字段
content 具体某一条的内容字段

修改配置如下:

1
2
3
4
5
6
7
8
keys:
data: hits
current: page
total: nbPage
hits: nbHits
time: processingTimeMS
title: _highlightResult.title.value
content: _highlightResult.content.value

至此,已经可以看到关键词高亮了,不过显示整篇文章的问题仍未解决,_highlightResult 是 Algolia 提供的一个叫做 Highlighting 的功能,很遗憾不支持截取字符串,但还有一个类似的功能叫做 Snippeting 可以达到限制字符串长度的效果,修改 request.body

1
2
request:
body: '{"query":":query","hitsPerPage":":per_page","page":":current","attributesToSnippet":["content:100"]}'

json 对象多了 "attributesToSnippet":["content:100"],即内容限长 100 个字符,再次查看请求结果:

Algolia Snippeting

多了 _snippetResult 字段,接着修改 keys

1
2
3
4
5
6
7
8
keys:
data: hits
current: page
total: nbPage
hits: nbHits
time: processingTimeMS
title: _highlightResult.title.value
content: _snippetResult.content.value

再次搜索,完美。

优化 Algolia 返回结果(可选)

也许你发现,按如上步骤配置完后,接口返回的结果有大量用不到的数据,有 2 个解决方案:

  1. 配置 Algolia
  2. 参数方式

参数方式

如果你疲于配置 Algolia,可以采取第 2 个方案,修改 request.body

1
2
request:
body: '{"query":":query","hitsPerPage":":per_page","page":":current","attributesToSnippet":["title:100","content:100"],"attributesToHighlight":[],"attributesToRetrieve":["*","-content"]}'

多了如下参数:

1
2
3
4
5
6
{
// 将 title 和 content 放一起,可以不返回整个 _highlightResult对象
attributesToSnippet: ["title:100","content:100"],
attributesToHighlight: [], // 不返回 _highlightResult
attributesToRetrieve: ["*","-content"] // 原始数据不返回 content
}

接着修改 keys

1
2
3
4
5
6
7
8
keys:
data: hits
current: page
total: nbPage
hits: nbHits
time: processingTimeMS
title: _snippetResult.title.value
content: _snippetResult.content.value

再次查看请求结果:

Algolia optimized response

完美!

配置 Algolia

上面涉及的所有 Algolia 参数,也可以直接配置 Algolia index,从而减少请求参数,此外还有很多无法通过参数实现的功能,如排序(Sorting)、容错(Typo Tolerance)等,这里就不做介绍了 ¯\_(ツ)_/¯

Buy me a cup of milk 🥛.