国产亚洲精品福利在线无卡一,国产精久久一区二区三区,亚洲精品无码国模,精品久久久久久无码专区不卡

當(dāng)前位置: 首頁 > news >正文

什么網(wǎng)站做微信公眾賬號seo專員工作容易學(xué)嗎

什么網(wǎng)站做微信公眾賬號,seo專員工作容易學(xué)嗎,西網(wǎng)站建設(shè)公司,wordpress固定網(wǎng)址打不開BOOST Boost是一個由C社區(qū)開發(fā)的開源庫,為C語言標準庫提供擴展。這個庫由C標準委員會庫工作組成員發(fā)起,旨在提供大量功能和工具,幫助C開發(fā)者更高效地編寫代碼。Boost庫強調(diào)跨平臺性和對標準C的遵循,因此與編寫平臺無關(guān)&#xff0…

BOOST

Boost是一個由C++社區(qū)開發(fā)的開源庫,為C++語言標準庫提供擴展。這個庫由C++標準委員會庫工作組成員發(fā)起,旨在提供大量功能和工具,幫助C++開發(fā)者更高效地編寫代碼。Boost庫強調(diào)跨平臺性和對標準C++的遵循,因此與編寫平臺無關(guān),是C++標準化進程的重要開發(fā)引擎之一。

但是BOOST沒有站內(nèi)的搜索引擎,我們在使用想快速查找信息的時候十分不方便,所以我們自己動手實現(xiàn)一個。

技術(shù)棧與項目環(huán)境

技術(shù)棧:

  • 用C/C++作為主要編程語言,并利用STL中的容器等功能
  • cpp-httplib:輕量級HTTP庫,用于構(gòu)建HTTP服務(wù)器和處理HTTP請求
  • cppjieba:中文分詞工具,用于對查詢詞和文檔進行分詞處理。
  • HTML/CSS:用于前端開發(fā),構(gòu)建用戶搜索界面和展示搜索結(jié)果。

項目環(huán)境:

  • CentOS7云服務(wù)器,作為項目的運行環(huán)境
  • vim/gcc/g++/Makefile:代碼編輯、構(gòu)建

搜索引擎的原理

在這里插入圖片描述
在這里插入圖片描述

正排索引(Forward Index)

正排索引是以文檔的ID為關(guān)鍵字,表中記錄文檔中每個詞的位置信息。

文檔ID文檔內(nèi)容
1張三在吃飯
2張三在買東西

索引的ID和文檔的內(nèi)容是一一對應(yīng)的,記錄了文檔中出現(xiàn)的關(guān)鍵詞及其出現(xiàn)次數(shù)和位置信息。正排索引的優(yōu)勢在于可以快速地查找某個文檔里包含哪些詞項,但不適用于查找包含某個詞項的文檔有哪些。

倒排索引(Inverted Index)

倒排索引是以詞為關(guān)鍵字的索引結(jié)構(gòu),表中記錄了出現(xiàn)這個詞的所有文檔的ID和位置信息,或者記錄了這個詞在哪些文檔的哪些位置出現(xiàn)過,以及出現(xiàn)多少次。

關(guān)鍵字(具有唯一性)文檔ID,weight(權(quán)重)
張三文檔1,文檔2
吃飯文檔1
買東西文檔2

查找過程: 用戶輸入張三-> 倒排索引->提取文檔ID(1,2)->根據(jù)正排索引->找到文檔的內(nèi)容 ->title +conent(desc)+url 文檔結(jié)果進行摘要 ->構(gòu)建響應(yīng)結(jié)果

項目實現(xiàn)

image-20240601164824326

數(shù)據(jù)部分

在boost官網(wǎng)把boost的內(nèi)容下載下來,并在CentOS7下解壓。

image-20240531150509659

創(chuàng)建一個data的目錄,把boost_1_83_0/doc/html/data拷貝到data目錄下的input中來,此時data/input就是我們的數(shù)據(jù)源。

image-20240601092253900

去標簽與數(shù)據(jù)清洗Parser

上面說到的data/input數(shù)據(jù)源中我們隨便打開一個html文件

image-20240531152305259

可以看到我們需要的是文檔中的內(nèi)容,所以需要把標簽去掉,寫入到raw_html目錄中。

