惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

SecWiki News
SecWiki News
I
InfoQ
The Cloudflare Blog
人人都是产品经理
人人都是产品经理
博客园 - Franky
T
Tailwind CSS Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
博客园_首页
罗磊的独立博客
V
V2EX
李成银的技术随笔
大猫的无限游戏
大猫的无限游戏
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
T
True Tiger Recordings
Vercel News
Vercel News
Cyberwarzone
Cyberwarzone
Cisco Talos Blog
Cisco Talos Blog
F
Fox-IT International blog
D
Darknet – Hacking Tools, Hacker News & Cyber Security
M
Microsoft Research Blog - Microsoft Research
Know Your Adversary
Know Your Adversary
爱范儿
爱范儿
The Register - Security
The Register - Security
G
Google Developers Blog
The Hacker News
The Hacker News
Malwarebytes
Malwarebytes
S
Securelist
博客园 - 三生石上(FineUI控件)
Jina AI
Jina AI
T
Threat Research - Cisco Blogs
T
The Exploit Database - CXSecurity.com
S
SegmentFault 最新的问题
博客园 - 叶小钗
F
Fortinet All Blogs
Apple Machine Learning Research
Apple Machine Learning Research
宝玉的分享
宝玉的分享
博客园 - 聂微东
T
Threatpost
博客园 - 【当耐特】
D
Docker
P
Privacy & Cybersecurity Law Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
G
GRAHAM CLULEY
V
Visual Studio Blog
C
Cisco Blogs
IT之家
IT之家
S
Security Archives - TechRepublic
Latest news
Latest news
阮一峰的网络日志
阮一峰的网络日志

元视角

Terraform 极简入门:从 AWS-CLI 到基础设施即代码(IaC) - 元视角 .NET 生态下的 Agent 框架选型:从 ReAct 到原生推理 - 元视角 从「能用」到「好用」:LLM 流式响应实现方式的探索之路 - 元视角 当我用 2000 条聊天记录,让 AI 为我画一幅自画像 - 元视角 基于 Supabase 的 AI 应用开发探索 - 元视角 盛世幻象:从荔枝看盛唐的兴衰 - 元视角 观影 - 元视角 听歌 - 元视角 个人作品 - 元视角 站点统计 - 元视角 读书 - 元视角 微博 × MCP:社交媒体新玩法解锁 - 元视角 四点钟海棠花未眠 - 元视角 留言 - 元视角 Semantic Kernel × MCP:智能体的上下文增强探索 - 元视角 命运、偏见与自由:《魔童之哪吒闹海》的终极抗争 - 元视角 基于 K-Means 聚类分析实现人脸照片的快速分类 - 元视角 容器技术驱动下的代码沙箱实践与思考 - 元视角 温故而知新:后端通用查询方案的再思考 - 元视角 浅议 CancellationToken 在前后端协同取消场景中的应用 - 元视角 Semantic Kernel 视角下的 Text2SQL 实践与思考 - 元视角 走走停停,允许一切发生 - 元视角 关于 ChatGPT 的流式传输,你需要知道的一切 - 元视角 从抖音看见世界的参差 - 元视角 俯仰之间:五一小长假出行记 - 元视角 RAG 的是与非、Rewrite 和 Rerank - 元视角 《你想活出怎样的人生》与宫崎骏的自我和解 - 元视角 使用 EFCore 和 PostgreSQL 实现向量存储及检索 - 元视角 基于 LLaMA 和 LangChain 实践本地 AI 知识库 - 元视角 使用 llama.cpp 在本地部署 AI 大模型的一次尝试 - 元视角 如何为 Git 配置多个 SSH Key - 元视角 C# 使用 LibUsbDotNet 实现 USB 设备检测 - 元视角 基于 C# 实现样式与数据分离的打印方案 - 元视角 基于 SVG 的图形交互方案实践 - 元视角 前端视频播放技术概览 - 元视角 你好,千寻小姐 - 元视角 温故而知新,再话 Python 动态导入 - 元视角 后 GPT 时代,NLP 不存在了? - 元视角 视频是不能 P 的系列:使用 Milvus 实现海量人脸快速检索 - 元视角 GDI+下字体大小自适应方案初探 - 元视角 小爱音箱集成 ChatGPT 的不完全教程 - 元视角 程序员视角下的三体世界随想 - 元视角 关于 Docker 容器配置信息的渐进式思考 - 元视角 在 Docker 容器内集成 Crontab 定时任务 - 元视角 为你的服务器集成 LDAP 认证 - 元视角 似花还似非花 - 元视角 视频是不能 P 的系列:使用 Dlib 实现人脸识别 - 元视角 浅议分布式链路追踪与日志的整合 - 元视角 关于 Git 大文件上传这件小事 - 元视角 .NET 进程内队列 Channel 的入门与应用 - 元视角 使用 Fody 实现 .NET 的静态编织 - 元视角 .NET Core + ELK 搭建可视化日志分析平台(下) - 元视角 聊一聊前端图片懒加载背后的故事 - 元视角 杂感·七月寄望 - 元视角 支持外部链接跳转的 Vue Router 扩展实现 - 元视角 视频是不能 P 的系列:OpenCV 和 Dlib 实现表情包 - 元视角 不得不说的 ASP.NET Core 集成测试 - 元视角 再议 DDD 视角下的 EFCore 与 领域事件 - 元视角 Vue.js 前端项目容器化部署实践极简教程 - 元视角 再见,人间四月天 - 元视角 Python 图像风格化迁移助力画家梦想 - 元视角 在 Vue.js 中使用 Mock.js 实现接口模拟 - 元视角 利用 ASP.NET Core 中的标头传播实现分布式链路追踪 - 元视角 读《一个叫欧维的男人决定去死》 - 元视角 利用 gRPC 实现文件的上传与下载 - 元视角 七种武器:延迟队列的原理和实现总结 - 元视角 gRPC 流式传输极简入门指南 - 元视角 烟波梦影,从天国王朝到刺客信条 - 元视角 关于 - 元视角 Envoy 集成 Jaeger 实现分布式链路追踪 - 元视角 浅议非典型 Web 应用场景下的身份认证 - 元视角 gRPC 借助 Any 类型实现接口的泛化调用 - 元视角 分布式丛林探险系列之 Redis 集群模式 - 元视角 写在冬阳升起以前 - 元视角 分布式丛林探险系列之 Redis 主从复制模式 - 元视角 通过 Python 预测 2021 年双十一交易额 - 元视角 从《失控玩家》中得到的启示 - 元视角 gRPC 搭配 Swagger 实现微服务文档化 - 元视角 SSL/TLS 加密传输与数字证书的前世今生 - 元视角 夕雾花园:从建筑中读出的爱情和美学 - 元视角 使用 Python 自动识别防疫健康码 - 元视角 你不可不知的容器编排进阶技巧 - 元视角 ASP.NET Core 搭载 Envoy 实现 gRPC 服务代理 - 元视角 再话 AOP,从简化缓存操作说起 - 元视角 洗衣随想曲 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务身份认证(JWT) - 元视角 浪客剑心:一曲幕末时代的挽歌 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的监控预警 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的负载均衡 - 元视角 ASP.NET Core 搭载 Envoy 实现微服务的反向代理 - 元视角 ASP.NET Core gRPC 打通前端世界的尝试 - 元视角 EFCore 实体命名约定库:EFCore.NamingConventions - 元视角 ASP.NET Core gRPC 集成 Polly 实现优雅重试 - 元视角 ASP.NET Core gRPC 健康检查的探索与实现 - 元视角 ASP.NET Core gRPC 拦截器的使用技巧分享 - 元视角 SnowNLP 使用自定义语料进行模型训练 - 元视角 假如时间有温度 - 元视角 使用 HttpMessageHandler 实现 HttpClient 请求管道自定义 - 元视角 ABP vNext 的实体与服务扩展技巧分享 - 元视角 ABP vNext 对接 Ant Design Vue 实现分页查询 - 元视角
原生 JavaScript 实现 Hexo 博客推荐功能 - 元视角
2020-06-08 · via 元视角

