Files
pages/2024/10/01/suggest.html
2026-02-08 12:35:58 +00:00

396 lines
32 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<!-- Begin Jekyll SEO tag v2.8.0 -->
<title>如何给博客添加相似文章推荐功能 | Mayx的博客</title>
<meta name="generator" content="Jekyll v3.9.5" />
<meta property="og:title" content="如何给博客添加相似文章推荐功能" />
<meta name="author" content="mayx" />
<meta property="og:locale" content="zh_CN" />
<meta name="description" content="看来向量数据库的作用有很多啊……" />
<meta property="og:description" content="看来向量数据库的作用有很多啊……" />
<meta property="og:site_name" content="Mayx的博客" />
<meta property="og:type" content="article" />
<meta property="article:published_time" content="2024-10-01T00:00:00+08:00" />
<meta name="twitter:card" content="summary" />
<meta property="twitter:title" content="如何给博客添加相似文章推荐功能" />
<meta name="google-site-verification" content="huTYdEesm8NaFymixMNqflyCp6Jfvd615j5Wq1i2PHc" />
<meta name="msvalidate.01" content="0ADFCE64B3557DC4DC5F2DC224C5FDDD" />
<meta name="yandex-verification" content="fc0e535abed800be" />
<script type="application/ld+json">
{"@context":"https://schema.org","@type":"BlogPosting","author":{"@type":"Person","name":"mayx"},"dateModified":"2024-10-01T00:00:00+08:00","datePublished":"2024-10-01T00:00:00+08:00","description":"看来向量数据库的作用有很多啊……","headline":"如何给博客添加相似文章推荐功能","mainEntityOfPage":{"@type":"WebPage","@id":"/2024/10/01/suggest.html"},"publisher":{"@type":"Organization","logo":{"@type":"ImageObject","url":"https://avatars0.githubusercontent.com/u/17966333"},"name":"mayx"},"url":"/2024/10/01/suggest.html"}</script>
<!-- End Jekyll SEO tag -->
<link rel="canonical" href="https://mabbs.github.io/2024/10/01/suggest.html" />
<link type="application/atom+xml" rel="alternate" href="/atom.xml" title="Mayx的博客" />
<link rel="alternate" type="application/rss+xml" title="Mayx的博客(RSS)" href="/rss.xml" />
<link rel="alternate" type="application/json" title="Mayx的博客(JSON Feed)" href="/feed.json" />
<link rel="stylesheet" href="/assets/css/style.css?v=1770554153" />
<!--[if !IE]> -->
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
<!-- <![endif]-->
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="Mayx的博客" />
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
<link rel="pingback" href="https://webmention.io/mabbs.github.io/xmlrpc" />
<link rel="preconnect" href="https://summary.mayx.eu.org" crossorigin="anonymous" />
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
<link rel="me" href="https://github.com/Mabbs" />
<script src="/assets/js/jquery.min.js"></script>
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery-ajaxtransport-xdomainrequest/1.0.3/jquery.xdomainrequest.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/respond.js/1.4.2/respond.min.js"></script>
<![endif]-->
<script>
var lastUpdated = new Date("Sun, 08 Feb 2026 20:35:53 +0800");
var BlogAPI = "https://summary.mayx.eu.org";
</script>
<script src="/assets/js/main.js"></script>
<!--[if !IE]> -->
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async="async" src="https://www.googletagmanager.com/gtag/js?id=UA-137710294-1"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'UA-137710294-1');
</script>
<script src="/assets/js/instant.page.js" type="module"></script>
<!-- <![endif]-->
</head>
<body>
<!--[if !IE]> --><noscript><marquee style="top: -15px; position: relative;"><small>发现当前浏览器没有启用JavaScript这不影响你的浏览但可能会有一些功能无法使用……</small></marquee></noscript><!-- <![endif]-->
<!--[if IE]><marquee style="top: -15px; position: relative;"><small>发现当前浏览器为Internet Explorer这不影响你的浏览但可能会有一些功能无法使用……</small></marquee><![endif]-->
<div class="wrapper">
<header class="h-card">
<h1><a class="u-url u-uid p-name" rel="me" href="/">Mayx的博客</a></h1>
<img src="https://avatars0.githubusercontent.com/u/17966333" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
<p class="p-note">Mayx's Home Page</p>
<form action="/search.html">
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." />&#160;<input type="submit" value="搜索" />
</form>
<br />
<p class="view"><a class="u-url" href="/Mabbs/">About me</a></p>
<ul class="downloads">
<li style="width: 270px; border-right: none;"><a href="/MayxBlog.tgz">Download <strong>TGZ File</strong></a></li>
</ul>
</header>
<section class="h-entry">
<small><time class="date dt-published" datetime="2024-10-01T00:00:00+08:00">1 October 2024</time> - 字数统计2832 - 阅读大约需要11分钟 - Hits: <span id="/2024/10/01/suggest.html" class="visitors">Loading...</span></small>
<h1 class="p-name">如何给博客添加相似文章推荐功能</h1>
<p class="view">by <a class="p-author h-card" href="//github.com/Mabbs">mayx</a></p>
<div id="outdate" style="display:none;">
<hr /><p>
这是一篇创建于 <span id="outime"></span> 天前的文章,其中的信息可能已经有所发展或是发生改变。
</p>
</div>
<script>
daysold = Math.floor((new Date().getTime() - new Date("Tue, 01 Oct 2024 00:00:00 +0800").getTime()) / (24 * 60 * 60 * 1000));
if (daysold > 90) {
document.getElementById("outdate").style.display = "block";
document.getElementById("outime").innerHTML = daysold;
}
</script>
<hr />
<b>AI摘要</b>
<p id="ai-output">这篇文章介绍了作者如何利用Cloudflare Vectorize的向量数据库功能将其扩展到博客的相似文章推荐系统中。作者通过根据文章ID查询向量实现了简洁的后端查询流程并处理了第一条自身结果的问题。尽管在前端设计时原作者考虑不足没有存标题但作者想到了利用之前的全文搜索功能和localStorage缓存来解决标题显示问题。文章最后提到尽管查询速度适中且 Cloudflare 免费版查询额度有限,作者还是决定通过按钮调用且添加缓存,以利用向量数据库的广泛用途,为博客提供更多发展空间。</p>
<hr />
<ul><li><a href="#起因">起因</a></li><li><a href="#制作过程">制作过程</a><ul><li><a href="#后端部分">后端部分</a></li><li><a href="#前端部分">前端部分</a></li></ul></li><li><a href="#感想">感想</a></li></ul>
<hr />
<main class="post-content e-content" role="main"><p>看来向量数据库的作用有很多啊……<!--more--></p>
<h1 id="起因">
<a href="#起因"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 起因
</h1>
<p>前几天我<a href="/2024/09/27/rag.html">用Cloudflare Vectorize给博客的聊天机器人加了知识库的功能</a>,本来想着用向量数据库做文章推荐是不是每次都要走翻译+向量化的操作不过后来我又仔细看了一下Cloudflare的官方文档发现它是<a href="https://developers.cloudflare.com/vectorize/reference/client-api/#get-vectors-by-id">可以根据ID查询存储的向量</a>的,既然这样的话用现有的数据库做一个相似文章推荐应该非常简单,于是我就做了一个试试看。</p>
<h1 id="制作过程">
<a href="#制作过程"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 制作过程
</h1>
<h2 id="后端部分">
<a href="#后端部分"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 后端部分
</h2>
<p>其实流程很简单就是把对应ID的向量查出来之后拿着这个向量再去查询就好了唯一需要注意的就是它查出来的第一条肯定是自己所以只要把第一条删掉就行 <del>代码也非常简单</del> (后来又加了缓存稍微变的复杂了😂):</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">if</span> <span class="p">(</span><span class="nx">url</span><span class="p">.</span><span class="nx">pathname</span><span class="p">.</span><span class="nx">startsWith</span><span class="p">(</span><span class="dl">"</span><span class="s2">/suggest</span><span class="dl">"</span><span class="p">))</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">resp</span> <span class="o">=</span> <span class="p">[];</span>
<span class="kd">let</span> <span class="nx">update_time</span> <span class="o">=</span> <span class="nx">url</span><span class="p">.</span><span class="nx">searchParams</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="dl">'</span><span class="s1">update</span><span class="dl">'</span><span class="p">);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">update_time</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">result</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">env</span><span class="p">.</span><span class="nx">mayx_index</span><span class="p">.</span><span class="nx">getByIds</span><span class="p">([</span>
<span class="nx">query</span>
<span class="p">]);</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">result</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">let</span> <span class="nx">cache</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">prepare</span><span class="p">(</span><span class="dl">"</span><span class="s2">SELECT `id`, `suggest`, `suggest_update` FROM `blog_summary` WHERE `id` = ?1</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">query</span><span class="p">).</span><span class="nx">first</span><span class="p">();</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">cache</span><span class="p">.</span><span class="nx">id</span><span class="p">)</span> <span class="p">{</span>
<span class="k">return</span> <span class="nx">Response</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">resp</span><span class="p">,</span> <span class="p">{</span>
<span class="na">headers</span><span class="p">:</span> <span class="nx">commonHeader</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">update_time</span> <span class="o">!=</span> <span class="nx">cache</span><span class="p">.</span><span class="nx">suggest_update</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">resp</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">env</span><span class="p">.</span><span class="nx">mayx_index</span><span class="p">.</span><span class="nx">query</span><span class="p">(</span><span class="nx">result</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="nx">values</span><span class="p">,</span> <span class="p">{</span> <span class="na">topK</span><span class="p">:</span> <span class="mi">6</span> <span class="p">});</span>
<span class="nx">resp</span> <span class="o">=</span> <span class="nx">resp</span><span class="p">.</span><span class="nx">matches</span><span class="p">;</span>
<span class="nx">resp</span><span class="p">.</span><span class="nx">splice</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span>
<span class="k">await</span> <span class="nx">db</span><span class="p">.</span><span class="nx">prepare</span><span class="p">(</span><span class="dl">"</span><span class="s2">UPDATE `blog_summary` SET `suggest_update` = ?1, `suggest` = ?2 WHERE `id` = ?3</span><span class="dl">"</span><span class="p">)</span>
<span class="p">.</span><span class="nx">bind</span><span class="p">(</span><span class="nx">update_time</span><span class="p">,</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">resp</span><span class="p">),</span> <span class="nx">query</span><span class="p">).</span><span class="nx">run</span><span class="p">();</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">resp</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">cache</span><span class="p">.</span><span class="nx">suggest</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
<span class="nx">resp</span> <span class="o">=</span> <span class="nx">resp</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">respObj</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="nx">respObj</span><span class="p">.</span><span class="nx">id</span> <span class="o">=</span> <span class="nb">encodeURI</span><span class="p">(</span><span class="nx">respObj</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">respObj</span><span class="p">;</span>
<span class="p">});</span>
<span class="p">}</span>
<span class="k">return</span> <span class="nx">Response</span><span class="p">.</span><span class="nx">json</span><span class="p">(</span><span class="nx">resp</span><span class="p">,</span> <span class="p">{</span>
<span class="na">headers</span><span class="p">:</span> <span class="nx">commonHeader</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<h2 id="前端部分">
<a href="#前端部分"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 前端部分
</h2>
<p>后端当然很简单,但是我之前有些欠考虑了,我当时做<a href="/2024/07/03/ai-summary.html">AI摘要</a><a href="/2024/09/27/rag.html">知识库</a>的时候,都只存了文章的链接,没有存标题😅……但是推荐文章的超链接总不能不放标题吧……那怎么办呢?一种就是我把数据库清空然后摘要中加一个字段,向量数据库中加一个元数据,这样查询的时候就能查到标题然后显示出来了。不过这种方法我仔细考虑了一下,麻烦是一方面,另一方面是我的接口没做验证,有人乱上传文章会影响推荐链接显示的内容,不太合适……那应该用什么办法呢? </p><p>
我还想到一个办法,我之前<a href="/2021/07/23/search.html">给博客做过全文搜索的功能</a>用这个JS关联查询就能查到标题而且查不到的内容也显示不出来这样就能避免有人故意乱上传导致显示奇怪的内容了不过之前的设计是每次查询都要加载一次包含我文章内容的JSON文件感觉不太合理虽然那个文件不算特别大但是也挺影响速度的所以我想了一下还是用localStorage缓存一下比较好所以增加了一个能缓存获取搜索JSON的函数</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">getSearchJSON</span><span class="p">(</span><span class="nx">callback</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">searchData</span> <span class="o">=</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">parse</span><span class="p">(</span><span class="nx">localStorage</span><span class="p">.</span><span class="nx">getItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">blog_</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">lastUpdated</span><span class="p">.</span><span class="nx">valueOf</span><span class="p">()));</span>
<span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">searchData</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">localStorage</span><span class="p">.</span><span class="nx">clear</span><span class="p">();</span>
<span class="nx">$</span><span class="p">.</span><span class="nx">getJSON</span><span class="p">(</span><span class="dl">"</span><span class="s2">/search.json</span><span class="dl">"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">localStorage</span><span class="p">.</span><span class="nx">setItem</span><span class="p">(</span><span class="dl">"</span><span class="s2">blog_</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">lastUpdated</span><span class="p">.</span><span class="nx">valueOf</span><span class="p">(),</span> <span class="nx">JSON</span><span class="p">.</span><span class="nx">stringify</span><span class="p">(</span><span class="nx">data</span><span class="p">));</span>
<span class="nx">callback</span><span class="p">(</span><span class="nx">data</span><span class="p">);</span>
<span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">callback</span><span class="p">(</span><span class="nx">searchData</span><span class="p">);</span>
<span class="p">}</span>
<span class="p">}</span>
</code></pre></div></div>
<p>做好这个之后就可以做文章推荐的功能了不过文章推荐应不应该加载完页面就加载呢其实我测了一下Vectorize数据库的查询速度不算很慢但还是需要时间另外免费版我看了下额度是每月3000万个查询的向量维度这个其实我没看太懂😂。另外Cloudflare不知道为什么没有展示免费版剩余的额度而且它是按月计算的导致我不敢乱用这个查询。 <del>所以我想了一下还是给个按钮来调用吧</del> (后来想了一下干脆直接调用然后加个缓存吧,毕竟我的文章不变,推荐内容也不会变)。最终调用的函数如下:</p>
<div class="language-javascript highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kd">function</span> <span class="nx">getSuggestBlog</span><span class="p">(</span><span class="nx">blogurl</span><span class="p">)</span> <span class="p">{</span>
<span class="kd">var</span> <span class="nx">suggest</span> <span class="o">=</span> <span class="nx">$</span><span class="p">(</span><span class="dl">"</span><span class="s2">#suggest-container</span><span class="dl">"</span><span class="p">)[</span><span class="mi">0</span><span class="p">];</span>
<span class="nx">suggest</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">Loading...</span><span class="dl">"</span><span class="p">;</span>
<span class="nx">$</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">BlogAPI</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">/suggest?id=</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">blogurl</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">&amp;update=</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">lastUpdated</span><span class="p">.</span><span class="nx">valueOf</span><span class="p">(),</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">data</span><span class="p">)</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">data</span><span class="p">.</span><span class="nx">length</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">getSearchJSON</span><span class="p">(</span><span class="kd">function</span> <span class="p">(</span><span class="nx">search</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">suggest</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">'</span><span class="s1">&lt;b&gt;推荐文章&lt;/b&gt;&lt;hr style="margin: 0 0 5px"/&gt;</span><span class="dl">'</span><span class="p">;</span>
<span class="kd">const</span> <span class="nx">searchMap</span> <span class="o">=</span> <span class="k">new</span> <span class="nb">Map</span><span class="p">(</span><span class="nx">search</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">item</span> <span class="o">=&gt;</span> <span class="p">[</span><span class="nx">item</span><span class="p">.</span><span class="nx">url</span><span class="p">,</span> <span class="nx">item</span><span class="p">]));</span>
<span class="kd">const</span> <span class="nx">merged</span> <span class="o">=</span> <span class="nx">data</span><span class="p">.</span><span class="nx">map</span><span class="p">(</span><span class="nx">suggestObj</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="kd">const</span> <span class="nx">searchObj</span> <span class="o">=</span> <span class="nx">searchMap</span><span class="p">.</span><span class="kd">get</span><span class="p">(</span><span class="nx">suggestObj</span><span class="p">.</span><span class="nx">id</span><span class="p">);</span>
<span class="k">return</span> <span class="nx">searchObj</span> <span class="p">?</span> <span class="p">{</span> <span class="p">...</span><span class="nx">searchObj</span> <span class="p">}</span> <span class="p">:</span> <span class="kc">null</span><span class="p">;</span>
<span class="p">});</span>
<span class="nx">merged</span><span class="p">.</span><span class="nx">forEach</span><span class="p">(</span><span class="nx">element</span> <span class="o">=&gt;</span> <span class="p">{</span>
<span class="k">if</span> <span class="p">(</span><span class="nx">element</span><span class="p">)</span> <span class="p">{</span>
<span class="nx">suggest</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">+=</span> <span class="dl">"</span><span class="s2">&lt;a href=</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">element</span><span class="p">.</span><span class="nx">url</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">&gt;</span><span class="dl">"</span> <span class="o">+</span> <span class="nx">element</span><span class="p">.</span><span class="nx">title</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">&lt;/a&gt; - </span><span class="dl">"</span> <span class="o">+</span> <span class="nx">element</span><span class="p">.</span><span class="nx">date</span> <span class="o">+</span> <span class="dl">"</span><span class="s2">&lt;br /&gt;</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">});</span>
<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
<span class="nx">suggest</span><span class="p">.</span><span class="nx">innerHTML</span> <span class="o">=</span> <span class="dl">"</span><span class="s2">暂无推荐文章……</span><span class="dl">"</span><span class="p">;</span>
<span class="p">}</span>
<span class="p">});</span>
<span class="p">}</span>
</code></pre></div></div>
<h1 id="感想">
<a href="#感想"><svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg></a> 感想
</h1>
<p>看来向量数据库的用途还是挺广泛的不仅仅是为了给AI使用说不定还能做更多有意思的功能这下不得不更依赖Cloudflare了😆。 </p><p>
另外随着做了越来越多的功能,做新的功能还能用上旧的功能,感觉这样我的博客可以有不少发展的空间啊😁。</p></main>
<small style="display: block">tags: <a rel="category tag" class="p-category" href="/search.html?keyword=Cloudflare"><em>Cloudflare</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=Workers"><em>Workers</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=Vectorize"><em>Vectorize</em></a> - <a rel="category tag" class="p-category" href="/search.html?keyword=%E5%8D%9A%E5%AE%A2"><em>博客</em></a> <span style="float: right;"><a href="https://gitlab.com/mayx/mayx.gitlab.io/tree/master/_posts/2024-10-01-suggest.md">查看原始文件</a></span></small>
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
<p id="suggest-container">Loading...</p>
<script>
var suggest = $("#suggest-container");
$.get(BlogAPI + "/suggest?id=/2024/10/01/suggest.html&update=" + lastUpdated.valueOf(), function (data) {
if (data.length) {
getSearchJSON(function (search) {
suggest.empty();
var searchMap = {};
for (var i = 0; i < search.length; i++) {
searchMap[search[i].url] = search[i];
}
var tooltip = $('<div class="content-tooltip"></div>').appendTo('body').hide();
for (var j = 0; j < data.length; j++) {
var item = searchMap[data[j].id];
if (item) {
var link = $('<a href="' + item.url + '">' + item.title + '</a>');
var contentPreview = item.content.substring(0, 100);
if (item.content.length > 100) {
contentPreview += "……";
}
link.hover(
function(e) {
tooltip.text($(this).data('content'))
.css({
top: e.pageY + 10,
left: e.pageX + 10
})
.show();
},
function() {
tooltip.hide();
}
).mousemove(function(e) {
tooltip.css({
top: e.pageY + 10,
left: e.pageX + 10
});
}).data('content', contentPreview);
suggest.append(link);
suggest.append(' - ' + item.date + '<br />');
}
}
});
} else {
suggest.html("暂无推荐文章……");
}
});
</script>
<br />
<div class="pagination">
<span class="prev">
<a href="/2024/09/27/rag.html">
上一篇用CF Vectorize把博客作为聊天AI的知识库
</a>
</span>
<br />
<span class="next">
<a href="/2024/10/13/arm-linux.html">
下一篇Linux ARM生态评测
</a>
</span>
</div>
<!--[if !IE]> -->
<link rel="stylesheet" href="/assets/css/gitalk.css">
<script src="/assets/js/gitalk.min.js"></script>
<div id="gitalk-container"></div>
<script>
var gitalk = new Gitalk({
clientID: '36557aec4c3cb04f7ac6',
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
repo: 'mabbs.github.io',
owner: 'Mabbs',
admin: ['Mabbs'],
id: '/2024/10/01/suggest', // Ensure uniqueness and length less than 50
distractionFreeMode: false, // Facebook-like distraction free mode
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
})
gitalk.render('gitalk-container')
</script>
<!-- <![endif]-->
</section>
<!--[if !IE]> -->
<div id="landlord" style="left:5px;bottom:0px;">
<div class="message" style="opacity:0"></div>
<canvas id="live2d" width="500" height="560" class="live2d"></canvas>
<div class="live_talk_input_body">
<form id="live_talk_input_form">
<div class="live_talk_input_name_body" >
<input type="checkbox" id="load_this" />
<input type="hidden" id="post_id" value="/2024/10/01/suggest.html" />
<label for="load_this">
<span style="font-size: 11px; color: #fff;">&#160;想问这篇文章</span>
</label>
</div>
<div class="live_talk_input_text_body">
<input name="talk" type="text" class="live_talk_talk white_input" id="AIuserText" autocomplete="off" placeholder="要和我聊什么呀?" />
<button type="submit" class="live_talk_send_btn" id="talk_send">发送</button>
</div>
</form>
</div>
<input name="live_talk" id="live_talk" value="1" type="hidden" />
<div class="live_ico_box" style="display:none;">
<div class="live_ico_item type_info" id="showInfoBtn"></div>
<div class="live_ico_item type_talk" id="showTalkBtn"></div>
<div class="live_ico_item type_music" id="musicButton"></div>
<div class="live_ico_item type_youdu" id="youduButton"></div>
<div class="live_ico_item type_quit" id="hideButton"></div>
<input name="live_statu_val" id="live_statu_val" value="0" type="hidden" />
<audio src="" style="display:none;" id="live2d_bgm" data-bgm="0" preload="none"></audio>
<input id="duType" value="douqilai" type="hidden" />
</div>
</div>
<div id="open_live2d">召唤伊斯特瓦尔</div>
<!-- <![endif]-->
<footer>
<p>
<small>Made with ❤ by Mayx<br />Last updated at 2026-02-08 20:35:53<br /> 总字数617672 - 文章数179 - <a href="/atom.xml" >Atom</a> - <a href="/README.html" >About</a></small>
</p>
</footer>
</div>
<script src="/assets/js/scale.fix.js"></script>
<!--[if !IE]> -->
<script src="/assets/js/main_new.js"></script>
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
<script src="/Live2dHistoire/live2d/js/message.js"></script>
<!-- <![endif]-->
</body>
</html>