Boost搜索引擎

1.项目相关背景

百度,搜狐,360等搜索引擎;

boost的官网是没有站内搜索的。

2.搜索引擎的相关宏观原理

Boost搜索引擎_第1张图片

 爬虫程序我就不做了,受国家的法律法规的限制,我就通过正规的下载途径来做。

3.搜索引擎技术栈和项目环境

技术栈 : C/C++ C++11, STL, 准标准库 Boost Jsoncpp cppjieba cpp - httplib , html5 css js 、jQuery、 Ajax
项目环境: Centos 7 云服务器, vim/gcc(g++)/Makefile , vs2019 or vs code

4.正排序引VS倒排序引-搜索引擎具体原理

文档 1 : 雷军买了四斤小米
文档 2 : 雷军发布了小米手机
正排索引:就是从文档 ID 找到文档内容 ( 文档内的关键字 )
Boost搜索引擎_第2张图片

目标文档进行分词(目的:方便建立倒排索引和查找):

文档 1[ 雷军买了四斤小米 ]: 雷军 / / 四斤 / 小米 / 四斤小米
文档 2[ 雷军发布了小米手机 ] :雷军 / 发布 / 小米 / 小米手机
停止词:了,的,吗, a the,一般我们在分词的时候可以不考虑
倒排索引:根据文档内容,分词,整理不重复的各个关键字,对应联系到文档 ID 的方案
关键字(具有唯一性) 文档,weight(权重)
雷军 文档1,文档2
文档1
四斤 文档1
小米         文档1,文档2
四斤小米 文档1
发布 文档2
小米手机 文档2

模拟一次查找的过程:

用户输入:小米 -> 倒排索引中查找 -> 提取出文档 ID(1,2) -> 根据正排索引 -> 找到文档的内容 ->
title+conent (desc) +url 文档结果进行摘要 -> 构建响应结果

5.编写数据去标签与数据清洗的模块Parser

boost 官网: https : //www.boost.org/
// 目前只需要 boost_1_78_0/doc/html 目录下的 html 文件,用它来进行建立索引
去标签
[ whb@VM - 0 - 3 - centos boost_searcher ] $ touch parser . cc
// 原始数据 -> 去标签之后的数据
DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd" >
< html >
< head >
< meta http - equiv = "Content-Type" content = "text/html; charset=UTF-8" >
< title > Chapter 30. Boost . Process title >
< link rel = "stylesheet" href = "../../doc/src/boostbook.css" type = "text/css" >
< meta name = "generator" content = "DocBook XSL Stylesheets V1.79.1" >
< link rel = "home" href = "index.html" title = "The Boost C++ Libraries BoostBook Documentation
Subset" >
< link rel = "up" href = "libraries.html" title = "Part I. The Boost C++ Libraries (BoostBook
Subset)" >
< link rel = "prev" href = "poly_collection/acknowledgments.html" title = "Acknowledgments" >
< link rel = "next" href = "boost_process/concepts.html" title = "Concepts" >
head >
< body bgcolor = "white" text = "black" link = "#0000FF" vlink = "#840084" alink = "#0000FF" >
< table cellpadding = "2" width = "100%" >< tr >
< td valign = "top" >< img alt = "Boost C++ Libraries" width = "277" height = "86"
src = "../../boost.png" > td >
< td align = "center" >< a href = "../../index.html" > Home a > td >
< td align = "center" >< a href = "../../libs/libraries.htm" > Libraries a > td >
< td align = "center" >< a href = "http://www.boost.org/users/people.html" > People a > td >
< td align = "center" >< a href = "http://www.boost.org/users/faq.html" > FAQ a > td >
< td align = "center" >< a href = "../../more/index.htm" > More a > td >
tr > table >
.........
// <> : html 的标签,这个标签对我们进行搜索是没有价值的,需要去掉这些标签,一般标签都是成对出现的!
[ whb@VM - 0 - 3 - centos data ] $ mkdir raw_html
[ whb@VM - 0 - 3 - centos data ] $ ll
total 20
drwxrwxr - x 60 whb whb 16384 Mar 24 16 : 49 input // 这里放的是原始的 html 文档
drwxrwxr - x 2 whb whb 4096 Mar 24 16 : 56 raw_html // 这是放的是去标签之后的干净文档
[ whb@VM - 0 - 3 - centos input ] $ ls - Rl | grep - E '*.html' | wc - l
8141
目标:把每个文档都去标签,然后写入到同一个文件中!每个文档内容不需要任何 \n !文档和文档之间用 \3 区分
version1
类似: XXXXXXXXXXXXXXXXX\3YYYYYYYYYYYYYYYYYYYYY\3ZZZZZZZZZZZZZZZZZZZZZZZZZ\3
采用下面的方案:
version2 : 写入文件中,一定要考虑下一次在读取的时候,也要方便操作 !
类似: title\3content\3url \n title\3content\3url \n title\3content\3url \n ...
方便我们 getline ( ifsream , line ) ,直接获取文档的全部内容: title\3content\3url
编写 parser
#include
#include
#include
#include
#include"util.hpp"


