108、【Ubuntu】【Hugo】搭建私人博客:搜索引擎

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

背景

上篇 blog
【Ubuntu】【Hugo】搭建私人博客:模糊搜索 Fuse.js(三)

分析了 Hugo PaperMod 搜索的默认配置项,以及支持用户可自定义的搜索配置项,下面继续

搭建私人博客

OK,下面来看 Fuse 搜索引擎实例的创建

这里面的两个参数:

  • data:从 index.json 里加载的文章数组
  • options:上面构建好的用户自定义配置对象

此时 new Fuse(...) 会遍历 data 中的每篇文章,并对 keys 指定的字段建立倒排索引 ,然后返回一个可复用的搜索对象,之后就可以通过 let results = fuse.search("ssh tunnel"); 这样返回匹配的文章列表(按相关性排序)

对关键字 keys 指定的字段建立倒排索引是搜索引擎(包括 Fuse.js,Elasticsearch,Lucene 等)高效查找数据的核心原理,下面来详细分析下

正排索引

在分析倒排索引之前,先来看下正排索引,做个对比

假如有一本书,目录是这样的

标题 ID 内容
1 苹果很好吃
2 香蕉和苹果都是水果
3 大家喜欢吃苹果

这种格式就是正排索引,按标题索引内容,如果想知道第 2 篇文章写了什么,查一下标题 ID 就可以知道,但如果想知道哪些文章里有关键词【苹果】,就得逐篇扫描所有内容,那么效率就很低,时间复杂度 O(n)

倒排索引

OK,下面再来看上面提到的倒排索引,之前正排索引是【标题】->【内容】,现在倒排索引是【关键词】->【标题】,倒排索引会把上面举例的数据转换成下面这样:

关键词 标题 ID
苹果 1,2,3
很好吃 1
香蕉 2
水果 2
喜欢 3

可以看到,在倒排索引中,当用户搜索【苹果】关键词,搜索引擎直接查倒排表,就可以立马找到结果 [1,2,3],瞬间返回,而不需要扫描全文,时间复杂度从 O(n) 降到 O(log n),快的飞起

OK,回到 fastsearch.js,首先定义了关键字段 keys: ['title', 'summary', 'content'],Fuse.js 在初始化时(new Fuse(data, options)),会遍历每一篇文章(data 中的每个对象),然后对 keys 中指定的每一个字段进行分词,并把每个词映射到包含它的文档 ID,举个例子,假设有两篇文章

javascript 复制代码
[
  {
    id: 1,
    title: "SSH 隧道教程",
    summary: "教你如何使用 SSH 反向隧道"
  },
  {
    id: 2,
    title: "Git 使用指南",
    summary: "Git 是分布式版本控制系统"
  }
]

Fuse.js 会对 title 和 summary 建立倒排索引(简化版)如下

词 文档 ID
ssh 1
隧道 1
教程 1
使用 1,2
git 2
分布式 2
版本控制 2

实际上,Fuse.js 还支持模糊匹配(比如 sssh 也能匹配 ssh),所以它的索引比传统倒排更复杂,但核心思想是一样的

OK,最后再来对比下传统搜索引擎和 Fuse.js 的倒排索引

特性 传统引擎(比如 Elasticsearch) Fuse.js
索引存储 磁盘/内存,支持持久化 纯内存,页面关闭就消失
分词 支持中文分词,同义词等 默认按空格/字母分词(对中文效果一般)
模糊匹配 需额外配置 内置强大模糊算法(基于 Levenshtein 距离)
适用场景 大型网站,海量数据 小型静态站(< 1000 篇文章)

Fuse.js 的倒排索引其实是为模糊搜索优化的内存结构,不完全等同于数据库的倒排,但思想一致

对 keys 指定的字段建立倒排索引,就是把文章中指定字段(比如标题,摘要等)中的每个词进行分类,预先记录这个词会出现在哪些文章里,这样搜索时就能秒级定位结果,而不用一片片翻,这是所有现代搜索引擎(从 Google 到博客搜索框)高效工作的基石


OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【Ubuntu】【Hugo】搭建私人博客:搜索功能(五)

相关推荐
程序员-Benothing2 小时前
Vim编辑器从入门到精通:模式、快捷键、配置、插件
linux·运维·服务器
‎ദ്ദിᵔ.˛.ᵔ₎2 小时前
linux 进程信号 (上)
linux·服务器
15Moonlight2 小时前
Linux网络(02):Socket 编程 UDP
linux·网络·udp
wuminyu3 小时前
ForkJoinPool窃取线程在扫描其他WorkQueue时的随机采样算法与Phase线程挂起唤醒机制解析
java·linux·c语言·jvm·c++
liulilittle3 小时前
Linux 下 select 测试函数
linux·服务器·网络·数据库·c++·select·c
DongQiShanRen3 小时前
玄龙(上):TICK 主循环——意识心跳怎么跳
linux·jvm·数据库·人工智能·数据挖掘·rust
小此方3 小时前
Linux网络(二十一):深入理解 TCP 异常处理:网线断开、Keepalive 保活机制与 Linux 内核传输层协议源码剖析
linux·网络·tcp/ip
pride.li4 小时前
Python 安装
linux·python·ubuntu
笔墨登场说说4 小时前
centos 8 使用 kafka_2.13-4.3.1.tgz 安装kafka
linux·kafka·centos
luo_guibin4 小时前
Linux系统下OpenSSL升级全流程,新旧版本切换
linux·运维·服务器