typedef struct DocInfo
{std::string title;   // 文檔的標題std::string content; // 文檔的內(nèi)容 --body里面有內(nèi)容信息std::string url;     // 該文檔在官網(wǎng)中的url
} DocInfo_t;int main()
{std::vector<std::string> files_list;// 1.遞歸式的把每個html文件命帶路徑,保存到files_list中// 方便后期進行一個一個文件的讀取if (!EnumFile(src_path, &files_list)){std::cerr << "euum file name error!" << std::endl;return 1;}// 2.按照files_list 讀取每個文件的內(nèi)容,并進行解析std::vector<DocInfo_t> results; // 解析后的結(jié)果存放在results中if (!ParseHtml(files_list, &results)){std::cerr << "parse html error" << std::endl;return 2;}// 3.把解析完畢的各個文件內(nèi)容,寫入到output中,按照\3作為分隔符if (!SaveHtml(results, output)){std::cerr << "sava html error" << std::endl;return 3;}return 0;
}

遍歷數(shù)據(jù)源下所有以 .html 擴展名的文件路徑,然后將這些路徑存儲在一個files_list中。


bool EnumFile(const std::string &src_path, std::vector<std::string> *files_list)
{namespace fs = boost::filesystem; // 給boost命名空間起別名fs::path root_path(src_path);if (!fs::exists(root_path)) // 路徑不存在直接退出{std::cerr << src_path << "not exists" << std::endl;return false;}// 定義一個迭代器來判斷遞歸的結(jié)束fs::recursive_directory_iterator end;// 遍歷文件路徑for (fs::recursive_directory_iterator iter(root_path); iter != end; iter++){// 判斷是不是普通文件if (!fs::is_regular_file(*iter)){continue;}// 判斷文件名的后綴是否符合要求if (iter->path().extension() != ".html"){continue;}files_list->push_back(iter->path().string()); // 把帶路徑的html保存在files_list中}return true;
}

從files_list的HTML文件列表中解析信息,提取titile、continue并構(gòu)建URL到一個個DocInfo_t中。

bool ParseHtml(const std::vector<std::string> &files_list, std::vector<DocInfo_t> *results)
{for (const std::string &file : files_list){std::string result;// 讀文件if (!ns_util::FileUtil::ReadFile(file, &result)){continue;}DocInfo_t doc;// 解析文件,提取titleif (!ParseTitle(result, &doc.title)){continue;}// 解析文件,提取continue--去標簽if (!ParseContent(result, &doc.content)){continue;}// 解析文件路徑,構(gòu)建urlif (!ParseUrl(file, &doc.url)){continue;}// 完成解析任務(wù),解析結(jié)果保存在doc中results->push_back(std::move(doc)); // 減少拷貝}return true;
}//<title> 我們要的內(nèi)容 <title>
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;
}/*<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>*/
//上面的標簽都清洗掉
/*<div class="titlepage"><div><div><h2 class="title" style="clear: both">
<a name="array.ack"></a>Acknowledgements</h2></div></div></div>
<p>Doug Gregor </p>*/
//標簽中的Acknowledgements 、Doug Gregor保留下來
static bool ParseContent(const std::string &file, std::string *content)
{//狀態(tài)機enum status{LABLE,CONTENT};enum status s = LABLE; // 默認為LABLE狀態(tài)for (char c : file) //以字符方式遍歷file{switch (s){case LABLE:if (c == '>') // 碰到>就意味著標簽處理完畢s = CONTENT;break;case CONTENT:if (c == '<')  //碰到<就意味著內(nèi)容處理完畢s = LABLE;else{// 不保留原始文件的\n, \n用來做html解析之后的文本分割符if (c == '\n')c = ' ';content->push_back(c);}break;default:break;}}return true;
}/* 
boost庫的官方文檔和下載下來的文檔是有路徑對應(yīng)關(guān)系的
//官網(wǎng)URL
https://www.boost.org/doc/libs/1_83_0/doc/html/accumulators.html
//linux中URL
data/input/accumulators.html//下載下來的boost庫url_head ="https://boost.org/doc/libs/1_83_0/doc/html/"
url_tail= data/input/accumulators.html data/input(刪除)--> /accumulators.html
url = url_head + url_tail  //相當(dāng)于一個官網(wǎng)連接 */static bool ParseUrl(const std::string &file_path, std::string *url)
{std::string url_head = "https://www.boost.org/doc/libs/1_83_0/doc/html";std::string url_tail = file_path.substr(src_path.size()); //subsrt去掉data/input*url = url_head + url_tail;return true;
}