const std::string src_path = "data/input/";   //所有的html
const std::string output = "data/raw_html/raw.txt"; //解析所有完的html

typedef  struct DocInfo54
{
    std::string title;    //文档的标题
    std::string content;  //文档的内容
    std::string url;      //该文档在官网的url
}DocInfo_t;

bool EnumFile(const std::string &src_path,std::vector *file_list);
bool ParseHtml(std::vector& file_list,std::vector *results);
bool SaveHtml(std::vector& results,const std::string &output);



static bool ParseTitle(const std::string &result,std::string *title) 
{
    size_t begin = result.find("");
    if(begin == std::string::npos)
    {
        return false;
    }
    size_t end = result.find("");
    if(end == std::string::npos)
    {
        return false;
    }
    begin += std::string("").size();
    if(begin > end)
    {
        return false;
    }
    *title = result.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(auto e :file)
    {
        switch (s)
        {
        case LABLE:
            if(e == '>')  //代表结束
                s = CONTENT;
            /* code */
            break;
        case CONTENT:
            if(e == '<') //代表开始
                s = LABLE;
            else
            {
                if(e == '\n') e = ' '; 
                *content += e;
            }
        break;
        default:
            break;
        }
    }
    return true;
}
static bool ParseUrl(const std::string &file,std::string *url)
{
    std::string url_head = "https://www.boost.org/doc/libs/1_79_0/doc/html/";
    std::string url_tail = file.substr(src_path.size());
    *url = url_head + url_tail;
    return true;
}

int main()
{
    //第一步拿到所有文件名
    std::vector<std::string> files_list;
    if(!EnumFile(src_path,&files_list))
    {
        std::cerr<<"enum file name error"<<std::endl;
        return 1;
    }
    //第二步解析文件
    std::vector<DocInfo_t> results;
    if(!ParseHtml(files_list,&results))
    {
        std::cerr<<"parse is error"<<std::endl;
        return 2;
    }
    //第三步,把解析完毕的各个文件内容,写入output,按照\3作为每个文档的分隔符
    if(!SaveHtml(results,output))
    {
        std::cerr<<"save html error"<<std::endl;
        return 3;
    }
    return 0;
}

