主页 > 软件开发  > 

9.综合调试|输入不能存在空格|desc存在None|输出权值和ID|函数重名|修改文件名|权值和实际关键词出现

9.综合调试|输入不能存在空格|desc存在None|输出权值和ID|函数重名|修改文件名|权值和实际关键词出现
输入不能存在空格

目前输入的关键词时每隔一空格内容分别进行搜索,大部分时候我们都是将一串包含空格的内容直接进行搜索,需要将代码改进。 将cin换为fgets

#include "searcher.hpp" #include <iostream> #include <cstdio> #include <cstring> #include <string> const std::string input = "data/raw_html/raw.txt"; int main() { //for test ns_searcher::Searcher *search = new ns_searcher::Searcher(); search->InitSearcher(input); std::string query; std::string json_string; char buffer[1024]; while(true){ std::cout << "Please Enter You Search Query# "; fgets(buffer, sizeof(buffer)-1, stdin); buffer[strlen(buffer) - 1] = 0; query = buffer; search->Search(query, &json_string); std::cout << json_string << std::endl; } return 0; } desc存在None

搜索出来的结果,有部分desc的内容时None

std::string GetDesc(const std::string &html_content, const std::string &word) { //找到word在html_content中的首次出现,然后往前找50个字节(如果没有,就从begin开始),往后找100个字节(如果没有,就截取到end) //截取出这部分内容 const std::size_t prev_step = 50; const std::size_t next_step = 100; //1.找到首次出现 std::size_t pos = html_content.find(word); if(pos == std::string::npos){ return "None1"; //不可能发生 } //2.获取start,end std::size_t start = 0; std::size_t end = html_content.size() - 1; //如果之前有50+字符,就更新开始位置 if(pos - prev_step > start) start = pos - prev_step; if(pos + next_step < end) end = pos + next_step; //3.截取子串,return if(start >= end) return "None2"; return html_content.substr(start, end - start); }

给None的两种情况加上脚标

None1和2都有

因为pos是无符号整数,减去step过了0,成为负数,其实是变为一个特别大的值,此时就超过了start,远大于start,条件成立,更新start,start变为一个特别大的值;这时start有可能大于end,于是返回None2

if(pos > start + prev_step) start = pos - prev_step;

将-变为+,转换为两个正数的比较

std::string GetDesc(const std::string &html_content, const std::string &word) { //找到word在html_content中的首次出现,然后往前找50个字节(如果没有,就从begin开始),往后找100个字节(如果没有,就截取到end) //截取出这部分内容 const std::size_t prev_step = 50; const std::size_t next_step = 100; //1.找到首次出现 std::size_t pos = html_content.find(word); if(pos == std::string::npos){ return "None1"; //不可能发生 } //2.获取start,end,std::size_t 无符号整数 std::size_t start = 0; std::size_t end = html_content.size() - 1; //如果之前有50+字符,就更新开始位置 if(pos > start + prev_step) start = pos - prev_step; if((int)pos < (int)(end - next_step)) end = pos + next_step; //3.截取子串,return if(start >= end) return "None2"; return html_content.substr(start, end - start); }

None2修改完成

在word里面保存的对应的搜索关键字,都变为小写。 索引关键字,搜索关键字都是小写 但是在获取摘要的时候,用的是原始的网页内容,提炼摘要的word是已经转为小写的词 实际在获取摘要,find的时候,就匹配不到了,因为fine不是忽略大小写的 而且string在实际搜索的时候,也没有忽略大小写的匹配方式 并且不能直接将原始网页全部变为小写

可以使用c++的search

std::string GetDesc(const std::string &html_content, const std::string &word) { //找到word在html_content中的首次出现,然后往前找50个字节(如果没有,就从begin开始),往后找100个字节(如果没有,就截取到end) //截取出这部分内容 const int prev_step = 50; const int next_step = 100; //1.找到首次出现 auto iter = std::search(html_content.begin(), html_content.end(), word.begin(), word.end(), [](int x, int y){ return (std::tolower(x) == std::tolower(y)); }); if(iter == html_content.end()){ return "None1"; } int pos = std::distance(html_content.begin(), iter); //2.获取start,end,std::size_t 无符号整数 int start = 0; int end = html_content.size() - 1; //如果之前有50+字符,就更新开始位置 if(pos > start + prev_step) start = pos - prev_step; if(pos < end - next_step) end = pos + next_step; //3.截取子串,return if(start >= end) return "None2"; return html_content.substr(start, end - start); }

None1修改完成

输出权值和doc_id

searcher.hpp

Json::Value root; for(auto &item : inverted_list_all){ ns_index::DocInfo * doc = index->GetForwardIndex(item.doc_id); if(nullptr == doc){ continue; } Json::Value elem; elem["title"] = doc->title; elem["desc"] = GetDesc(doc->content, item.word); //content是文档的去标签的结果,但是不是我们想要的,我们要的是一部分 elem["url"] = doc->url; //for debug elem["id"] = (int)item.doc_id; //int->string elem["weight"] = item.weight; root.append(elem); }

是按照权值大小降序排列的 打开这个网页查看

函数重名

util.hpp

class StringUtil{ public: static void Split(const std::string &target, std::vector<std::string> *out, const std::string &sep) { //boost split boost::split(*out, target, boost::is_any_of(sep), boost::token_compress_on); } };

把StringUtil的函数名改为Split

index.hpp

DocInfo *BuildForwardIndex(const std::string &line) { //1. 解析line,字符串切分 //line -> 3 string, title, content, url std::vector<std::string> results; const std::string sep = "\3"; //行内分隔符 ns_util::StringUtil::Split(line, &results, sep); //ns_util::StringUtil::CutString(line, &results, sep); if(results.size() != 3){ return nullptr; } //2. 字符串进行填充到DocIinfo DocInfo doc; doc.title = results[0]; //title doc.content = results[1]; //content doc.url = results[2]; ///url doc.doc_id = forward_index.size(); //先进行保存id,在插入,对应的id就是当前doc在vector中的下标! //3. 插入到正排索引的vector forward_index.push_back(std::move(doc)); //doc,html文件内容 return &forward_index.back(); }

把index的BuildForwardIndex的调用改为Split

修改文件名

makefile

PARSER=parser DUG=debug cc=g++ .PHONY:all all:$(PARSER) $(DUG) $(PARSER):parser.cc $(cc) -o $@ $^ -lboost_system -lboost_filesystem -std=c++11 $(DUG):debug.cc $(cc) -o $@ $^ -ljsoncpp -std=c++11 .PHONY:clean clean: rm -f $(PARSER) $(DUG)

将server.cc改名为debug.cc

mv server.cc debug.cc

权值和实际关键词出现次数不符合

会多计算也会少计算权值 可能分词工具在分词的时候会少分词 如果目标关键词在尖括号内,可能会当成标签处理,不会计入

把整个文件拿到内存 去标签之后,先拿到标题 对整个文件进行去标签,其中是包括标签的 实际,如果一个词在title中出现,一定会被当标题和当内容分别统计一次 index.hpp

bool BuildInvertedIndex(const DocInfo &doc) { //DocInfo{title, content, url, doc_id} //word -> 倒排拉链 struct word_cnt{ 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::CutString(doc.title, &title_words); if(doc.doc_id == 8713){ for(auto &s : title_words){ std::cout << "title: " << s << std::endl; } } //对标题进行词频统计 for(std::string s : title_words){ boost::to_lower(s); //需要统一转化成为小写 word_map[s].title_cnt++; //如果存在就获取,如果不存在就新建 } //对文档内容进行分词 std::vector<std::string> content_words; ns_util::JiebaUtil::CutString(doc.content, &content_words); if(doc.doc_id == 8713){ for(auto &s : content_words){ std::cout << "content: " << s << std::endl; } } //对内容进行词频统计 for(std::string s : content_words){ boost::to_lower(s); word_map[s].content_cnt++; } #define X 10 #define Y 1 //Hello,hello,HELLO for(auto &word_pair : word_map){ InvertedElem item; item.doc_id = doc.doc_id; item.word = word_pair.first; 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; }

debug.cc

#include "searcher.hpp" #include <iostream> #include <cstdio> #include <cstring> #include <string> const std::string input = "data/raw_html/raw.txt"; int main() { //for test ns_searcher::Searcher *search = new ns_searcher::Searcher(); search->InitSearcher(input); //std::string query; //std::string json_string; //char buffer[1024]; //while(true){ // std::cout << "Please Enter You Search Query# "; // fgets(buffer, sizeof(buffer)-1, stdin); // buffer[strlen(buffer) - 1] = 0; // query = buffer; // search->Search(query, &json_string); // std::cout << json_string << std::endl; //} return 0; }

生成了内容和分词,但是很难观察 创建一个log.txt

touch log.txt

将debug的内容重定向到log.txt当中

./debug > log.txt

共有7000行内容 查找split

标签:

9.综合调试|输入不能存在空格|desc存在None|输出权值和ID|函数重名|修改文件名|权值和实际关键词出现由讯客互联软件开发栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“9.综合调试|输入不能存在空格|desc存在None|输出权值和ID|函数重名|修改文件名|权值和实际关键词出现