將一組DocInfo_t類型的數(shù)據(jù)也就是上面解析出來的內(nèi)容保存到output中。

#define SEP '\3' //分割符號
bool SaveHtml(const std::vector<DocInfo_t> &results, const std::string &output)
{// 二進制寫入--寫入什么文檔保存就是什么std::ofstream out(output, std::ios::out | std::ios::binary); if (!out.is_open()){std::cerr << "open " << output << "failed" << std::endl;return false;}//title\3content\3url \n  title\3content\3url \n ....//方便getline(ifsream,line)直接獲取文檔全部內(nèi)容 title\3content\3url(getline以\n結(jié)束) for (auto &item : results){std::string out_string;out_string = item.title;out_string += SEP;out_string += item.content;out_string += SEP;out_string += item.url;out_string += '\n'; // 文檔和文檔之間的分隔out.write(out_string.c_str(), out_string.size());}out.close();return true;
}

索引Index

對清洗過的內(nèi)容構(gòu)建正排、倒排索引

struct DocInfo
{ std::string title;   //文檔的標題std::string content; //文檔對應(yīng)的去標簽之后的內(nèi)容std::string url;     //官網(wǎng)文檔urluint64_t doc_id;     //文檔的ID,用uint64_t:為了防止索引越界
};//倒排結(jié)構(gòu)
struct InvertedElem
{    uint64_t doc_id;//對應(yīng)的文檔idstd::string word;//關(guān)鍵字int weight; //權(quán)重  可以根據(jù)權(quán)重決定文檔顯示的先后順序InvertedElem():weight(0){}
};typedef std::vector<InvertedElem> InvertedList;// 倒排拉鏈
//單例模式
class Index 
{
private:std::vector<DocInfo> forward_index;// 正排拉鏈//存放關(guān)鍵字和倒排拉鏈的映射關(guān)系std::unordered_map<std::string, InvertedList> inverted_index; 
public:Index(){} //但是一定要有函數(shù)體,不能delete~Index(){}Index(const Index&) = delete;Index& operator=(const Index&) = delete;static Index* instance;//指向全局唯一的單例對象static std::mutex mtx;
public://獲取全局唯一的單例對象static Index* GetInstance(){//第一次需要加鎖,后面都不需要加鎖的場景,可以使用雙檢查加鎖//特點:第一次加鎖,后面不加鎖,保護線程安全,同時提高效率if(nullptr == instance){//加鎖只有第一次有意義,后面再有線程來沒必要加鎖,加鎖會引發(fā)效率低下mtx.lock();if(nullptr == instance){instance = new Index();}mtx.unlock();}return instance;//返回這個全局的單例對象}//根據(jù)文檔id找到找到文檔內(nèi)容   DocInfo* GetForwardIndex(uint64_t doc_id) {    if(doc_id >= forward_index.size()) //沒有該文檔id{std::cerr << "doc_id out range, error!" << std::endl;return nullptr;}return &forward_index[doc_id]; //數(shù)組的下標天然就是文檔id,所以直接返回數(shù)組對應(yīng)的內(nèi)容的地址}//根據(jù)關(guān)鍵字word,獲得倒排拉鏈 InvertedList *GetInvertedList(const std::string &word){//在哈希表當(dāng)中查找是否存在這個關(guān)鍵字對應(yīng)的倒排拉鏈auto iter = inverted_index.find(word);if(iter == inverted_index.end()){std::cerr << word << " have no InvertedList" << std::endl;return nullptr;}return &(iter->second);}//根據(jù)文檔內(nèi)容構(gòu)造索引,參數(shù):經(jīng)過數(shù)據(jù)清洗之后的文檔bool BuildIndex(const std::string &input) {std::ifstream in(input, std::ios::in | std::ios::binary);if(!in.is_open()){ std::cerr << "build index error, open " << input << " failed" << std::endl;return false;}int count = 0;//方便觀察當(dāng)前建立的索引個數(shù)std::string line; //讀取一行數(shù)據(jù) //對每一個html文件格式化之后的內(nèi)容進行正排和倒排索引while(std::getline(in, line)) {//建立正排索引,返回描述這個文檔內(nèi)容的節(jié)點DocInfo * doc = BuildForwardIndex(line); if(nullptr == doc){ std::cerr << "build " << line << " error" << std::endl; //for deubgcontinue;}BuildInvertedIndex(*doc);//根據(jù)上面返回的正排索引節(jié)點,建立倒排索引count ++;if(count % 150 == 0){LOG(NORMAL,"當(dāng)前的已經(jīng)建立的索引文檔:"+std::to_string(count));}}return true;}
};