bool EnumFile(const std::string &src_path,std::vector<std::string> *file_list)  //拿到所有html文件名
{
    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 it(root_path); it != end; ++it)
    {
        if(!fs::is_regular_file(*it)) //如果不是普通文件继续
        {
            continue;
        }
        if(it->path().extension() != ".html")
        {
            continue;
        }
        //测试
        //std::cout<<"debug"<<it->path().string()<<std::endl;
        file_list->push_back(it->path().string());
    }

    return true;
}
void ShowInfo(const DocInfo_t &doc)
{
    std::cout<<doc.title<<std::endl;
    std::cout<<doc.content<<std::endl;
    std::cout<<doc.url<<std::endl;
}
bool ParseHtml(std::vector<std::string>& file_list,std::vector<DocInfo_t> *results)//拿到所有html的标题,内容,url
{
    for(const auto  file : file_list)
    {
        //1读取文件
        std::string result;
        if(!ns_util::FileUtil::ReadFile(file,&result))
        {
            //文件读取失败
            continue;
        }
        DocInfo_t doc;
        //2提取标签
        if(!ParseTitle(result,&doc.title))
        {
            continue;;
        }
        //3提取内容
        if(!ParseContent(result,&doc.content))
        {
            continue;
        }
        //4提取url
        if(!ParseUrl(file,&doc.url))
        {
            continue;
        }
        //将结果出入到vector,这里有拷贝问题,以后在优化
        results->push_back(std::move(doc)); //采用右值,资源转移
        //for debug
        //ShowInfo(doc);
        //break;
    }
    return true;
}
bool SaveHtml(std::vector<DocInfo_t>& results,const std::string &output)
{
#define SEP '\3'
    std::ofstream of(output,std::ios::out | std::ios::binary);
    if(!of.is_open())
    {
        std::cerr<<"open"<<output<<"fail"<<std::endl;
        return false;
    }
    //写入文件
    for(const auto &item : results)
    {
        std::string  out_result;
        out_result = item.title;
        out_result += SEP;
        out_result += item.content;
        out_result += SEP;
        out_result += item.url;
        out_result += '\n';

        of.write(out_result.c_str(),out_result.size());
    }
    of.close();
    return true;
}
</code></pre> 
         <div> <span style="color:#333333;"><strong>boost 开发库的安装</strong></span> 
         </div> 
         <div> <span style="color:#333333;"><strong>s</strong></span> <span style="color:#000000;">udo yum install </span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">y boost</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">devel </span> <span style="color:#aa5500;">//</span> <span style="color:#aa5500;">是</span> <span style="color:#aa5500;">boost </span> <span style="color:#aa5500;">开发库</span> 
         </div> 
         <div> <span style="color:#333333;"><strong>提取</strong></span> <span style="color:#333333;"><strong>title</strong></span> 
         </div> 
         <div> <a href="http://img.e-com-net.com/image/info8/14c2343be1354817ac967242fc52a4a7.jpg" target="_blank"><img alt="Boost搜索引擎_第3张图片" height="188" src="http://img.e-com-net.com/image/info8/14c2343be1354817ac967242fc52a4a7.jpg" width="650" style="border:1px solid black;"></a> 
         </div> 
         <p> <a href="http://img.e-com-net.com/image/info8/b679405e75b642eca2ae3acb0e4a0529.jpg" target="_blank"><img alt="Boost搜索引擎_第4张图片" height="182" src="http://img.e-com-net.com/image/info8/b679405e75b642eca2ae3acb0e4a0529.jpg" width="650" style="border:1px solid black;"></a></p> 
         <p><a href="http://img.e-com-net.com/image/info8/5ac7a5f875824b6983107c02f5b7c3cf.jpg" target="_blank"><img alt="Boost搜索引擎_第5张图片" height="393" src="http://img.e-com-net.com/image/info8/5ac7a5f875824b6983107c02f5b7c3cf.jpg" width="650" style="border:1px solid black;"></a> <span style="color:#333333;">在进行遍历的时候,只要碰到了 </span><span style="color:#333333;">> </span><span style="color:#333333;">,</span><span style="color:#333333;">就意味着,当前的标签被处理完毕</span><span style="color:#333333;">. </span><span style="color:#333333;">只要碰到了 </span><span style="color:#333333;">< </span><span style="color:#333333;">意味着新的标签开始了</span></p> 
         <p><span style="color:#333333;"><strong>构建</strong></span><span style="color:#333333;"><strong>URL </strong></span></p> 
         <div> <span style="color:#333333;">boost</span> <span style="color:#333333;">库的官方文档,和我们下载下来的文档,是有路径的对应关系的</span> 
         </div> 
         <div> 
          <div> <span style="color:#333333;">官网</span> <span style="color:#333333;">URL</span> <span style="color:#333333;">样例: </span> <span style="color:#333333;">https://www.boost.org/doc/libs/1_78_0/doc/html/accumulators.html </span> 
          </div> 
          <div> <span style="color:#333333;">我们下载下来的</span> <span style="color:#333333;">url</span> <span style="color:#333333;">样例:</span> <span style="color:#333333;">boost_1_78_0/doc/html/accumulators.html </span> 
          </div> 
          <div> <span style="color:#333333;">我们拷贝到我们项目中的样例:</span> <span style="color:#333333;">data/input/accumulators.html //</span> <span style="color:#333333;">我们把下载下来的</span> <span style="color:#333333;">boost</span> <span style="color:#333333;">库 </span> <span style="color:#333333;">doc/html/* copy </span> 
          </div> 
          <div> <span style="color:#333333;">data/input/ </span> 
          </div> 
          <div> <span style="color:#333333;">url_head = "https://www.boost.org/doc/libs/1_78_0/doc/html"; </span> 
          </div> 
          <div> <span style="color:#333333;">url_tail = [data/input](</span> <span style="color:#333333;">删除</span> <span style="color:#333333;">) /accumulators.html -> url_tail = /accumulators.html </span> 
          </div> 
          <div> <span style="color:#333333;">url = url_head + url_tail ; </span> <span style="color:#333333;">相当于形成了一个官网链接 </span> 
          </div> 
         </div> 
         <p> <span style="color:#333333;"><strong>将解析内容写入文件中</strong></span> </p> 
         <div> <span style="color:#aa5500;">//</span> <span style="color:#aa5500;">见代码 </span> 
         </div> 
         <div> <span style="color:#000000;">采用下面的方案: </span> 
         </div> 
         <div> <span style="color:#000000;">version2</span> <span style="color:#333333;">: </span> <span style="color:#000000;">写入文件中,一定要考虑下一次在读取的时候,也要方便操作</span> <span style="color:#981a1a;">! </span> 
         </div> 
         <div> <span style="color:#000000;">类似:</span> <span style="color:#000000;">title\3content\3url \n title\3content\3url \n title\3content\3url \n </span> <span style="color:#333333;">... </span> 
         </div> 
         <div> <span style="color:#000000;">方便我们</span> <span style="color:#000000;">getline</span> <span style="color:#333333;">(</span> <span style="color:#000000;">ifsream</span> <span style="color:#333333;">, </span> <span style="color:#000000;">line</span> <span style="color:#333333;">)</span> <span style="color:#000000;">,直接获取文档的全部内容:</span> <span style="color:#000000;">title\3content\3url</span> 
         </div> 
        </div> 
       </div> 
      </div> 
     </div> 
    </div> 
   </div> 
  </div> 
  <h1>6.编写建立索引的模块Index</h1> 
  <pre><code class="language-cpp">#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <unordered_map>