有时候,我不禁在想,我们到底处在一个什么样的时代呢?而之所以会有这样的疑问,则是因为我们的习惯在不断地被这个时代向前推进,就像我用了两年多的魅蓝 Note6 屏幕出现了问题,扫视了一圈新手机,居然再找不出一款带实体键的手机,刘海屏、水滴屏、破孔屏、异形屏、曲面屏等等简直令人眼花缭乱,唯独没有一款让我感到熟悉的非全面屏手机。做软件的时候,会不明白那些似是而非的定制需求的差异,可为什么偏偏到了硬件的时候,大家就能被迫适应这些越来越同质化的东西呢?也许有和我一样怀念非全面屏的人,可对于这个时代而言,一切都好像无足轻重,喜欢魅族对产品的设计,喜欢小而美的不妥协,可当大家都越来越相似的时候,也许,是因为我们终于都长大了吧,而怀念则是一种可有可无、甚至有一点多余的东西。在被告知一切向前看的路上,我们能拥有、用留住的东西本就不多,可偏偏我们就在给世间一切东西,努力刻上时间的温度,经历着花繁叶茂,经历着落叶归根。

写博客,曾经是件很有意思的事情,透过网页去读每条留言背后的人,常常令你产生神交已久的感觉,即便网络如此发达的今天,让一个人失散,无非是动动手指拉黑、删除。陈星汉先生有一款游戏作品叫做《风之旅人》,游戏里的玩家依靠某种微弱的信号相互联系,而一旦失散彼此,将永远迷失在浩瀚无际的沙海里,你说,这是不是有人生本身的意味在里面呢?再后来 140 个字符的微博开始流行,而这些沉迷在博客时代里的人们,或固执地继续在博客这一方天地里挥洒,或搭乘移动互联网的 “高铁” 通往新的彼岸。有人这样比喻朋友圈和微博,说朋友圈装饰别人梦境的月亮,而微博则是装饰自己梦境的镜子。其实呢,在隐私问题基本荡然无存的今天,我们都只是在装饰资本的 “窗户” 吧!

