Node-js用FlexSearch给Hexo添加极速全站搜索

发布时间 2024-01-03 21:57:00作者: CarlZeng
title: Node.js用FlexSearch给Hexo添加极速全站搜索
tags: [Node.js,node,Javascript,Debian,Linux,FlexSearch,搜索]
新版原文: https://www.carlzeng.top/search?q=Node.js用FlexSearch给Hexo添加极速全站搜索
版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
date: 2023-12-16 11:21:33
categories: Node.js

全站检索,全站内容搜索之自定义flexsearch实现【已上线,V0.0.2测试中】

引用拓展:大文本,多文本,多文件系统级文本字符低资源消耗高效急速搜索

有什么用

许多网站或博主都苦于站内搜索的功能缺陷,使用特定搜索引擎的搜索就得要忍耐特定搜索引擎收录文章的速度(搜索内容受局限于特定的旧版本),自带的搜索消耗太多资源,速度慢,html的静态站点无法使用数据库的搜索.....

介绍flexsearch(这个可以轻易从加速浏览器中搜索获取最新版信息)不是本文的重点,Node.js的入门在我上一篇文章是重点:Node.js开发环境及应用实例

本文主要分享Node.js + FlexSearch 实际应用在本站(hexo)中全文搜索实现,用于我在Carl Notes 博客园中同步发布文章时“相关内容”章节的实现(iframe方法,由于博客园禁止了在文章中添加javascript代码,导致ajax跨域去cdn站点里面获取相关内容失败,这是一个巨坑,坑了我好2-3天)

使用FlexSearch对于内容的搜索是很有帮助是它的强项,Hexo对于相关内容的实现也不错:用插件中的算法去比对我目前300多篇文章彼此之间的联系,关键字,权重等等。详细见 Hello hexo中关于相关文章 related_posts 如何增加到10条?的章节介绍

但hexo(我目前的版本)在全站搜索的实现是潦草了,不知道最新版有没有改进‘全站检索‘

hexo: 6.3.0                                                                                                
hexo-cli: 4.3.1        
# 我的hexo待更新啊。。。懒。。。新版吸引力不足。。。
node: 20.10.0 

目前版本的hexo是通过ajax请求把search.xml,比如这样的 search.xml下载到内存中,然后通过js来在本地浏览器搜索和匹配(优点:UI界面很好看)可是,可是我的文件截止目前为止已经3M了!

可是这对于WEB太大了,我用最快的CDN线路,最快也要花费350ms+才能下载到本地,一般的cdn都要1s+这对于用户是很要命的。这是在方案级别上的缺陷。

怎么用

使用了目前(2023年12月中旬)是最新版本的FlexSearch

最简单的使用:

//申明三种情况的应用,从简单到复杂Index,Document和Worker;先理解最简单的Index
const {Index, Document, Worker} = require("flexsearch");

//指定Index索引的参数,可以很复杂,先从默认最简单的开始
const index = new Index({
	tokenize: "reverse",
	depth: 2,
	minlength: 3
});

//添加源内容,比如多个文件,数据库。。。
index.add(post.title, post.title + post.source + post.content)

//搜索,参数限定了11个结果
var searchRes = index.search(req.query.q, 11);

相关内容

实现方法/过程

基础学习建议实践走一下流程:https://expressjs.com/en/starter/installing.html
(在试一试列子https://expressjs.com/en/starter/examples.html)

Express, jade相关

#主程序文件app.js,文件内容节选:
var appSearchRouter = require('./routes/appsearch'); 
#这里引用的新建的文件appserach.js

app.use('/appsearch', appSearchRouter); #这个注册appsearch可以按需修改名称

#其他的文件内容都按默认的列子https://expressjs.com/en/starter/examples.html
#生成的默认的文件列表即可。文档很清晰,友好。




#appsearch.js文件内容Express,  jade相关:
var express = require('express');
var router = express.Router();


res.render('searchTemplate', { searchResults: arrSearchRes });
#对应下面的searchTemplate.jade文件内容:
#然后在views目录下面添加searchTemplate.jade文件,文件内容:
doctype html
html
    head
        title= title
        link(rel='stylesheet', href='/stylesheets/style.css')
    body
        .popup.search-popup
            .search-result-container
                .search-stats 找到 #{searchResults.length} 个搜索结果
                hr
                ul.search-result-list
                    each result in searchResults
                        li
                            a(href=result.doc.url, class="search-result-title", data-pjax-state="")
                                mark.search-keyword= result.doc.title
                            a(data-pjax-state="" href=result.doc.url)
                                p.search-result= result.doc.subcontent

FlexSearch相关

#appsearch.js文件内容中FlexSearch相关:
const {Index, Document, Worker} = require("flexsearch");


//const document
const index = new Document({
    tokenize: "reverse",
    minlength: 3,
    document: {
        id: "id",
        index: [
            // { 没必要用title在搜索一遍,即便效率极高
            //     field: "title",
            //     tokenize: "forward"
            // },
            {
                field: "content",
                context: {
                    // depth: 2,
                    // resolution: 3
                },
                tokenize: "reverse"
            }],
        store: ["title", "updated", "date", "source", "content"]
    }
});

// load posts from a file 加载hexo的数据库文件
var pages = JSON.parse(require('fs').readFileSync(path.join(__dirname, '../../blog/db.json')).toString()).models.Post;

// add posts to the index
pages.forEach(post => {
    var idx = 1;
    // index.add(post.title, post.title + post.source + post.content)
    index.add({
        id: post.title,
        title: post.title,
        "title": post.title,
        "updated": post.updated,
        "date": post.date,
        "source" : post.source,
        "related_posts": post.related_posts,
        content: post._content
    })
    idx ++;
});


var arrSearchRes = index.search(req.query.q, {
        limit: 11,
        enrich: true
    });

注意避坑事项1

// create the index
// var FlexSearch = require("flexsearch");
// var index = FlexSearch.create();

这是flexsearch的旧版本语法,Google了一圈,国内的(中文内容)很多例子都是这个旧版本的,旧版本是无法运行的,各种报错,连ChatGpt3.5都不会解释,问题出现在哪里了。(这告诉我们版本是多么重要的)

注意避坑事项2

jade模版也是很好用的,缩紧语法。很简易地将HTML生成。制作过程中,也能很容易地使用转换工具,将现成的HTML转化为jade(或者Pug)的模版,比如:https://tool.fiaox.com/template-html-pug/

模版转化,模版转换Html to Pug

添加CORS跨站支持

res.setHeader("Access-Control-Allow-Origin","*");
res.setHeader(
    "Access-Control-Allow-Methods",
    "PUT, GET, POST, DELETE, HEAD, PATCH"
);

Docker中Production发布

Docker中发布是我首选项,高效简单易管理。

发布文件列表:

​ 复制所有文件夹除了node_modules

#进入nodejs容器,启动bash(用于执行node程序们)
> docker exec -it nodejs bash

#直接运行node程序:
> node /home/app/blogsearch/bin/www
#或者进入目录在运行
> cd h.........
# [继续阅读](https://carlzeng.top/202312161121.html)
 [请点击访问最新版内容](https://carlzeng.top/202312161121.html)