#include <fstream>
#include "util.hpp"
#include <mutex>
#include"log.hpp"
namespace ns_index
{
    struct DocInfo
    {
        std::string title;   //文档标题
        std::string content; //文档对应的去标签之后的内容
        std::string url;     //官网的url
        uint64_t doc_id;     //文档的id
    };

    struct InvertedElem
    {
        uint64_t doc_id;
        std::string word;
        int weigth;
    };

    //倒排拉链
    typedef std::vector<InvertedElem> InvertedList;

    class Index
    {
    private:
        std::vector<DocInfo> forward_index;                           //正排索引
        std::unordered_map<std::string, InvertedList> inverted_index; //倒排索引
        static Index *Instance;
        static std::mutex mtx;

    private:
        Index() = default;
        Index(const Index &) = delete;
        Index &operator=(const Index &) = delete;

    public:
        ~Index() = default;
        static Index *GetInstance()
        {
            if (nullptr == Instance)
            {
                mtx.lock();
                if (nullptr == Instance)
                {
                    Instance = new Index();
                }
                mtx.unlock();
            }

            return Instance;
        }
        //根据doc_id找到文档内容
        DocInfo *GetForWardIndex(uint64_t doc_id)
        {
            if (doc_id >= forward_index.size())
            {
                std::cerr << "doc_id is error" << std::endl;
                return nullptr;
            }
            return &forward_index[doc_id];
        }
        //根据关键字string,获得倒排拉链
        InvertedList *GetInvertedList(const std::string &word)
        {
            auto it = inverted_index.find(word);
            if (it == inverted_index.end())
            {
                std::cerr << word << "have no InvertedList" << std::endl;
                return nullptr;
            }
            return &(it->second);
        }
        //根据去标签,格式化之后的文档,构建正排索引和倒排索引
        // data/raw_html/raw.txt
        bool BuildIndex(const std::string &input)
        {
            std::ifstream in(input, std::ios::in | std::ios::binary);
            if (!in.is_open())
            {
                std::cerr << "sorry" << input << "open sorry" << std::endl;
                return false;
            }
            std::string line;

            int count = 0;
            while (std::getline(in, line))
            {
                DocInfo *doc = BuildForwardIndex(line); //构建正排
                if (doc == nullptr)
                {
                    std::cerr << "build" << line << std::endl; // for debug
                    continue;
                }
                BuildInvertedIndex(*doc);
                count++;
                if(count % 50 == 0) //std::cout<<"当前已经建立的索引文档:"<<count<<std::endl;
                LOG(NORMAL, "当前的已经建立的索引文档: " + std::to_string(count));
            }
            return true;
        }