曾经运营过一段时间的微信公众号,最后发觉还是博客的载体更适合自己,虽然这些年没少为博客投入 “钱财”,在博客时代一去不复返的时间禁锢里,通过博客来盈利的想法堪堪聊以自慰,更不必说后来流行起来的 “在线教育” 和 Vlog。有人说,靠工资是没有办法挣到钱的,挣钱要靠这些 “睡后收入”,可当一件事物风头正盛的时候,彼时的你不足以追逐这一切的时候,这种感觉该如何言明呢?大概就像你在最落魄的时候,遇到一生中最想要保护的那个人一样,这听起来多少有点讽刺,人在不成熟的时候,总是后知后觉,可有一天真成熟了,再难有那时的运气或是豪气。所以呢,继续写下去吧,也许有一天,当你看着从前写的幼稚的文字,或哭或笑皆可入题,这不就是 “嬉笑怒骂,皆成文章” 了吗?

果然,一不小心又扯远了。虽然说博客平时没什么流量,可像搜索引擎优化(SEO)、前端构建(CI/CD)、PWA 等等这些东西倒是有所钻研,提高博客访问量的方式除了增加搜索引擎里的权重和曝光率以外,其实,还有一种方式就是减少跳出时间。换句话说,访客在你博客里停留的时间越长,这意味着你有更多的内容可以被对方访问到,所以,增加内链是一个不错的思路。最直接的方式,就是在每篇博客结束以后推荐相关的博客供访客继续阅读。之前曾经尝试过像 hexo-recommended-posts 这样的插件,坦白说效果不是特别好,因为有时候加载这些站外的内容,导致博客页面打开的时候异常卡顿,所以,我们今天将采用原生的 JavaScript 来为 Hexo 实现博客推理功能,希望对大家有所启发。

首先,我们来说说原理,推荐系统一般是需要一部分量化的指标来表征不同内容的相关性的。譬如通过 TF-IDF 来计算文本的相似度,通过公共词袋中的词频构造向量再配合余弦公式来计算,通过 TextRank 这类借鉴 PageRank 思想的方法来计算等等。这里呢,我们不采用这些方法来实现,主要是考虑到 200 篇左右的博客,两两计算相似度特别耗费时间,对于 Hexo 这种静态博客而言,我们还是应该节省生成静态页面的时间,虽然这部分时间都是 Travis CI 去跑的(逃……。我们采用的方案是基于标签和日期的推荐方式,即根据当前文章的标签筛选相同标签的文章,根据当前文章的日期筛选相同日期的文章。有了这两种策略,配合 Hexo 中提供的全局变量,我们可以很容易地编写出下面的代码:

<%
    function shuffle(a) {
        for (let i = a.length; i; i--) {
            let j = Math.floor(Math.random() * i);
            [a[i - 1], a[j]] = [a[j], a[i - 1]];
        }
        return a;
    }

    function recommended_posts(page, site, limit = 5) {
        page.tags = page.tags || []
        if (page.tags.length == 0) return [];
        let pageTags = page.tags.map(x=>x.name);
        let sitePosts = site.posts.toArray().map(x=> {
            return {tags:x.tags.toArray().map(y=>y.name), title:x.title, permalink:x.permalink, date:x.date}
        });
        let relatedPosts = pageTags.map(x=>sitePosts.filter(y=>y.title != page.title  && (y.tags.indexOf(x) != -1 || y.date.format('MM/DD') == page.date.format('MM/DD')))).reduce((prev,next)=>{
            return prev.concat(next);
        },[]);
        return shuffle(Array.from(new Set(relatedPosts))).slice(0, limit);
    }
%>
<% var post_list = recommended_posts(page, site, config.recommended_posts.limit) %>
<% if(post_list.length > 0 && config.recommended_posts.enable) { %>
<div class="recommended_posts">
    <h1><%= config.recommended_posts.title %></h1>
    <ul>
        <% post_list.forEach(function(link) { %>
        <li><a href="<%= link.permalink %>"><%= link.title %></a></li>
        <% }) %>
    </ul>
</div>
<% } %>

代码非常直白,按照标签和日期两种策略筛选出文章,打乱顺序后从中提取出若干个返回,而剩下的工作,就是将其渲染到页面中。在这里,博主单独定义了一个模板文件,所以,我们在博客的适当位置引入即可,博主是放在博客结束以后的位置:

<div class="post-content" id="post-content" itemprop="postContent">
    <%- post.content %>
    <%- partial('post/recommended_posts') %>
</div>

最终实现的效果如下图所示:

本文实现的相关文章推荐功能 本文实现的相关文章推荐功能

当然,当你看到这篇博客的时候,你已经看到博主为你推荐的内容了,是否有兴趣继续读下去呢?如果这样的话,就说明这两个内容是相关的。而基于日期的推荐,即所谓的“去年今日”,它本身的相关性可能并不强,但可以让你产生一种强烈的对比感,原来,这一天我是这样度过的啊。好了,这就是这篇博客的内容啦,晚安~