建立正排索引

    //line:就是一個html文件里面去標簽,格式化之后的文檔內(nèi)容DocInfo *BuildForwardIndex(const std::string &line) {//1. 解析line->本質(zhì)是進行字符串切分,解析成:title, content, url  std::vector<std::string> results;//保存切分好的內(nèi)容const std::string sep = "\3";   //分隔符//切分字符串ns_util::StringUtil::Split(line, &results, sep);if(results.size() != 3)		//判斷切分結(jié)果是否正確,要切分為3部分{ return nullptr;}//2. 切分好的字符串進行填充到DocIinfoDocInfo doc;doc.title = results[0]; //titledoc.content = results[1]; //contentdoc.url = results[2];   ///urldoc.doc_id = forward_index.size(); //3. 插入到正排索引數(shù)組當(dāng)中forward_index.push_back(std::move(doc)); return &forward_index.back(); }

建立倒排索引

  bool BuildInvertedIndex(const DocInfo &doc)//建立倒排索引,參數(shù)是正排索引節(jié)點{//DocInfo里面包含一個html文件的:{title, content, url, doc_id}struct word_cnt //針對一個詞的數(shù)據(jù)統(tǒng)計{   int title_cnt;//在標題出現(xiàn)次數(shù)int content_cnt;//在內(nèi)容中出現(xiàn)次數(shù)word_cnt():title_cnt(0), content_cnt(0){}               };std::unordered_map<std::string, word_cnt> word_map; //暫存詞頻的映射表/* 根據(jù)文檔標題和內(nèi)容,分詞并進行詞頻統(tǒng)計 *///對標題進行分詞std::vector<std::string> title_words;ns_util::JiebaUtil::CutString(doc.title, &title_words);//對標題分詞之后的結(jié)果進行詞頻統(tǒng)計for(std::string s : title_words){  boost::to_lower(s); //忽略大小寫//查找對應(yīng)關(guān)鍵詞,如果存在就++,不存在就新建  word_map[s].title_cnt++; }//對內(nèi)容進行分詞std::vector<std::string> content_words;ns_util::JiebaUtil::CutString(doc.content, &content_words);//對內(nèi)容進行詞頻統(tǒng)計for(std::string s : content_words) {boost::to_lower(s);//忽略大小寫word_map[s].content_cnt++;}// 自定義相關(guān)性#define X 15  //標題當(dāng)中出現(xiàn)的詞,權(quán)重更高#define Y 1//建立倒排拉鏈for(auto &word_pair : word_map){InvertedElem item;item.doc_id = doc.doc_id;item.word = word_pair.first;//設(shè)置權(quán)重item.weight = 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;}

搜索服務(wù)Searcher

前面的部分都是前期的準備工作,Searcher提供搜索服務(wù),對用戶輸入的字符串進行分詞,使用倒排索引查找與查詢詞相關(guān)的內(nèi)容,并進行排序。