    private:
        DocInfo *BuildForwardIndex(const std::string &line)
        {
            // 1进行字符串切分
            std::vector<std::string> results;
            const std::string seq = "\3";
            ns_util::StringUtil::Split(line, &results, seq);
            if (results.size() != 3)
            {
                return nullptr;
            }
            // 2将字符串进行填充到DocInfo
            DocInfo doc;
            doc.title = results[0];
            doc.content = results[1];
            doc.url = results[2];
            doc.doc_id = forward_index.size();
            // 3插入到正排索引的vector中
            forward_index.push_back(std::move(doc));
            return &forward_index.back();
        }
        bool BuildInvertedIndex(const DocInfo &doc)
        {
            // word 倒排拉链
            struct word_cnt
            {
                /* data */
                int title_cnt;
                int content_cnt;
                word_cnt() : title_cnt(0), content_cnt(0) {}
            };
            std::unordered_map<std::string, word_cnt> word_map;
            //对标题进行分词
            std::vector<std::string> title_words;
            ns_util::JiebaUtil::CurString(doc.title, &title_words);
            for (auto s : title_words)
            {
                boost::to_lower(s); //转化成小写
                word_map[s].title_cnt++;
            }
            //对文档内容进行分词
            std::vector<std::string> contnet_word;
            ns_util::JiebaUtil::CurString(doc.content, &contnet_word);
            for (auto s : contnet_word)
            {
                boost::to_lower(s); //转化成小写
                word_map[s].content_cnt++;
            }
#define X 10
#define Y 1
            for (auto &word_pair : word_map)
            {
                InvertedElem item;
                item.doc_id = doc.doc_id;
                item.word = word_pair.first;
                //相关性
                item.weigth = X * word_pair.second.title_cnt + Y * word_pair.second.content_cnt;
                InvertedList &inverted_list = inverted_index[word_pair.first];
                inverted_list.push_back(std::move(item));
            }
            return true;    
        }
    };
    Index* Index::Instance = nullptr;
    std::mutex Index::mtx;
}</code></pre> 
  <div> <span style="color:#aa5500;">//jieba</span> <span style="color:#aa5500;">的使用</span> <span style="color:#aa5500;">--cppjieba </span> 
  </div> 
  <div> <span style="color:#000000;">获取链接: </span> <span style="color:#000000;">git clone https</span> <span style="color:#333333;">:</span> <span style="color:#aa5500;">//gitcode.net/mirrors/yanyiwu/cppjieba.git </span> 
  </div> 
  <div> <span style="color:#000000;">如何使用:注意细节,我们需要自己执行: </span> <span style="color:#000000;">cd cppjieba</span> <span style="color:#333333;">; </span> <span style="color:#000000;">cp </span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">rf deps</span> <span style="color:#981a1a;">/</span> <span style="color:#000000;">limonp include</span> <span style="color:#981a1a;">/</span> <span style="color:#000000;">cppjieba</span> <span style="color:#981a1a;">/</span> <span style="color:#333333;">, </span> <span style="color:#000000;">不然会编 译报错 </span> 
  </div> 
  <p> </p> 
  <h1>7.编写搜索引擎模块Searcher</h1> 
  <pre><code class="language-cpp">#pragma once
#include "index.hpp"
#include <algorithm>
#include <jsoncpp/json/json.h>
// struct Com
// {
//     bool operator>(const InvertedElem& e1,const InvertedElem& e2)
//     {
//         return e1.weigth > e2.weigth;
//     }
// }
struct InvertedElemPrint
{
    uint64_t doc_id;
    int weight;
    std::vector<std::string> words;
    InvertedElemPrint() : doc_id(0), weight(0) {}
};
namespace ns_searcher
{
    class Searcher
    {
    private:
        ns_index::Index *index;

    public:
        Searcher() = default;
        ~Searcher() = default;
        void InitSearcher(const std::string &input)
        {
            // 1.获取或者创建index对象
            index = ns_index::Index::GetInstance(); //获得单例
            //std::cout << "获取单例成功" << std::endl;
            LOG(NORMAL, "获取index单例成功...");
            // 2.根据index对象建立索引
            index->BuildIndex(input);
           // std::cout << "建立正排和倒排索引成功...." << std::endl;
            LOG(NORMAL, "建立正排和倒排索引成功...");
        }

