基于boost准标准库的搜索引擎项目

零 项目背景/原理/技术栈

1.介绍boost准标准库

2.项目实现效果

3.搜索引擎宏观架构图

这是一个基于Web的搜索服务架构

该架构优点:

  1. 客户端-服务器模型:采用了经典的客户端-服务器模型,用户通过客户端与服务器交互,有助于集中管理和分散计算。
  2. 简单的用户界面:客户端似乎很简洁,用户通过简单的HTTP请求与服务端交互,易于用户操作。
  3. 搜索引擎功能:服务器端的搜索器能够接收查询请求,从数据存储中检索信息,这是Web搜索服务的核心功能。
  4. 数据存储:有专门的存储系统用于存放数据文件(如HTML文件),有助于维护数据的完整性和持久性。
  5. 模块分离:搜索器、存储和处理请求的模块被分开,这有助于各模块独立更新和维护.

该架构不足:

  1. 单一服务器瓶颈:所有请求似乎都经过一个中心服务器处理,这可能会导致瓶颈,影响扩展性和可用性。
  2. 缺乏负载均衡:在架构图中没有显示负载均衡系统,当大量并发请求到来时可能会影响性能。
  3. 没有明确的缓存策略:对于频繁搜索的内容,缓存可以显著提高响应速度,降低服务器压力,架构图中没有体现出缓存机制。
  4. 可靠性和冗余性:没有看到备份服务器或数据复制机制,这对于数据的安全性和服务的持续可用性非常重要。
  5. 安全性:架构图中未展示任何安全措施,例如SSL加密通信、防火墙、入侵检测系统等。

4.搜索过程的原理~正排,倒排索引

5.技术栈和项目环境,工具

技术栈:C/C++ C++11 STL boost准标准库 JsonCPP cppjieba cpp-httplib 
html css js jQuery Ajax

项目环境:Centos7  华为云服务器 gcc/g++/makefile Vscode

一 Paser数据清洗,获取数据源模块


const std::string src_path = "data/input/";
const std::string output_file = "data/output/dest.txt";
class DocInfo
{
public:std::string _title;std::string _content;std::string _url;
};

Paser模块主逻辑 

int main()
{std::vector<std::string> files_list;// 第一步 把搜索范围src_path内的所有html的路径+文件名放到 files_list中if (!EnumFileName(src_path, &files_list)){lg(_Error,"%s","enum filename err!");exit(EnumFileNameErr);}// 第二步 将files_list中的文件打开,读取并解析为DocInfo后放到 web_documents中std::vector<DocInfo> html_documents;if (!ParseHtml(files_list, &html_documents)){lg(_Error,"%s","parse html err!");exit(ParseHtmlErr);}// 第三步 将web_documents的信息写入到 output_file文件中, 以\3为每个文档的分隔符if (!SaveHtml(html_documents, output_file)){lg(_Error,"%s","save html err!");exit(SaveHtmlErr);}
}
  1. 枚举文件:从给定的源路径(src_path)中枚举所有HTML文件,并将它们的路径和文件名放入files_list中。

  2. 解析HTML:读取files_list中的每个文件,解析它们为DocInfo对象(可能包含标题、URL、正文等元素),然后存储到html_documents向量中。

  3. 保存文档:将html_documents中的文档信息写入到指定的输出文件output_file中,文档之间用\3(ASCII码中的End-of-Text字符)分隔。

EnumFileName

bool EnumFileName(const std::string &src_path, std::vector<std::string> *files_list)
{namespace fs = boost::filesystem;fs::path root_path(src_path);if (!fs::exists(root_path)) // 判断路径是否存在{lg(_Fatal,"%s%s",src_path.c_str()," is not exist");return false;}// 定义一个空迭代器,用来判断递归是否结束fs::recursive_directory_iterator end;// 递归式遍历文件for (fs::recursive_directory_iterator it(src_path); it != end; it++){if (!fs::is_regular(*it))continue; // 保证是普通文件if (it->path().extension() != ".html")continue; // 保证是.html文件files_list->push_back(it->path().string()); // 插入的都是合法 路径+.html文件名}return true;
}

