c++实现boost库 搜索引擎(详细介绍和代码),cppjieba的下载和使用,正排/倒排索引的查询和建立,cpp-httplib的下载和使用

目录

boost库 搜索引擎

项目背景

引入

表现形式

boost库介绍

项目环境

数据源

下载文档

页面目录

查看html文件的数量

技术栈

原理

过程

正排/倒排索引

正排索引

分词

暂停/停止词

倒排索引

模拟查找过程

parser模块

读取文件

标签

如何存放

代码编写思路

遍历目录

读取文件

格式化

标题

正文

代码

注意

构建url

借助move

添加分隔符

建立索引模块

正排索引

倒排索引

查找索引

建立索引

读取文档

建立正排索引

切分字符串 -- split

插入元素

代码 

建立倒排索引

思路

分词 -- cppjieba

确定权重

忽略大小写

插入元素

代码

搜索引擎模块     

索引对象单例化                                                

搜索

流程

忽略大小写

查询倒排索引

得到集合

去重

排序

查询正排索引

引入jsoncpp

截取文档摘要

代码 

服务器模块

cpp-httplib

devtoolset

创建对象

设置根目录

处理请求

获取请求

获取搜索内容

调用搜索模块

代码 

运行结果

前端模块

代码

运行结果

代码结构


boost库 搜索引擎

项目背景

引入

市面上已经有很多公司设计出很多的搜索引擎

  • 百度,搜狗,goole,360搜索等等
  • 这种大型的项目我们一个人是没办法完成的,因为它是全网搜索,涉及到的内容过于庞大

但我们可以实现站内搜索

  • 比如cplusplus.com

与全网搜索的不同点在于,站内搜索得到的结果更垂直,数据量更小

  • 垂直 -- 数据之间具有很强的相关性

表现形式

搜索引擎以什么方式显示给用户?

  • 搜索框+搜索按钮

搜索关键字后,每个搜索结果基本由三大部分组成:

  • 并且,提供跳转网页的功能
  • 其他的搜索引擎也基本是这些内容,只是细节有所不同

boost库介绍

Boost库是一个广泛使用的C++库集合,提供了许多功能强大且高效的工具和组件,可以帮助开发者提高代码的质量和效率

  • Boost库包含超过160个独立的库,这些库各自提供特定的功能,包括数据结构、算法、并发编程、网络编程等

但是boost库的官网并没有提供搜索功能,但网站提供的资源量非常大

  • 所以需要我们自己做一个boost库的搜索引擎
  • 注意,搜索的是boost官网上罗列的手册(接口什么的介绍),而不是boost库的源码

项目环境

centos7云服务器,vim,gcc/g++,makefile,vscode

数据源

下载文档

在boost官网下可以下载 -- Boost C++ Libraries

  • 点击下图的download

然后将下载的文件上传到云服务器下

  • 如果在上传过程中出现乱码(文件如果很大,就可能会出现乱码)
  • 可以在使用rz命令时添加E选项

上传成功后,进行解压缩

页面目录

我们在boost官网下的文档进行查询时,点击其中某个标签页,会发现得到的新页面大多数是放在/doc/html目录下的

  • 所以我们在后续使用该网页上的文档作为搜索引擎数据源时,就只需要使用/doc/html目录下的文件即可

这些文件就是boost各个组件对应的手册内容,以网页形式存在

  • 我们后面就用它们来建立索引
  • 所以我们直接将这个目录拷贝到我们项目文件中

不过也有不在doc下的网页文件,但我们不考虑这些

查看html文件的数量

我们可以查看一下我们的目标目录中一共有多少html文件:

  • ls -Rl | grep -E '*.html' | wc -l

技术栈

  • c/c++,c++11,stl,boost库
  • jsoncpp -- cs两端进行数据交换的格式
  • cppjieba -- 分词工具(对文档和用户输入内容进行分词)
  • cpp-httplib -- 构建http服务器
  • html5,css,JavaScript,jQuery,ajax -- 前端内容

原理

过程

客户端(pc或手机)

  • 上面会运行着很多软件(浏览器)

服务器(比如公司服务主机)

  • 上面也会服务运行软件(searcher)

在提供服务前,需要在各个网站中抓取网页,放入主机磁盘中

  • 并且对抓取到的数据进行处理,并建立索引
  • 完成之后,就可以基于搜索引擎进行搜索了

用户通过浏览器

  • 向服务器发送http请求,其中携带有搜索关键字

服务器接收后

  • 使用关键字在索引中进行检索,得到相关网页
  • 最后将多个网页信息经过包装(title+desc+url),形成一个新的网页后,返回给客户端

我们这里要完成的内容,就是红框内的功能

  • 至于爬虫,我们可以通过正规渠道将目标网站的内容下载下来,也是一样的(也就是前面说的数据源)

正排/倒排索引

假设有两个文档

正排索引

文档id 找到 文档内容

建立正排索引:

分词

将一段文本切分成更小的单元(称为“词”或“标记”)

我们建立搜索引擎,需要对目标文档分词

  • 目的 -- 方便建立倒排索引和查找