namespace ns_searcher
{struct InvertedElemPrint{uint64_t doc_id;                // 文檔idint weight;                     // 累加權(quán)重std::vector<std::string> words; // 一個doc_id對應(yīng)多個關(guān)鍵字InvertedElemPrint() : doc_id(0), weight(0){}};class Searcher{private:ns_index::Index *index; // 供系統(tǒng)進行查找的索引public:Searcher() {}~Searcher() {}void InitSearcher(const std::string &input){// 1. 獲取或者創(chuàng)建index對象index = ns_index::Index::GetInstance();LOG(NORMAL, "獲取index單例成功");// 2. 根據(jù)index對象建立索引index->BuildIndex(input);LOG(NORMAL, "建立正排和倒排索引成功...");}// 獲取一部分內(nèi)容std::string GetDesc(const std::string &html_content, const std::string &word){// 1.在html_content范圍內(nèi),找word首次出現(xiàn)的位置auto cmp = [](char x, char y)  { return (std::tolower(static_cast<unsigned char>(x)) == std::tolower(static_cast<unsigned char>(y))); };  auto iter = std::search(html_content.begin(), html_content.end(),   word.begin(), word.end(), cmp);  if (iter == html_content.end()){return "None1";}int pos = iter - html_content.begin();// 2. 獲取start,end的位置int start = 0;                     // 默認就是在文本的起始位置int end = html_content.size() - 1; // 默認是文本的結(jié)尾// 找到word在html_content中的首次出現(xiàn)的位置,然后往前找30字節(jié),如果沒有,就從	start開始// 往后找80字節(jié)如果沒有,到end就可以的 ,然后截取出這部分內(nèi)容const int prev_step = 30;const int next_step = 80;if (pos - prev_step > 0)start = pos - prev_step;if (pos + next_step < end)end = pos + next_step;// 3. 截取子串,然后returnif (start >= end)return "None2";// 從start開始,截取end - start個字節(jié)的內(nèi)容std::string desc = html_content.substr(start, end - start);desc += "...";return desc;}// query:用戶搜索關(guān)鍵字  json_string: 返回給用戶瀏覽器的搜索結(jié)果void Search(const std::string &query, std::string *json_string){// 1.對query進行按照searcher的要求進行分詞std::vector<std::string> words;ns_util::JiebaUtil::CutString(query, &words);// 2.就是根據(jù)分詞的各個"詞",進行index索引查找std::vector<InvertedElemPrint> inverted_list_all; // 存放所有經(jīng)過去重之后的倒排拉鏈// 根據(jù)doc_id進行去重,凡是id相同的倒排索引節(jié)點,其關(guān)鍵字都放在InvertedElemPrint的vector里面std::unordered_map<uint64_t, InvertedElemPrint> tokens_map;// 因為我們建立索引的時候,建立index是忽略大小寫,所以搜索的時候關(guān)鍵字也需要忽略大小寫for (std::string word : words){boost::to_lower(word); // 將切分之后的查找關(guān)鍵字轉(zhuǎn)為小寫// 先查倒排ns_index::InvertedList *inverted_list = index->GetInvertedList(word); // 通過關(guān)鍵字獲得倒排拉鏈if (nullptr == inverted_list)                                         {continue; // 檢測下一個關(guān)鍵詞}for (const auto &elem : *inverted_list) // 遍歷倒排拉鏈,合并索引節(jié)點{//[]:如果存在直接獲取,如果不存在新建auto &item = tokens_map[elem.doc_id]; // 根據(jù)文檔id獲得其對應(yīng)的關(guān)鍵字集合// 此時item一定是doc_id相同的倒排拉鏈打印節(jié)點item.doc_id = elem.doc_id;item.weight += elem.weight;      // 權(quán)值累加item.words.push_back(elem.word); // 把當(dāng)前的關(guān)鍵字放到去重的倒排拉鏈打印節(jié)點當(dāng)中的vector當(dāng)中保存}}for (const auto &item : tokens_map) // 遍歷去重之后的map{inverted_list_all.push_back(std::move(item.second)); // 插入倒排拉鏈打印節(jié)點到inverted_list_all}// 3.匯總查找結(jié)果,按照相關(guān)性(weight)進行降序排序auto cmp = [](const InvertedElemPrint &e1, const InvertedElemPrint &e2){return e1.weight > e2.weight;};std::sort(inverted_list_all.begin(), inverted_list_all.end(), cmp);// 4.根據(jù)查找出來的結(jié)果,構(gòu)建json串 -- jsoncpp --通過jsoncpp完成序列化&&反序列化Json::Value root;for (auto &item : inverted_list_all){// item就是倒排索引打印節(jié)點ns_index::DocInfo *doc = index->GetForwardIndex(item.doc_id); // 根據(jù)文檔id->查詢正排,返回正排索引節(jié)點if (nullptr == doc){continue;}// doc里面就有title,url,content,文檔id// 我們想給瀏覽器返回的是網(wǎng)頁的title,內(nèi)容摘要,鏈接Json::Value elem;elem["title"] = doc->title;//只需要一部分文檔內(nèi)容elem["desc"] = GetDesc(doc->content, item.words[0]);elem["url"] = doc->url;// for deubg, for deleteelem["id"] = (int)item.doc_id; // doc_id是uint64 ,json可能報錯,所以轉(zhuǎn)為intelem["weight"] = item.weight;  // doc_id,weight雖然是int,但是json會幫我們自動轉(zhuǎn)為stringroot.append(elem);}// Json::StyledWriter writer; //為了方便調(diào)試觀看Json::FastWriter writer;*json_string = writer.write(root);}};
}

http_server

監(jiān)聽HTTP請求,解析用戶輸入的參數(shù),調(diào)用Searcher進行搜索,把給結(jié)果響應(yīng)回給客戶。

#include "cpp-httplib/httplib.h"
#include "searcher.hpp"//引入搜索引擎
const std::string input = "data/raw_html/raw.txt";//html文件經(jīng)過parser之后存放的結(jié)果的路徑 
const std::string root_path = "./wwwroot"; //wwroot作為服務(wù)器的主頁int main()
{ns_searcher::Searcher search;search.InitSearcher(input);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("必須要有搜索關(guān)鍵字!", "text/plain; charset=utf-8");return;}std::string word = req.get_param_value("word");LOG(NORMAL,"用戶在搜索:"+word);std::string json_string;search.Search(word, &json_string);//返回給客戶端rsp.set_content(json_string, "application/json"); });LOG(NORMAL,"服務(wù)器啟動成功...");svr.listen("0.0.0.0", 8081);return 0;
}