        std::string GetDesc(const std::string &html_src, const std::string &word)
        {
            const int prev_step = 50;
            const int next_step = 100;
            //找到首次出现的位置
            // std::size_t pos = html_src.find(word);  //错误原文档没有忽略大小写
            auto it = std::search(html_src.begin(), html_src.end(), word.begin(), word.end(),
                                  [](int a, int b)
                                  { return std::tolower(a) == std::tolower(b); });
            int pos = std::distance(html_src.begin(), it);
            if (pos == std::string::npos)
            {
                return "None1"; //不存在这种情况
            }
            // 2获取start end
            int start = 0;
            int end = html_src.size() - 1;

            if (pos > start + prev_step)
                start = pos - prev_step;
            if (pos < end - next_step)
                end = pos + next_step;

            if (start >= end)
                return "None2";
            return html_src.substr(start, end - start) + "...";
        }
        // query:搜索关键字
        // josn_string:返回给用户的搜索结果
        void Search(const std::string &query, std::string *json_string)
        {
            // 1.[分词]:对我们的query进行按照searcher的要求进行分词
            std::vector<std::string> words;
            ns_util::JiebaUtil::CurString(query, &words);
            // 2.[触发]:就是根据分词的各个“词”,进行Index查找
            // ns_index::InvertedList inverted_list_all;
            std::vector<InvertedElemPrint> inverted_list_all;

            std::unordered_map<uint64_t, InvertedElemPrint> tokens_map;
            for (auto &e : words)
            {
                boost::to_lower(e);
                ns_index::InvertedList *inverted_list = index->GetInvertedList(e);
                if (inverted_list == nullptr)
                    continue;
                //不完美的地方,可能有重复的文档
                //  inverted_list_all.insert(inverted_list_all.end(),inverted_list->begin(),inverted_list->end());
                for (const auto &elem : *inverted_list)
                {
                    auto &item = tokens_map[elem.doc_id]; //[]:如果存在直接获取,如果不存在新建
                    // item一定是doc_id相同的print节点
                    item.doc_id = elem.doc_id;
                    item.weight += elem.weigth;
                    item.words.push_back(elem.word);
                }
                for (const auto &elem : *inverted_list)
                {
                    auto &item = tokens_map[elem.doc_id]; //[]:如果存在直接获取,如果不存在新建
                    // item一定是doc_id相同的print节点
                    item.doc_id = elem.doc_id;
                    item.weight += elem.weigth;
                    item.words.push_back(elem.word);
                }
                for (const auto &item : tokens_map)
                {
                    inverted_list_all.push_back(std::move(item.second));
                }
            }
            // 3.[合并排序]:汇总查找结果,按照相关性(weight)降序排序
            //  std::sort(inve rted_list_all.begin(), inverted_list_all.end(),\
            //               []( const ns_index::InvertedElem e1,  const ns_index::InvertedElem e2){
            //                return e1.weigth > e2.weigth;
            //                });
            //  std::sort(inverted_list_all.begin(),inverted_list_all.end(),Com());

            std::sort(inverted_list_all.begin(), inverted_list_all.end(),
                      [](const InvertedElemPrint &e1, const InvertedElemPrint &e2)
                      {
                          return e1.weight > e2.weight;
                      });
            // 4.[构建]:根据查找出来的结果,构建jsonc串 -----jsoncpp
            Json::Value root;
            for (auto &item : inverted_list_all)
            {
                ns_index::DocInfo *doc = index->GetForWardIndex(item.doc_id);
                if (doc == nullptr)
                    continue;

                Json::Value elem;
                elem["title"] = doc->title;
                elem["desc"] = GetDesc(doc->content, item.words[0]); // content是文档的去标签的结果,但是不是我们想要的,我们要的是一部分 TODO
                elem["url"] = doc->url;
                // for deubg, for delete
                elem["id"] = (int)item.doc_id;
                elem["weight"] = item.weight; // int->string

                root.append(elem);
            }

            Json::StyledWriter writer;
            *json_string = writer.write(root);
        }
    };
}</code></pre> 
  <p><a href="http://img.e-com-net.com/image/info8/56b798e628b648c78909d50bed07d9fd.jpg" target="_blank"><img alt="Boost搜索引擎_第6张图片" height="255" src="http://img.e-com-net.com/image/info8/56b798e628b648c78909d50bed07d9fd.jpg" width="650" style="border:1px solid black;"></a> </p> 
  <p><span style="color:#333333;">搜索:雷军小米</span><span style="color:#333333;"> -> </span><span style="color:#333333;">雷军、小米</span><span style="color:#333333;">-></span><span style="color:#333333;">查倒排</span><span style="color:#333333;">-></span><span style="color:#333333;">两个倒排拉链(文档</span><span style="color:#333333;">1</span><span style="color:#333333;">,文档</span><span style="color:#333333;">2</span><span style="color:#333333;">,文档</span><span style="color:#333333;">1</span><span style="color:#333333;">、文档</span><span style="color:#333333;">2</span><span style="color:#333333;">)</span> </p> 
  <p><span style="color:#333333;"><strong>安装 </strong></span><span style="color:#333333;">jsoncpp </span> </p> 
  <div> <span style="color:#000000;">sudo yum install </span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">y jsoncpp</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">devel</span> 
  </div> 
  <div>
    获取摘要 
  </div> 
  <div> <a href="http://img.e-com-net.com/image/info8/ab7808a5e52442d09cecb5d8147b5d52.jpg" target="_blank"><img alt="Boost搜索引擎_第7张图片" height="263" src="http://img.e-com-net.com/image/info8/ab7808a5e52442d09cecb5d8147b5d52.jpg" width="650" style="border:1px solid black;"></a> 
  </div> 
  <p><span style="color:#333333;"><strong>关于调试 </strong></span> </p> 
  <div> <span style="color:#333333;">把整个文件读到内存 </span> 
  </div> 
  <div> <span style="color:#333333;">先拿到标题,取到了标题。 </span> 
  </div> 
  <div> <span style="color:#333333;">对整个文件进行去标签,其中是包括标签的!!!! </span> 
  </div> 
  <div> <span style="color:#333333;">实际如果一个词在</span> <span style="color:#333333;">title</span> <span style="color:#333333;">中出现,一定会被当标题 和 当内容分别被统计一次!!!</span> 
  </div> 
  <h1>8.编写http server模块</h1> 
  <div> <span style="color:#000000;">cpp</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">httplib</span> <span style="color:#000000;">库:</span> <span style="color:#000000;">https</span> <span style="color:#333333;">:</span> <span style="color:#aa5500;">//gitee.com/zhangkt1995/cpp-httplib?_from=gitee_search </span> 
  </div> 
  <div> <span style="color:#000000;">注意:</span> <span style="color:#000000;">cpp</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">httplib</span> <span style="color:#000000;">在使用的时候需要使用较新版本的</span> <span style="color:#000000;">gcc</span> <span style="color:#000000;">,</span> <span style="color:#000000;">centos </span> <span style="color:#116644;">7</span> <span style="color:#000000;">下默认</span> <span style="color:#000000;">gcc </span> <span style="color:#116644;">4.8.5 </span> 
  </div> 
  <div></div> 
  <div> 
   <div> <span style="color:#000000;">sudo yum install centos</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">release</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">scl scl</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">utils</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">build</span> 
   </div> 
   <div>
     yum -y install devtoolset-9-gcc devtoolset-9-gcc-c++ devtoolset-9-binutils # 安装gcc和g++ 
   </div> 
   <div> 
    <div> <span style="color:#000000;">scl enable devtoolset</span> <span style="color:#981a1a;">-</span> <span style="color:#116644;">7 </span> <span style="color:#000000;">bash</span> 
    </div> 
   </div> 
   <div> 
    <div> <span style="color:#000000;">ls </span> <span style="color:#981a1a;">/</span> <span style="color:#000000;">opt</span> <span style="color:#981a1a;">/</span> <span style="color:#000000;">rh</span> <span style="color:#981a1a;">/  </span> <span style="color:#aa5500;">//</span> <span style="color:#aa5500;">启动: 细节,命令行启动只能在本会话有效</span> 
    </div> 
    <div> <span style="color:#aa5500;">//</span> <span style="color:#aa5500;">可选:如果想每次登陆的时候,都是较新的</span> <span style="color:#aa5500;">gcc </span> 
    </div> 
    <div> 
     <div></div> 
     <div> <span style="color:#000000;">永久更新 vim ~</span> <span style="color:#981a1a;">/</span> <span style="color:#333333;">.</span> <span style="color:#000000;">bash_profile 在文本末尾添加 scl enable devtoolset</span> <span style="color:#981a1a;">-</span> <span style="color:#116644;">7 </span> <span style="color:#000000;">bash</span> 
     </div> 
     <div> <span style="color:#333333;"><strong>安装 </strong></span> <span style="color:#333333;">cpp</span> <span style="color:#333333;"><strong>-</strong></span> <span style="color:#333333;">httplib </span> 
     </div> 
     <div> 
      <div> <span style="color:#000000;">最新的</span> <span style="color:#000000;">cpp</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">httplib</span> <span style="color:#000000;">在使用的时候,如果</span> <span style="color:#000000;">gcc</span> <span style="color:#000000;">不是特别新的话有可能会有运行时错误的问题 </span> 
      </div> 
      <div> <span style="color:#000000;">建议:</span> <span style="color:#000000;">cpp</span> <span style="color:#981a1a;">-</span> <span style="color:#000000;">httplib </span> <span style="color:#116644;">0.7.15 </span> 
      </div> 
      <div> <span style="color:#000000;">下载</span> <span style="color:#000000;">zip</span> <span style="color:#000000;">安装包,上传到服务器即可 或者直接get clone也行,在gitee上有项目,直接搜索cpp-hpplib</span> 
      </div> 
      <div> 
       <pre><code class="language-cpp">#include "cpp-httplib/httplib.h"
