重写 StarBlog 的搜索功能和页面,支持权重设置和结果高亮
重写搜索?就内存算权重加Regex?太业余了。标题权重100倍正文?这种土味方案意外的有效。页面也重写了,但Bootstrap样式够原始的。 v2还指望用Lucene.NET?
目录9 个章节
前言
最近在整理本地的一些笔记
有些日期不太对的,我的博客上有记录发布和更新时间,所以我去搜索了一下
这时候发现 StarBlog 的搜索功能太简陋了
虽然上次更新增加了一大波功能,也优化了一下搜索功能,之前只能搜索标题,现在可以搜索正文内容了。详见: StarBlog v1.3.0 新版本,一大波更新以及迁移服务器部署
不过有个问题是没有权重,标题的权重应该比正文更高的
按理说这些应该得加入全文检索引擎,Elasticsearch、MeiliSearch 之类的来实现。但这些需要额外的服务,太重了。
再不济也要用 Lucene.NET 这种,这是 Elasticsearch 的基础,但不需要额外服务,纯本地嵌入式,支持权重控制、高亮、分词等功能。
但为了快速实现,这些我都不想用,先用最简单的方式来改进。
同时我也重写了搜索结果页面,之前的页面太业余了。
极简实现
最终我的方案是:在内存里手动算权重 + Regex 实现结果高亮
成本非常低,效果也不错
实现效果
来看看效果吧
这套 StarBlog 的前端是 Bootstrap,样式都得靠 CSS,相对于我现在用的 Tailwind CSS、Shadcn/ui、Magic UI 之类的,太原始了,重写这个界面已经尽力了hhh😄

代码
OK,接下来是大家不感兴趣的代码环节
模型
先定义搜索结果模型
public class SearchPost {
public Post Post { get; set; }
public int TitleScore { get; set; }
public int ContentScore { get; set; }
// 标题每命中一次+100分
// 内容命中+1分
public int Score => TitleScore * 100 + ContentScore;
public string HighlightedTitle { get; set; }
public string HighlightedSnippet { get; set; }
}
搜索逻辑
搜索功能逻辑都在 src/StarBlog.Web/Controllers/SearchController.cs 文件里
在内村里计算权重,从数据库查询出来后,用 Linq 计算权重,关键词出现一次为一分;总分是在 SearchPost 里计算的,标题每命中一次+100分,内容命中+1分
var searchPosts = _postRepo
.Where(a => a.IsPublish)
.Where(a =>
a.Title!.Contains(keyword) ||
a.Content.Contains(keyword)
)
.Include(a => a.Category)
.ToList()
.Select(p => new SearchPost {
Post = p,
TitleScore = p.Title.ToLower().Split(keyword).Length - 1,
ContentScore = p.Content?.ToLower().Split(keyword).Length - 1 ?? 0,
})
.OrderByDescending(x => x.Score)
.ToList();
搜索结果高亮
使用正则表达式来实现结果高亮
var regex = new Regex(Regex.Escape(keyword), RegexOptions.IgnoreCase);
foreach (var item in searchPosts) {
item.HighlightedTitle = regex.Replace(item.Post.Title, m => $"<mark>{m.Value}</mark>");
item.HighlightedSnippet = GetHighlightedSnippet(item.Post.Content, keyword);
}
生成高亮片段摘要
思路很简单:
- 找到第一个命中的位置
- 截取前后一定长度的内容(比如前后各 50 个字符)
- 再用 Regex 替换加
<mark>高亮 - 最后拼上
...作为省略号
public static string GetHighlightedSnippet(string content, string keyword, int snippetLength = 100) {
if (string.IsNullOrEmpty(content) || string.IsNullOrEmpty(keyword))
return string.Empty;
var regex = new Regex(Regex.Escape(keyword), RegexOptions.IgnoreCase);
var match = regex.Match(content);
if (!match.Success) {
// 没匹配到,直接取前 snippetLength*2 个字符作为摘要
return content.Length > snippetLength * 2
? content.Substring(0, snippetLength * 2) + "..."
: content;
}
// 计算截取范围(匹配位置前后各 snippetLength)
int start = Math.Max(0, match.Index - snippetLength);
int length = Math.Min(content.Length - start, match.Length + snippetLength * 2);
string snippet = content.Substring(start, length);
// 高亮处理
snippet = regex.Replace(snippet, m => $"<mark>{m.Value}</mark>");
// 前后补省略号(如果不是全文开头或结尾)
if (start > 0) snippet = "..." + snippet;
if (start + length < content.Length) snippet += "...";
return snippet;
}
小结
重构之后体验更上一层
不过在老架构上修修补补终究不是长久之计
等有空就得赶紧开始 v2 新版的开发💪
PS:接下来也许会拓展一下这个搜索功能,加入多个关键词搜索的支持,再进一步搭配 Lucene.NET 也不无可能。
_EOF_
重写 StarBlog 的搜索功能和页面,支持权重设置和结果高亮
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
StarBlog v1.3.0 新版本,一大波更新以及迁移服务器部署
服务器故障逼得更新,直接上云服务器迁移。v1.3.0版本来了,架构、界面、SEO全升级,还加了图片压缩工具,代码总算整理干净点。来看看这波大更新如何?
2025-08-19 · StarBlog番外 · 约 1 分钟
StarBlog小更新,文章管理体验巨大提升,重写了几个管理后台页面
面对破破烂烂的后台,只能先缝缝补补。重写了丑出水平的登录页,还做了分类树和照片墙。看着几年前写的代码直呼好家伙,这种临时方案迟早要重构。
2025-10-30 · StarBlog番外 · 约 1 分钟
StarBlog 番外篇 (3) StarBlog Publisher,跨平台一键发布,DeepSeek加持的文章创作神器
StarBlog Publisher是一款针对StarBlog博客系统的专业文章发布工具,简化了Markdown文章的发布流程。它支持预览、一键发布,自动处理图片,提供AI辅助创作,且支持跨平台使用。该工具基于.NET 8.0开发,集成多种AI模型,提升内容创作者效率。
2025-03-27 · StarBlog番外 · 约 1 分钟
StarBlog 番外篇 (1) 全新的访问统计功能,异步队列,分库存储
虽然现在工作重心以AI为主了,不过相比起各种大模型的宏大叙事,我还是更喜欢自己构思功能、写代码,享受解决问题和发布上线的过程。 之前 StarBlog 系列更新的时候我也有提到,随着功能更新,会在教程系列完结之后继续写番外,这不第一篇番外就来了。 这次是全新设计的访问统计功能。
2025-03-25 · StarBlog番外 · 约 1 分钟
讨论
共 0 条加载评论中…