Boost搜索引擎

本文档详细介绍了如何实现一个基于Boost库的站内搜索引擎,涵盖了功能与框架、技术栈与项目环境、数据去标签、正排和倒排索引的建立、搜索模块、网络模块以及前端模块。主要使用C++、Boost、Jsoncpp和cppjieba等技术,旨在提高搜索效率,提供标题、摘要和URL的搜索结果。

目录

一·功能和框架

二·技术栈与项目环境

三·具体代码结构

​编辑 四·项目背景

 五·项目宏观原理

 六·数据去标签模块

七·建立索引模块

建立正排索引

 建立倒排索引

倒排原理解析

 八·建立搜索模块

将index设置为单例模式

九·网络模块

十·前端模块


一·功能和框架

功能:实现boost文档站内搜索。通过输入关键字,将与关键字有关的网页按文档权值大小,罗列出来。前端显示包括,标题,摘要,网址~

框架:

二·技术栈与项目环境

 技术栈:

c/c++、c++11、STL、准标准库boost、Jsoncpp、cppjieba、cpp-httplib

项目环境:

Linux CentOS 7云服务器、vim/gcc(g++)/Makefile、vscode 

 

三·具体代码结构

 四·项目背景

        项目与日常搜索搜索网站不同,如百度,360,搜狗。此搜索引擎只支持boost库1.78版本站内搜索

boost库:

        

 我们平时在网上搜索的内容都以三个内容返回给我们;标题,摘要,网页url

我们在数据清理阶段只需要对boost/html下的文件标题,摘要,url进行处理即可

 五·项目宏观原理

 六·数据去标签模块

我们下载到linux中的boost1.78文档中有好多东西是我们不需要的

 以上<title></title>和划线的都是不需要的我们将这一些去掉并将这些文档内容按每个文档:

文档1:标题\3摘要\3/url\n

文档2:标题\3摘要\3/url\n

...

以此这样排列好放在一个特定目录下方便我们进行检索

在进行原始文件的处理时用到了boost库开发的工具就掠过吧~

去标签代码:parser.cc

//判断文件是否为html后缀文件,是的话就放在一个集合进行统一处理
bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list);
//解析文件将文件标题,目录,URl按照我们上面说的方式整理放在一个集合。
bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results);
//将处理好的html文件(已经处理好的去标签,数据清洗完的。统一放在output文件里。每个文件按\n分割)
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output);
int main()
{
  std::vector<std::string> files_list;
  //第一步: 递归式的把每个html文件名带路径,保存到files_list中,方便后期进行一个一个的文件进行读取
  if (!EnumFile(src_path, &files_list))
  {
    std::cerr << "enum file name error!" << std::endl;
    return 1;
  }
  // 第二步: 按照files_list读取每个文件的内容,并进行解析
  std::vector<DocInfo_t> results;
  if (!ParseHtml(files_list, &results))
  {
    std::cerr << "parse html error" << std::endl;
    return 2;
  }

  // //第三步: 把解析完毕的各个文件内容,写入到output,按照\3作为每个文档的分割符
  if (!SaveHtml(results, output))
  {
    std::cerr << "sava html error" << std::endl;
    return 3;
  }

  return 0;
}

bool EnumFile(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))
  {
    std::cerr << src_path << " not exists" << std::endl;
    return false;
  }

  //定义一个空的迭代器,用来进行判断递归结束
  fs::recursive_directory_iterator end;
  for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++)
  {
    //判断文件是否是普通文件,html都是普通文件
    if (!fs::is_regular_file(*iter))
    {
      continue;
    }
    if (iter->path().extension() != ".html")
    { //判断文件路径名的后缀是否符合要求
      continue;
    }
    std::cout << "debug: " << iter->path().string() << std::endl;
    //当前的路径一定是一个合法的,以.html结束的普通网页文件
    files_list->push_back(iter->path().string()); //将所有带路径的html保存在files_list,方便后续进行文本分析
  }

  return true;
}

