《C/C+++ Boost 轻量级搜索引擎实战:架构流程、技术栈与工程落地指南——HTML清洗+正/倒排的+服务器的融合(终篇)》
前引这是一个聚焦基础搜索引擎核心工作流的实操项目基于 C/C 技术生态落地从全网爬虫抓取网页资源到服务器端完成 “去标签 - 数据清洗 - 索引构建” 的预处理再通过 HTTP 服务接收客户端请求、检索索引并拼接结果页返回 —— 完整覆盖了轻量级搜索引擎的端到端逻辑。项目采用 C11、STL、Boost 等核心技术栈搭配 CentOS 7 云服务器 GCC 编译环境或 VS 系列开发工具部署既适配后端工程的性能需求也能通过可选的前端技术HTML5/JS 等优化用户交互是理解搜索引擎底层原理与 C 工程实践的典型案例目录【一】调用正/倒排索引class Searcher【二】完成JSON格式的输出class Searcher【三】对指定内容完成摘要【四】引用 cpp httplib库【五】基本搜索演示1完成首页2调用cpp httplib3演示【六】优化1首页优化12效果展示2首页优化23效果展示【七】BOOST搜索引擎项目梳理【一】调用正/倒排索引class Searcher设计一个类调用正/倒排索引类中 Index 中的单例模式指针//索引对象 ns_index::Index* index;void Init_index(const std::string input) { //实例化索引对象 indexns_index::Index::handle(); //建立索引 index-Buildindex(input); }我们调用测试代码打印索引构建情况看看正排和倒排输出咋样【二】完成JSON格式的输出class Searcher对用户输入的提示词调用Jieba进行分词然后在倒排中进行匹配由正排找到对应的文档完成JSON序列化//利用正排和倒排构建JSON void searcher(const std::string input,std::string json_output) { //存储分词的结果 std::vectorstd::string S; //使用分词工具对input进行分词 ns_index::JiebaUtil jieba; Sjieba.Tokenize(input); //根据获取的关键字利用倒排获取关联的ID,返回的是一个个std::vectorInvertedindexStock_Inverted std::vectorns_index::Index::Stock_Inverted V; for(std::string word :S) { ns_index::Index::Stock_Inverted* pc (index-GetInverted_index(word)); //如果不存在 if(pcnullptr)continue; //如果存在存储对应涉及到的vectorInvertedindex V.push_back(*pc); } //扁平化获取input涉及的所有ID std::vectorns_index::Invertedindex all_item; for(auto e:V)//e拿到了每个vectorInvertedindex { for(auto it:e)//it拿到了每个Invertedindex { all_item.push_back(it); } } //对结果安装权重排序 std::sort(all_item.begin(),all_item.end(),Compare()); //根据id拿到每个文档完成JSON的序列化 nlohmann::json result_json; for(auto it:all_item) { ns_index::Forwardindex* pc (index-GetForward_index(it.doc_id)); if(pcnullptr)continue; nlohmann::json doc_json; doc_json[title]pc-title; doc_json[source]pc-source; doc_json[chain]pc-chain; result_json.push_back(doc_json); } json_output result_json.dump(4); }【三】对指定内容完成摘要//对内容做提取形成摘要 std::string GetDesc(const std::string html_content,const std::string word) { std::string SNone; //从word位置往前找50个字节如果不够从word向后找100个字节 //在内容中找word出现的位置 std::size_t it html_content.find(word); if(it std::string::npos) { return S; } //如果word前面的字符够50个字符 if(it50) { Shtml_content.substr(it-50,50); return S; } else//如果word前面不够50个字符 { std::size_t size_content html_content.size(); if(it100 size_content)//如果足够100个字符 { Shtml_content.substr(it,100); return S; } else//如果不足够100个字符 { Shtml_content.substr(it,size_content-it); } } return S; }【四】引用 cpp httplib库这个是已经写好了的服务器端的代码可以直接调用形成一个简单的服务器如果想系统的学可以看小编前面的服务端的实现//搜索是否有cpp-httplib的开发包 sudo apt search cpp-httplib//直接安装 sudo apt install libcpp-httplib-dev【五】基本搜索演示1完成首页首先我们准备一个首页index.html放在另外一个目录wwwroot下!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title搜索服务器/title style /* 基础样式保证界面简洁美观 */ body { font-family: Microsoft YaHei, Arial, sans-serif; background-color: #f8f9fa; margin: 0; padding: 0; display: flex; justify-content: center; align-items: center; min-height: 100vh; } .search-container { background-color: #ffffff; padding: 40px; border-radius: 10px; box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1); width: 550px; text-align: center; } .search-title { color: #333333; font-size: 32px; margin-bottom: 30px; font-weight: normal; } .search-box { display: flex; gap: 0; } #search-input { flex: 1; padding: 14px 18px; font-size: 16px; border: 1px solid #dddddd; border-right: none; border-radius: 6px 0 0 6px; outline: none; transition: border-color 0.3s; } #search-input:focus { border-color: #007bff; } #search-btn { padding: 14px 28px; background-color: #007bff; color: #ffffff; border: none; border-radius: 0 6px 6px 0; font-size: 16px; cursor: pointer; transition: background-color 0.3s; } #search-btn:hover { background-color: #0056b3; } .hint-text { color: #6c757d; font-size: 14px; margin-top: 20px; } /style /head body div classsearch-container h1 classsearch-title欢迎使用搜索服务/h1 div classsearch-box input typetext idsearch-input placeholder请输入搜索关键词... autocompleteoff button idsearch-btn搜索/button /div p classhint-text提示输入关键词后按回车键或点击搜索按钮提交/p /div script // 搜索提交逻辑跳转至/s接口并携带word参数 function submitSearch() { const keyword document.getElementById(search-input).value.trim(); if (!keyword) { alert(请输入搜索关键词); return; } // 拼接搜索接口地址encodeURIComponent处理中文/特殊字符 const searchUrl /s?word${encodeURIComponent(keyword)}; window.location.href searchUrl; } // 绑定按钮点击事件 document.getElementById(search-btn).addEventListener(click, submitSearch); // 绑定回车键提交事件 document.getElementById(search-input).addEventListener(keydown, function(e) { if (e.key Enter) { submitSearch(); } }); /script /body /html2调用cpp httplib这里的 searcher.h就是searcher.h中实现的Searcher类main执行的事件1完成索引为了提高速度方便我把索引的次数设置成了5个2创建了一个叫svr的服务器对象3告诉服务器静态文件比如index.html从./wwwroot目录里找4设置访问规则1用户如果要搜索关键字应该是这种形式IP:8080/s?word关键词2如果用户带了关键字就在服务器输出用户搜索的关键字在用JSON输出搜索结果3如果没带就显示错误#include httplib.h #includesearcher.h const std::string path ./data/data_clean.txt; const std::string root_path ./wwwroot; int main() { //构造索引 c_searcher::Searcher search; search.Init_index(path); //服务器响应内容 httplib::Server svr; svr.set_base_dir(root_path.c_str()); svr.Get(/s, [search](const httplib::Request req, httplib::Response rsp) { if(!req.has_param(word)) { rsp.set_content(必须要有搜索关键字!, text/plain; charsetutf-8); return; } std::string word req.get_param_value(word); std::cout 用户在搜索 word std::endl; std::string json_string; search.searcher(word, json_string); rsp.set_content(json_string, application/json); }); svr.listen(0.0.0.0, 8080); return 0; }3演示首先完成索引然后服务器开始启动然后浏览器访问使用了关键字且索引中有对应关键字文档搜索了关键字但索引中没有首页效果用户没有携带关键字【六】优化1首页优化1用户可以直接采用IP:端口:/?word关键字的方式响应内容前面我们已经搭建了首页用户也应该可以在首页搜索框中直接搜索关键字所以我们更改 index.html 文件!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title搜索服务/title style body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f5f5f5; font-family: Arial, sans-serif; } .search-box { background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; } .search-box h2 { margin-bottom: 20px; color: #333; } .search-input { padding: 10px 15px; width: 300px; border: 1px solid #ddd; border-radius: 4px 0 0 4px; font-size: 16px; } .search-btn { padding: 10px 20px; background: #007bff; color: #fff; border: none; border-radius: 0 4px 4px 0; font-size: 16px; cursor: pointer; } .search-btn:hover { background: #0056b3; } .tips { margin-top: 10px; color: #666; font-size: 14px; } /style /head body div classsearch-box h2欢迎使用搜索服务/h2 !-- 输入框和按钮 -- input typetext idsearch-input classsearch-input placeholder请输入搜索关键词... button idsearch-btn classsearch-btn搜索/button p classtips提示输入关键词后按回车键或点击搜索按钮提交/p /div script // 1. 获取输入框和按钮元素 const input document.getElementById(search-input); const btn document.getElementById(search-btn); // 2. 定义“提交搜索”的函数 function submitSearch() { // 获取输入的关键词去掉前后空格 const keyword input.value.trim(); // 如果关键词为空提示用户 if (!keyword) { alert(请输入搜索关键词); return; } // 拼接目标URLIP:端口/s?word关键词自动适配当前域名/端口 // encodeURIComponent处理关键词中的特殊字符比如空格、中文 const searchUrl /s?word${encodeURIComponent(keyword)}; // 跳转到搜索接口 window.location.href searchUrl; } // 3. 给按钮绑定“点击触发搜索” btn.addEventListener(click, submitSearch); // 4. 给输入框绑定“按回车键触发搜索” input.addEventListener(keydown, (e) { if (e.key Enter) { submitSearch(); } }); /script /body /html2效果展示效果如下通过首页的搜索可以自动补齐前面的IP:端口:/?word内容然后跳转2首页优化2用户输入关键词后首先响应的是如下内容那么可以直接跳转到响应JSON内容中的chain链接需要注意我们在searcher.h中实现的JSON序列化是数组形式的因为对应多个ID所以下面的网页代码在解析JSON中的chainURL时默认取数组的第一个元素的chian才可以响应!DOCTYPE html html langzh-CN head meta charsetUTF-8 meta nameviewport contentwidthdevice-width, initial-scale1.0 title搜索服务/title style body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background-color: #f5f5f5; font-family: Arial, sans-serif; } .search-box { background: #fff; padding: 30px; border-radius: 8px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); text-align: center; } .search-box h2 { margin-bottom: 20px; color: #333; } .search-input { padding: 10px 15px; width: 300px; border: 1px solid #ddd; border-radius: 4px 0 0 4px; font-size: 16px; } .search-btn { padding: 10px 20px; background: #007bff; color: #fff; border: none; border-radius: 0 4px 4px 0; font-size: 16px; cursor: pointer; } .search-btn:hover { background: #0056b3; } .tips { margin-top: 10px; color: #666; font-size: 14px; } .loading { margin-top: 15px; color: #007bff; display: none; /* 默认隐藏加载提示 */ } /style /head body div classsearch-box h2欢迎使用搜索服务/h2 input typetext idsearch-input classsearch-input placeholder请输入搜索关键词... button idsearch-btn classsearch-btn搜索/button p classloading idloading搜索中请稍候.../p p classtips提示输入关键词后按回车键或点击搜索按钮提交/p /div script const input document.getElementById(search-input); const btn document.getElementById(search-btn); const loading document.getElementById(loading); async function submitSearch() { const keyword input.value.trim(); if (!keyword) { alert(请输入搜索关键词); return; } // 显示“搜索中”提示 loading.style.display block; try { const response await fetch(/s?word${encodeURIComponent(keyword)}); if (!response.ok) throw new Error(请求失败状态码${response.status}); const rawText await response.text(); const resultArray JSON.parse(rawText); // 现在是数组 // 取数组第一个结果的chain if (resultArray.length 0 resultArray[0].chain) { window.location.href resultArray[0].chain; } else { alert(未找到对应的链接地址); } } catch (error) { alert(搜索出错${error.message}); } finally { loading.style.display none; } } // 绑定按钮点击事件 btn.addEventListener(click, submitSearch); // 绑定回车键事件 input.addEventListener(keydown, (e) { if (e.key Enter) { submitSearch(); } }); /script /body /html3效果展示可以看到它的网页结果刚好跳转到第一个chain链接【七】BOOST搜索引擎项目梳理项目目的模拟实现搜索引擎输入关键字是如何响应和匹配我们需要的网页内容的原理图项目搭建过程1首先我们选择了BOOST资料库作为数据对象来模拟全网数据2对所有数据进行清洗筛选出每条网页数据的标题、有效内容、URL存储起来3通过存储的这些信息构建正排/倒排索引正排通过ID映射每个文档信息倒排通过关键字映射文档ID在其中我们采用jieba分词工具来完成分词对每个文档的标题和内容形成关键字4接着我们处理用户输入的搜索信息再次调用jieba分词工具通过倒排锁定涉及到的文章ID再通过正排拿到文章ID对应的文档内容这样我们就拿到了涉及到的所有文档进行JSON序列化5对涉及到的文档再次筛选出摘要内容形成简短的文档内容展示6最后通过cpp httplib库直接形成服务器设计一套访问规则根据用户的关键字在倒排中找到对应的文档ID构建出JSON响应再响应给用户