可以分出来的不止这些词语

  • 因为有些词语是可以连起来的
  • 比如四斤小米,或是直接是整句话,总之会有很多种组合方式
暂停/停止词

对文本的意义或分析贡献较小的常见词汇

  • 通常用于构建句子的结构,帮助表达语法关系,但对于主题识别和信息检索的贡献有限
  • 所以,区分唯一性的价值不大,还会增加搜索成本,一般会在分词的时候忽略掉
  • 比如 : 了,的,在,是,吗,a,the 

倒排索引

根据关键字(也就是我们对文档进行分词后得到的结果),找到文档id

  • 关键字具有唯一性,如果关键字在多个文档中出现,只保留一份

建立倒排索引 -- 我们将文档内容分词后,整理出不重复的关键字,与文档id联系起来 

模拟查找过程

接下来,基于这两个索引,我们来模拟一次查找的过程:

假设用户输入"小米"

  • 那第一步一定是使用"小米"在倒排索引中进行查找,提取出对应的文档id(1,2)
  • 再拿着文档id在正排索引中查找,找到两个文档对应的内容,然后分别对文档结果进行格式化(提取出title+desc+url)
  • 最后将结果以网页的形式构建出响应,返回给用户

因为可能有多个文档与关键字匹配

  • 所以还需要给每个文档赋权值,谁的权重更高,就把哪个文档显示在前面
  • 就像是在各种搜索引擎上搜索出来的内容,一定会经过排序的,而顺序一定是由权重决定的

parser模块

整体思路 -- 对下载下来的文档信息(网页)进行去标签和数据清洗

读取文件

首先肯定是要先拿到文件,再对文件进行处理

  • 也就是需要先找到所有文件名,以vector的形式组织起来
  • 然后挨个进行读取

因为c++和stl对文件系统的支持不是特别好,所以我们需要使用boost库中的filesystem

  • boost开发库的安装 -- sudo yum install boost-devel
  • centos7下默认下载的是1.53版本的boost开发库,所以我们去官网上查看接口使用方法时,也应该查看1.53版本的
  • 注意:开发库 和 官网上下载到的文档(手册网页信息) ,不是一个东西

查看手册中filesystem的教程,并随便点击一个函数,进入filesystem库的接口说明:

因为boost库并不是c++的标准库,所以我们需要编译语句中指明我们要使用boost库

  • 否则会链接错误 -- -lboost_system  和 -lboost_filesystem

标签

这里截取一部分html目录下某文件的内容:

html的标签都被<>包裹起来

  • 对搜索没有意义,只是用来组成网页格式,并且这些标签在每个html文件中都会存在
  • 我们需要的是去掉这些标签后的部分,这才是对于搜索引擎来说的有效数据
  • 所以需要去标签

标签有成对出现的,也有单独出现的

  • eg:<head> 和 </head>,<link...>

如何存放

将文件数据做完去标签化后,该放在哪里呢?

  • 新建一个文件夹,并只创建一个文件,再将每个文档去标签的内容都写入到该文件
  • 每个文档之间用特殊符号隔开,相当于每个文档的内容只占"一行"

因为文档中的字符基本都是打印字符,是可显的

  • 控制字符是不可显的,就不会污染我们形成的新的文档
  • 所以我们可以选择使用控制字符作为分隔符

于是我们就有了html文档的原始数据和有效内容

代码编写思路

遍历目录

将html文档所在目录定义成一个path对象

  • 并在核心逻辑开始前,判断该路径是否存在

我们这里使用boost库提供的迭代器(注意,一定要使用递归迭代器recursive_directory_iterator,但在前期测试的时候可以使用普通迭代器directory_iterator,不然每次运行都可慢)

  • 迭代遍历目录下的子文件,直到为空
  • 迭代方式就和迭代查询一样,会将目录下所有文件都查出来,包括子目录下的文件

但遍历时,可能遍历到的文件不是html文件,而是其他文件

  • 所以,需要判断
  • 是否是常规文件 -- is_regular_file()
  • 后缀是否是.html -- extension()

path()

  • 提取迭代器指向的路径对象

string()

  • 获取路径对应的字符串形式(可以用来debug,以及传参)
读取文件

我们可以借助c++的文件流对象

  • 打开文件可以使用直接构建文件流对象的形式,然后结合getline读取

如何理解getline读取到文件结束?

  • getline的返回值是一个引用,但while判断的是bool类型
  • 判断过程的本质是因为重载了强制类型转化

我们可以将像这样的辅助函数全部写在一个文件中,并且限制下作用域

格式化

根据每个文档的内容都形成三个部分,方便我们进行后续操作

接下来是提取三大部分

标题

每个文档的标题都在<titile>...</title>内

  • 所以,提取的重点就是识别出这一对标签

然后根据迭代器位置,进行截取

  • 注意,在截取之前,我们还需要考虑一种情况,虽然这种情况的概率很小:begin在end之后
  • 这样的话就会导致截取到的字符串的字符个数是负数,不符合常理
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值