#include "searcher.hpp"
const std::string root_path = "./wwwroot";
const std::string input ="data/raw_html/raw.txt";
int main()
{ 
    ns_searcher::Searcher searcher;
    searcher.InitSearcher(input);
    httplib::Server svr; 
    svr.set_base_dir(root_path.c_str()); 
    svr.Get("/s", [&searcher](const httplib::Request &req, httplib::Response &rsp){
        if(!req.has_param("word"))
        {
            rsp.set_content("必须要有搜索关键字!","text/plain: chatset=utf-8");
            return;
        }
        std::string word = req.get_param_value("word");
       // std::cout<<"用户正在搜索:"<<word<<std::endl;
        LOG(NORMAL, "用户搜索的: " + word);
        std::string json_string;
        searcher.Search(word,&json_string);
        rsp.set_content(json_string,"application/json");
        });
        //rsp.set_content("你好,世界!", "text/plain; charset=utf-8"); 
        LOG(NORMAL, "服务器启动成功...");
        svr.listen("0.0.0.0", 8081); return 0;
}
</code></pre> 
       <p></p> 
      </div> 
     </div> 
    </div> 
   </div> 
  </div> 
  <h1>9.编写前段模块</h1> 
  <p></p> 
  <pre><code class="language-html"><!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 搜索引擎
    



    