工具util

//文件讀取
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()){std::cerr << "open file" << file_path << "error" << std::endl;return false;}std::string line;// 為什么getline的返回值是流的引用&,while是bool,能進行判斷呢?// 重載了強制類型轉(zhuǎn)換while (std::getline(in, line)){*out += line;}in.close();return true;}};// 字符串切割class StringUtil{public:static void Split(const std::string &target, std::vector<std::string> *out, std::string sep){//  token_compress_on on:壓縮打開 --將所有相連的分隔符壓縮成一個         				aa\3\3\3\3\3bbb-->aa   bbb// off:壓縮關(guān)閉boost::split(*out, target, boost::is_any_of(sep), boost::token_compress_on);}};//Jieba分詞
// dict路徑const char *const DICT_PATH = "./dict/jieba.dict.utf8";const char *const HMM_PATH = "./dict/hmm_model.utf8";const char *const USER_DICT_PATH = "./dict/user.dict.utf8";const char *const IDF_PATH = "./dict/idf.utf8";const char *const STOP_WORD_PATH = "./dict/stop_words.utf8";class JiebaUtil{private:// static cppjieba::Jieba jieba;cppjieba::Jieba jieba;std::unordered_map<std::string, bool> stop_words;private:JiebaUtil() : jieba(DICT_PATH, HMM_PATH, USER_DICT_PATH, IDF_PATH, STOP_WORD_PATH){}JiebaUtil(const JiebaUtil &) = delete;static JiebaUtil *instance;public:static JiebaUtil *get_instance(){static std::mutex mtx;if (nullptr == instance){mtx.lock();if (nullptr == instance){instance = new JiebaUtil();instance->InitJiebaUtil();}mtx.unlock();}return instance;}// 把暫停詞加載進來void InitJiebaUtil(){std::ifstream in(STOP_WORD_PATH);if (!in.is_open()){LOG(FATAL, "load stop words file error");return;}std::string line;while (std::getline(in, line)){stop_words.insert({line, true});}in.close();}
/*去掉暫停詞暫停詞是對我們搜索沒意義的詞語,如:“的”、“地”、“吧”等*/void CutStringHelper(const std::string &src, std::vector<std::string> *out){jieba.CutForSearch(src, *out);for (auto iter = out->begin(); iter != out->end();){auto it = stop_words.find(*iter);if (it != stop_words.end()){ // 說明當(dāng)前的string 是暫停詞,需要去掉iter = out->erase(iter);}else{iter++;}}}public:static void CutString(const std::string &src, std::vector<std::string> *out){ns_util::JiebaUtil::get_instance()->CutStringHelper(src, out);// jieba.CutForSearch(src,*out);}};

log

#pragma once
#include<iostream>
#include<string>
#include<ctime>
#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;
}

編寫js

用原生js成本高,jQuery好
<script>function Search(){// 是瀏覽器的一個彈出框//alert("hello js!");// 1. 提取數(shù)據(jù), $可以理解成就是JQuery的別稱let query = $(".container .search input").val();console.log("query = " + query); //console是瀏覽器的對話框,可以用來進行查看js數(shù)據(jù)//2. 發(fā)起http請求,ajax: 屬于一個和后端進行數(shù)據(jù)交互的函數(shù),JQuery中的$.ajax({type: "GET",url: "/s?word=" + query,success: function(data){console.log(data);BuildHtml(data);}});}function BuildHtml(data){// if(data==''||data==ull)// {//     document.write("搜索不到");//     return;// }// 獲取html中的result標簽let result_lable = $(".container .result");// 清空歷史搜索結(jié)果result_lable.empty();for( let elem of data){ let a_lable = $("<a>", {text: elem.title,href: elem.url,// 跳轉(zhuǎn)到新的頁面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.appenesult_lable);}}</script>

項目擴展

  1. 建立整個站的搜索,把boost庫的各個版本都進行正排倒排建立索引
  2. 數(shù)據(jù)部分設(shè)計一個在線更新網(wǎng)頁內(nèi)容,利用爬蟲,信號等進行設(shè)計
  3. 添加整站搜索、競價排名、熱詞統(tǒng)計等,進一步豐富項目的功能和用戶體驗。
  4. 設(shè)計登錄注冊功能,引入mysql

遇到問題

1.存在搜索出相同的內(nèi)容的問題

解決:在searcher模塊用unordered_map對建立的倒排拉鏈進行去重。

2.查看權(quán)重值的時候發(fā)現(xiàn)對不上

原因:分詞的時候會出現(xiàn)包含單詞也會統(tǒng)計的情況,比如我搜sprlit,sprlitabc也會被搜到。

3.使用jieba庫的時候出現(xiàn)找不到Log的錯誤

jieba的include下的頭文件有方法,jieba/dict里有分詞的庫(具體怎么分詞),我們采取鏈接的方式,jieba有一個問題就是需要把deps/limonp拷貝到include/cppjieba下,不然會報錯找不到log

http://aloenet.com.cn/news/38875.html

相關(guān)文章:

  • 做像素畫的網(wǎng)站岳陽seo公司
  • 局網(wǎng)站建設(shè)情況匯報官網(wǎng)制作公司
  • windows7怎么做網(wǎng)站服務(wù)器新聞式軟文
  • 中企動力做的網(wǎng)站被百度屏蔽關(guān)鍵詞查詢工具有哪些
  • 銀行網(wǎng)站維護是做哪些seo排名教程
  • 網(wǎng)站如何做長尾詞排名宣傳推廣文案
  • 寧波網(wǎng)站建設(shè)明細報價1小時快速搭建網(wǎng)站
  • 網(wǎng)站圖怎么做才能小而清晰百度灰色關(guān)鍵詞技術(shù)
  • 成都企業(yè)網(wǎng)站維護專業(yè)外貿(mào)網(wǎng)絡(luò)推廣
  • 做網(wǎng)站 一級 二級2023年10月爆發(fā)新冠
  • 產(chǎn)品開發(fā)流程及每個流程內(nèi)容網(wǎng)站優(yōu)化網(wǎng)站優(yōu)化
  • 官方網(wǎng)站建設(shè)條件博客網(wǎng)站注冊
  • 搜索網(wǎng)站怎么做東營優(yōu)化路網(wǎng)
  • 安徽平臺網(wǎng)站建設(shè)找哪家國產(chǎn)最好的a級suv88814
  • 哈爾濱企業(yè)展示型網(wǎng)站建設(shè)搜索引擎優(yōu)化期末考試答案
  • wordpress最簡單的主題濱州seo排名
  • 提高網(wǎng)站流量網(wǎng)絡(luò)推廣網(wǎng)站推廣方法
  • 濰坊網(wǎng)站制作 熊掌號今日熱搜榜排名最新
  • 最好的wordpress主題北京網(wǎng)站優(yōu)化方式
  • 網(wǎng)站用自己的電腦做服務(wù)器北京百度seo排名點擊軟件
  • 網(wǎng)站建設(shè)模板成功案例網(wǎng)絡(luò)營銷推廣技術(shù)
  • 營銷網(wǎng)站制作seo外貿(mào)公司推廣
  • 網(wǎng)站例子友情鏈接作用
  • 外國網(wǎng)站上做雅思考試競價排名深度解析
  • 網(wǎng)站建設(shè)的七個流程步驟2345網(wǎng)址大全
  • 如何建做校園購物網(wǎng)站注冊一個網(wǎng)站
  • 做甜品的網(wǎng)站蘇州優(yōu)化收費
  • 網(wǎng)站備案歸哪里管網(wǎng)頁快速收錄
  • 定西市小企業(yè)網(wǎng)站建設(shè)建設(shè)百度競價怎么做效果好
  • 商城網(wǎng)站制作多少錢58同城如何發(fā)廣告