static bool ParseTitle(const std::string &file, std::string *title)
{
  std::size_t begin = file.find("<title>");
  if (begin == std::string::npos)
  {
    return false;
  }
  std::size_t end = file.find("</title>");
  if (end == std::string::npos)
  {
    return false;
  }

  begin += std::string("<title>").size();

  if (begin > end)
  {
    return false;
  }
  *title = file.substr(begin, end - begin);
  return true;
}

static bool ParseContent(const std::string &file, std::string *content)
{
  //去标签,基于一个简易的状态机
  enum status
  {
    LABLE,
    CONTENT
  };

  enum status s = LABLE;
  for (char c : file)
  {
    switch (s)
    {
    case LABLE:
      if (c == '>')
        s = CONTENT;
      break;
    case CONTENT:
      if (c == '<')
        s = LABLE;
      else
      {
        //我们不想保留原始文件中的\n,因为我们想用\n作为html解析之后文本的分隔符
        if (c == '\n')
          c = ' ';
        content->push_back(c);
      }
      break;
    default:
      break;
    }
  }

  return true;
}

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

  *url = url_head + url_tail;
  return true;
}

// // for debug
sta
<think>我们正在讨论一个基于BoostC++Libraries的搜索引擎项目。根据提供的引用内容,我们可以了解到该项目的一些关键信息:1.项目目标:构建一个针对Boost库文档的搜索引擎2.技术栈:-C++11,STL,Boost-Jsoncpp:用于数据交换-cppjieba:用于中文分词(虽然Boost文档是英文的,但这里使用了分词,可能是为了通用性)-cpp-httplib:构建HTTP服务器-前端:HTML5,CSS,jQuery,JavaScript,Ajax3.数据来源:Boost官网下载的HTML文件(即Boost库的文档)4.核心原理:正排索引和倒排索引从引用[3]中,我们可以看到一个关键函数`create_inverted_index`,它用于创建倒排索引。该函数对每个文档(即一个HTML文件)进行处理:-对标题和内容分别进行分词(这里使用了`ns_helper::JiebaUtil::CutString`)-将所有单词转换为小写(使用`boost::to_lower`实现大小写不敏感)-统计每个词在标题和内容中出现的次数,并计算权重(标题中出现的权重更高)-将每个词及其对应的文档ID和权重添加到倒排索引中实现方案步骤:1.**数据准备**:-从Boost官网下载文档(HTML文件),如引用[4]所述,位于`/doc/html`目录下。-清理HTML文件,提取出我们需要搜索文本内容(去除标签等)。2.**建立索引**:-**正排索引**:以文档ID为键,存储文档的元信息(如标题、内容、URL等)。可以是一个数组或vector,下标即文档ID。-**倒排索引**:以词为键,存储包含该词的文档ID列表以及权重。如引用[3]所示,每个词对应一个列表,列表元素为`word_info`结构(包含文档ID和权重)。3.**分词处理**:-使用cppjieba对文档内容进行分词(注意:虽然Boost文档是英文的,但分词库同样可以处理英文,按空格和标点分词)。4.**索引构建优化**:-考虑使用多线程或并行处理加速索引构建。-注意内存管理,如果数据量大,可能需要分块构建索引然后合并。5.**服务器构建**:-使用cpp-httplib搭建HTTP服务器,提供搜索接口。-设计RESTfulAPI,例如`/search?query=xxx`。6.**搜索处理**:-接收用户查询字符串,同样进行分词、小写化等处理。-根据倒排索引查找包含这些词的文档。-计算每个文档的相关性得分(如TF-IDF或其他算法),这里引用[3]中使用了简单的权重(标题权重10,内容权重1)。-对结果按得分排序,返回前K个结果。7.**结果返回**:-将搜索结果以JSON格式(使用Jsoncpp)返回给前端。-前端通过Ajax获取结果并渲染。8.**前端界面**:-设计搜索页面,用户输入关键词,点击搜索。-使用Ajax发送请求到后端,获取并展示搜索结果(包括标题、摘要、链接等)。9.**部署**:-在CentOS7服务器上部署,使用Makefile编译项目。注意细节:-大小写不敏感:在索引构建和查询时,将单词统一转换为小写。-权重设计:标题中的词比内容中的词更重要,因此给予更高的权重。这是一个简化的实现方案。实际项目中还需要考虑很多其他因素,比如停用词过滤、词干提取、性能优化等。相关问题:1.如何优化倒排索引的构建速度?2.在搜索相关性排序中,除了简单的权重叠加,还有哪些常用算法?3.如何实现搜索结果的分页?4.如何处理用户查询中的特殊字符?5.如何提高搜索的响应速度?</think> ### Boost C++ Libraries 搜索引擎项目实现方案 根据提供的引用内容[^1][^2][^3][^4],Boost搜索引擎项目的核心实现方案如下: #### 1. **数据准备阶段** - **文档来源**:从Boost官网下载HTML格式的文档(如`/doc/html`目录下的文件)作为原始数据[^4]。 - **文档解析**:提取HTML中的标题(`<title>`)和正文内容(`<body>`),去除标签保留纯文本。 #### 2. **索引构建(核心)** 采用**正排索引 + 倒排索引**的双索引结构[^2]: - **正排索引**(文档ID → 内容) 存储每个文档的元数据: ```cpp struct docInfo_index { int doc_id_; // 文档唯一ID std::string title_; // 文档标题 std::string content_; // 去标签后的正文 }; ``` - **倒排索引**(关键词 → 文档列表) 通过`create_inverted_index`函数构建[^3]: ```cpp void create_inverted_index(const docInfo_index &doc) { std::unordered_map<std::string, word_cnt> cnt_map; // 1. 分词处理(使用cppjieba) std::vector<std::string> content_words = jieba.cut(doc.content_); std::vector<std::string> title_words = jieba.cut(doc.title_); // 2. 词频统计(大小写不敏感) for (auto &word : content_words) { boost::to_lower(word); // 统一转为小写 cnt_map[word].content_cnt_++; } for (auto &word : title_words) { boost::to_lower(word); cnt_map[word].title_cnt_++; } // 3. 权重计算(标题词权重更高) #define title_weight 10 #define content_weight 1 for (auto &[word, cnt] : cnt_map) { int weight = cnt.title_cnt_ * title_weight + cnt.content_cnt_ * content_weight; inv_index[word].push_back({doc.doc_id_, weight}); } } ``` **权重设计**:标题词权重(10) > 正文词权重(1),提升标题匹配的优先级[^3]。 #### 3. **搜索服务架构** ![](https://via.placeholder.com/600x200?text=搜索引擎架构图) *架构示意图:数据预处理→索引构建→HTTP服务→前端交互* - **技术栈组合**: - **后端**:C++11、Boost、cppjieba(分词)、cpp-httplib(HTTP服务器) - **数据交换**:Jsoncpp序列化搜索结果 - **前端**:HTML5/CSS/jQuery + Ajax异步请求[^2] - **搜索流程**: ```mermaid sequenceDiagram 前端->>+后端: HTTP GET /search?q=关键词 后端->>分词模块: jieba.cut(关键词) 分词模块-->>后端: 分词结果[词1,词2,...] 后端->>倒排索引: 查询每个词的文档列表 倒排索引-->>后端: {doc_id, weight} 后端->>排序模块: 按权重降序排序 后端->>+前端: JSON格式结果{title, snippet, url} ``` #### 4. **关键优化点 - **大小写不敏感**:通过`boost::to_lower`统一转换[^3] - **分词处理**:对中/英文混合查询友好(虽然Boost文档主要为英文) - **分布式扩展**:索引分片存储,支持横向扩展(引用未提及但建议) #### 5. **部署环境** - **操作系统**:CentOS 7 - **工具链**:gcc/g++、makefile、vscode - **服务部署**:通过cpp-httplib暴露HTTP接口,Nginx反向代理 [^1]: Boost库提供C++扩展功能,包含哈希、智能指针等组件 [^2]: 项目采用正排/倒排索引结构,使用多语言技术栈实现 [^3]: 倒排索引通过权重策略提升标题词的重要性 [^4]: 数据源直接使用Boost官网下载的HTML文档
评论 4
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值