makefile

Parser=parser
DUG=debug
HTTP_SEARCHER=http_searcher
cc=g++

.PHONY:all
all:$(Parser) $(DUG) $(HTTP_SEARCHER)
$(Parser):parser.cc
	$(cc) -o $@ $^ -lboost_system -lboost_filesystem -std=c++11
$(DUG):debug.cc
	$(cc) -o $@ $^  -ljsoncpp -std=c++11
$(HTTP_SEARCHER):http_searcher.cc
	$(cc) -o $@ $^  -ljsoncpp -lpthread -std=c++11

	
.PHONY:clean
clean:
	rm -rf $(Parser) $(DUG) $(HTTP_SEARCHER)

 

10.项目效果

Boost搜索引擎_第8张图片

 Boost搜索引擎_第9张图片

 11.添加日志

#pragma once

#include 
#include 
#include 

#define NORMAL  1
#define WARNING 2
#define DEBUG   3
#define FATAL   4

#define LOG(LEVEL, MESSAGE) log(#LEVEL, MESSAGE, __FILE__, __LINE__)

void log(std::string level, std::string message, std::string file, int line)
{
    std::cout << "[" << level << "]" << "[" << time(nullptr) << "]" << "[" << message << "]" << "[" << file << " : " << line << "]" << std::endl;
}
结项总结
项目扩展方向
1. 建立整站搜索
2. 设计一个在线更新的方案,信号,爬虫,完成整个服务器的设计
3. 不使用组件,而是自己设计一下对应的各种方案(有时间,有精力)
4. 在我们的搜索引擎中,添加竞价排名 ( 强烈推荐 )
5. 热次统计,智能显示搜索关键词(字典树,优先级队列) ( 比较推荐 )
6. 设置登陆注册,引入对 mysql 的使用 ( 比较推荐的 )
项目源码: liutao932/boost (github.com)icon-default.png?t=M666https://github.com/liutao932/boost

你可能感兴趣的:(网络,数据结构,c++进阶,搜索引擎,百度)