ParseHtml

bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo> *html_documents)
{for (const std::string &html_file_path : files_list){// 第一步 遍历files_list,根据路径+文件名,读取html文件内容std::string html_file;if (!ns_util::FileUtil::ReadFile(html_file_path, &html_file)){lg(_Error,"%s","ReadFile err!");continue;}DocInfo doc_info;// 第二步 解析html文件,提取titleif (!ParseTitle(html_file, &doc_info._title)){lg(_Error,"%s%s","ParseTitle err! ",html_file_path.c_str());continue;}// 第三步 解析html文件,提取content(去标签)if (!ParseContent(html_file, &doc_info._content)){lg(_Error,"%s","ParseContent err!");continue;}// 第四步 解析html文件,构建urlif (!ParseUrl(html_file_path, &doc_info._url)){lg(_Error,"%s","ParseUrl err!");continue;}// 解析html文件完毕,结果都保存到了doc_info中// ShowDcoinfo(doc_info);html_documents->push_back(std::move(doc_info)); // 尾插会拷贝,效率不高,使用move}lg(_Info,"%s","ParseHtml success!");return true;
}

1.ReadFile

    class FileUtil{public:static bool ReadFile(const std::string &file_path, std::string *out){std::ifstream in(file_path, std::ios::in); // 以输入方式打开文件if (!in.is_open()){lg(_Fatal,"%s%s%s","ReadFile:",file_path.c_str()," open err!");return false;}std::string line;while (std::getline(in, line)){*out += line;}in.close();return true;}};

2.ParseTitle

static bool ParseTitle(const std::string &html_file, std::string *title)
{size_t left = html_file.find("<title>");if (left == std::string::npos)return false;size_t right = html_file.find("</title>");if (right == std::string::npos)return false;int begin = left + std::string("<title>").size();int end = right;// 截取[begin,end-1]内的子串就是标题内容if (end-begin<0){lg(_Error,"%s%s%s","ParseTitle:",output_file.c_str(),"has no title");//std::cerr << "ParseTitle:" << output_file << "has no title" << std::endl;return false;}std::string str = html_file.substr(begin, end - begin);//std::cout << "get a title: " << str << std::endl;*title = str;return true;
}

3.ParseContent

static bool ParseContent(const std::string &html_file, std::string *content)
{// 利用简单状态机完成去标签工作enum Status{Lable,Content};Status status = Lable;for (char ch : html_file){switch (status){case Lable:if (ch == '>')status = Content;break;case Content:if (ch == '<')status = Lable;else{// 不保留html文本中自带的\n,防止后续发生冲突if (ch == '\n')ch = ' ';content->push_back(ch);}break;default:break;}}return true;
}

4.ParseUrl

static bool ParseUrl(const std::string &html_file_path, std::string *url)
{std::string url_head = "https://www.boost.org/doc/libs/1_84_0/doc/html";std::string url_tail = html_file_path.substr(src_path.size());*url = url_head + "/" + url_tail;return true;
}

SaveHtml

//doc_info内部用\3分隔,doc_info之间用\n分隔
bool SaveHtml(const std::vector<DocInfo> &html_documents, const std::string &output_file)
{const char sep = '\3';std::ofstream out(output_file, std::ios::out | std::ios::binary|std::ios::trunc);if (!out.is_open()){lg(_Fatal,"%s%s%s","SaveHtml:",output_file.c_str()," open err!");return false;}for(auto &doc_info:html_documents){std::string outstr;outstr += doc_info._title;outstr += sep;outstr += doc_info._content;outstr += sep;outstr+= doc_info._url;outstr+='\n';out.write(outstr.c_str(),outstr.size());}out.close();lg(_Info,"%s","SaveHtml success!");return true;
}

二 Index建立索引模块

三 Searcher搜索模块

四 http_server模块

const std::string input = "data/output/dest.txt";//从input里读取数据构建索引
const std::string root_path = "./wwwroot";
int main()
{std::unique_ptr<ns_searcher::Searcher> searcher(new ns_searcher::Searcher());searcher->SearcherInit(input);httplib::Server svr;svr.set_base_dir(root_path.c_str()); // 设置根目录// 重定向到首页svr.Get("/", [](const httplib::Request &, httplib::Response &rsp){ rsp.set_redirect("/home/LZF/boost_searcher_project/wwwroot/index.html"); }); // 重定向到首页svr.Get("/s",[&searcher](const httplib::Request &req,httplib::Response &rsp){if(!req.has_param("word")){rsp.set_content("无搜索关键字!","test/plain,charset=utf-8");return;}std::string json_str;std::string query = req.get_param_value("word");std::cout<<"用户正在搜索: "<<query<<std::endl;searcher->Search(query,&json_str);rsp.set_content(json_str,"application/json");});svr.listen("0.0.0.0", 8800);
}

五 前端模块

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><script src="http://code.jquery.com/jquery-2.1.1.min.js"></script><title>boost 搜索引擎</title><style>/* 去掉网页中的所有的默认内外边距,html的盒子模型 */* {/* 设置外边距 */margin: 0;/* 设置内边距 */padding: 0;}/* 将我们的body内的内容100%和html的呈现吻合 */html,body {height: 100%;}/* 类选择器.container */.container {/* 设置div的宽度 */width: 800px;/* 通过设置外边距达到居中对齐的目的 */margin: 0px auto;/* 设置外边距的上边距,保持元素和网页的上部距离 */margin-top: 15px;}/* 复合选择器,选中container 下的 search */.container .search {/* 宽度与父标签保持一致 */width: 100%;/* 高度设置为52px */height: 52px;}/* 先选中input标签, 直接设置标签的属性,先要选中, input:标签选择器*//* input在进行高度设置的时候,没有考虑边框的问题 */.container .search input {/* 设置left浮动 */float: left;width: 600px;height: 50px;/* 设置边框属性:边框的宽度,样式,颜色 */border: 1px solid black;/* 去掉input输入框的有边框 */border-right: none;/* 设置内边距,默认文字不要和左侧边框紧挨着 */padding-left: 10px;/* 设置input内部的字体的颜色和样式 */color: #CCC;font-size: 14px;}/* 先选中button标签, 直接设置标签的属性,先要选中, button:标签选择器*/.container .search button {/* 设置left浮动 */float: left;width: 150px;height: 52px;/* 设置button的背景颜色,#4e6ef2 */background-color: #4e6ef2;/* 设置button中的字体颜色 */color: #FFF;/* 设置字体的大小 */font-size: 19px;font-family:Georgia, 'Times New Roman', Times, serif;}.container .result {width: 100%;}.container .result .item {margin-top: 15px;}.container .result .item a {/* 设置为块级元素,单独站一行 */display: block;/* a标签的下划线去掉 */text-decoration: none;/* 设置a标签中的文字的字体大小 */font-size: 20px;/* 设置字体的颜色 */color: #4e6ef2;}.container .result .item a:hover {text-decoration: underline;}.container .result .item p {margin-top: 5px;font-size: 16px;font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;}.container .result .item i{/* 设置为块级元素,单独站一行 */display: block;/* 取消斜体风格 */font-style: normal;color: green;}</style>
</head>
<body><div class="container"><div class="search"><input type="text" value="请输入搜索关键字"><button onclick="Search()">搜索一下</button></div><div class="result"></div></div><script>function Search(){let query = $(".container .search input").val();console.log("query = " + query);$.get("/s", {word: query}, function(data){console.log(data);BuildHtml(data);});}function BuildHtml(data){let result_lable = $(".container .result");result_lable.empty();for( let elem of data){let a_lable = $("<a>", {text: elem.title,href: elem.url,target: "_blank"});let p_lable = $("<p>", {text: elem.desc});let i_lable = $("<i>", {text: elem.url});let div_lable = $("<div>", {class: "item"});a_lable.appendTo(div_lable);p_lable.appendTo(div_lable);i_lable.appendTo(div_lable);div_lable.appendTo(result_lable);}}</script></body>
</html>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/292101.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

idea从零开发Android 安卓 (超详细)

首先把所有的要准备的说明一下 idea 2023.1 什么版本也都可以操作都是差不多的 gradle 8.7 什么版本也都可以操作都是差不多的 Android SDK 34KPI 下载地址&#xff1a; AndroidDevTools - Android开发工具 Android SDK下载 Android Studio下载 Gradle下载 SDK Tools下载 …

Node | Node.js 版本升级

目录 Step1&#xff1a;下载 Step2&#xff1a;安装 Step3&#xff1a;换源 发现其他博客说的 n 模块不太行&#xff0c;所以老老实实地手动安装 Step1&#xff1a;下载 Node 中文官网&#xff1a;https://nodejs.cn/download 点击后&#xff0c;将会下载得到一个 .msi 文件…

vue3 视频播放功能整体复盘梳理

回顾工作中对视频的处理&#xff0c;让工作中处理的问题的经验固化成成果&#xff0c;不仅仅是完成任务&#xff0c;还能解答任务的知识点。 遇到的问题 1、如何隐藏下载按钮&#xff1f; video 标签中的controlslist属性是可以用来控制播放器上空间的显示&#xff0c;在原来默…

k8s的pod访问service的方式

背景 在k8s中容器访问某个service服务时有两种方式&#xff0c;一种是把每个要访问的service的ip注入到客户端pod的环境变量中&#xff0c;另一种是客户端pod先通过DNS服务器查找对应service的ip地址&#xff0c;然后在通过这个service ip地址访问对应的service服务 pod客户端…

Hive on Spark 配置

目录 1 Hive 引擎简介2 Hive on Spark 配置2.1 在 Hive 所在节点部署 Spark2.2 在hive中创建spark配置文件2.3 向 HDFS上传Spark纯净版 jar 包2.4 修改hive-site.xml文件2.5 Hive on Spark测试2.6 报错 1 Hive 引擎简介 Hive引擎包括&#xff1a;MR&#xff08;默认&#xff09…

Mistral 7B v0.2 基础模型开源,大模型微调实践来了

Mistral AI在3月24日突然发布并开源了 Mistral 7B v0.2模型&#xff0c;有如下几个特点&#xff1a; 和上一代Mistral v0.1版本相比&#xff0c;上下文窗口长度从8k提升到32k&#xff0c;上下文窗口&#xff08;context window&#xff09;是指语言模型在进行预测或生成文本时&…

竞赛 python+深度学习+opencv实现植物识别算法系统

0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 基于深度学习的植物识别算法研究与实现 &#x1f947;学长这里给一个题目综合评分(每项满分5分) 难度系数&#xff1a;4分工作量&#xff1a;4分创新点&#xff1a;4分 &#x1f9ff; 更多…

jupyter 设置工作目录

本博客主要介绍&#xff1a; 如何为jupyter设置工作目录 1.打开 anaconda prompt , 执行 jupyter notebook --generate-config 执行这个命令后会生成一个配置文件 2. 打开jupyter_notebook_config.py文件编辑 搜索notebook_dir&#xff0c;把这行代码的注释取消&#xff0c;…

Java学习笔记(23)

多线程 并发 并行 多线程实现方式 1.继承Thread类 自己创建一个类extends thread类 Start方法开启线程&#xff0c;自动执行重写之后的run方法 2.实现runable接口 自己创建一个类implements runnable Myrun不能直接使用getname方法&#xff0c;因为这个方法是thread类的方法…

win11 环境配置 之 Jmeter(JDK17版本)

一、安装 JDK 1. 安装 jdk 截至当前最新时间&#xff1a; 2024.3.27 jdk最新的版本 是 官网下载地址&#xff1a; https://www.oracle.com/java/technologies/downloads/ 建议下载 jdk17 另存为到该电脑的 D 盘下&#xff0c;新建jdk文件夹 开始安装到 jdk 文件夹下 2. 配…

C#基础知识总结

C语言、C和C#的区别 ✔ 面向对象编程&#xff08;OOP&#xff09;&#xff1a; C 是一种过程化的编程语言&#xff0c;它不直接支持面向对象编程。然而&#xff0c;C 是一种支持 OOP 的 C 的超集&#xff0c;它引入了类、对象、继承、多态等概念。C# 是完全面向对象的&#xff…

neo4j相同查询语句一次查询特慢再次查询比较快。

现象&#xff1a; neo4j相同查询语句一次查询特慢再次查询比较快。 分析&#xff1a; 查询语句 //查询同名方法match(path:Method) where id(path) in [244333030] and NOT path:Constructor//是rpc的方法match(rpc_method:Method)<-[:DECLARES]-(rpc_method_cls:Class) -…

实现ls -l 功能,index,rindex函数的使用

index(); rindex();----------------------------------------------------------------- index第一次遇到字符c&#xff0c;rindex最后一次遇到字符c&#xff0c;返回值都是从那个位置开始往后的字符串地址 #include <stdio.h> #include <sys/types.h> #include &…

【2023】kafka入门学习与使用(kafka-2)

目录&#x1f4bb; 一、基本介绍1、产生背景2、 消息队列介绍2.1、消息队列的本质作用2.2、消息队列的使用场景2.3、消息队列的两种模式2.4、消息队列选型&#xff1a; 二、kafka组件1、核心组件概念2、架构3、基本使用3.1、消费消息3.2、单播和多播消息的实现 4、主题和分区4.…

阿里云2核4G服务器租用价格_30元3个月_165元一年_199元

阿里云2核4G服务器租用优惠价格&#xff0c;轻量2核4G服务器165元一年、u1服务器2核4G5M带宽199元一年、云服务器e实例30元3个月&#xff0c;活动链接 aliyunfuwuqi.com/go/aliyun 活动链接如下图&#xff1a; 阿里云2核4G服务器优惠价格 轻量应用服务器2核2G4M带宽、60GB高效…

智慧城市数字孪生,综合治理一屏统览

现代城市作为一个复杂系统&#xff0c;牵一发而动全身&#xff0c;城市化进程中产生新的矛盾和社会问题都会影响整个城市系统的正常运转。智慧城市是应对这些问题的策略之一。城市工作要树立系统思维&#xff0c;从构成城市诸多要素、结构、功能等方面入手&#xff0c;系统推进…

Python面对对象 - 类的反射机制

Python面对对象类的反射机制是面向对象编程语言中比较重要的功能&#xff0c;可以动态获取对象信息以及动态调用对象。通过字符串形式的类名或属性来访问对应类或属性。 一、对象的反射 1. getattr 获取指定字符串名称的对象属性、方法&#xff1a; 当访问的属性不存在时&#…

微服务(基础篇-007-RabbitMQ)

目录 初识MQ(1) 同步通讯&#xff08;1.1&#xff09; 异步通讯&#xff08;1.2&#xff09; MQ常见框架&#xff08;1.3&#xff09; RabbitMQ快速入门(2) RabbitMQ概述和安装&#xff08;2.1&#xff09; 常见消息模型&#xff08;2.2&#xff09; 快速入门&#xff…

分布式理论:CAP理论 BASE理论

文章目录 1. CAP定理1.1 一致性1.3 分区容错1.4 矛盾 2. BASE理论3. 解决分布式事务的思路4. 扩展 解决分布式事务问题&#xff0c;需要一些分布式系统的基础知识作为理论指导。 1. CAP定理 Consistency(一致性): 用户访问分布式系统中的任意节点&#xff0c;得到的数据必须一…

【opencv】教程代码 —features2D(2)

使用SURF算法检测两幅图关键点后暴力匹配 SURF特征检测 使用SURF&#xff08;Speeded Up Robust Features&#xff09;算法来检测两张图像之间的关键点&#xff0c;并使用FLANN&#xff08;Fast Library for Approximate Nearest Neighbors&#xff09;基于特征描述符向量进行匹…