【北大天网搜索引擎TSE学习笔记】第8节——检索关键词+结果排序

        这一节将介绍搜索功能入口程序TSESearch.cpp的第四步和第五步——检索关键词+结果排序。


        其实,检索关键词非常简单,因为已经建立了倒排表mapBuckets,它是一个map结构,检索某个关键词,就是用map的find方法查询(下面代码中的第27),没有什么需要介绍的。也因此,TSE中将检索关键词和结果排序在一起实现,也就是main函数中调用的函数:iQuery.GetRelevantRst(vecTerm, mapBuckets, setRelevantRst)。

下面就看该函数的源代码,分析TSE中检索关键词和结果排序的实现。TSE的结果排序方法很简单,就是采用的词频(Term frequency)进行排序的,关于词频排序可以到网上搜索TF-IDF词条进行学习,这里不做详细说明。简单说,词频排序就是:网页中某个关键词出现次数(词频)越高,说明该网页与该关键词相关性越高,因而在结果排序中越优。


        下面的代码中加入了详细的注释(以“LB_C”开始的注释为我加入的)进行说明。

//LB_c: vecTerm中存储的用户查询字串分词以后的关键词,mapBucket为倒排表,setRelevantRst存储最终的查询的结果(里面存储
// 的是结果网页的docid)
bool CQuery::GetRelevantRst(vector<string> &vecTerm, 
	map<string,string> &mapBuckets, 
	set<string> &setRelevantRst) const
{
	//LB_c: 临时存储已经查询的结果
	set<string> setSRst;
	bool bFirst=true;

	//LB_c: 分别对vecTerm中的每一个关键词进行查询
	vector<string>::iterator itTerm = vecTerm.begin();
	for ( ; itTerm != vecTerm.end(); ++itTerm ){

		//LB_c: setRelevantRst为已查询的结果,将setRelevantRst存入setSRst中,后面将用到。
		setSRst.clear();
		copy(setRelevantRst.begin(), setRelevantRst.end(), 
		inserter(setSRst,setSRst.begin()));

		//LB_c: mapRstDoc是一个用于临时统计的map,string对应一个docID,int是该docID出现的次数(也就是当前关键词在docid
		// 的网页中出现的次数,也成为"词频",后面将称为"词频"), 后面是根据词频值对搜索结果进行排序的(即关键词出现次数
		// 越多的网页应该越"优")。
		map<string,int> mapRstDoc;
		string docid;
		int doccnt;
		//LB_c: 在倒排表中查询关键词(*itTerm)
		map<string,string>::iterator itBuckets = mapBuckets.find(*itTerm);	
		//LB_c: 在倒排表中找到了该关键词
		if (itBuckets != mapBuckets.end()){

			//LB_c: 获取该关键词出现的文档ID列表(即倒排表记录的第二项,忘记了的朋友可以看看第2节中倒排文件的结构)
			string strBucket = (*itBuckets).second;

			string::size_type idx;
			idx = strBucket.find_first_not_of(" ");
			strBucket = strBucket.substr(idx);

			//LB_c: 循环从文档ID列表字符串中获取一个文档ID,并计算词频,插入mapRstDoc中
			while ( (idx = strBucket.find(" ")) != string::npos ) {
				docid = strBucket.substr(0,idx);
				if (docid.empty()) continue;
				doccnt = 0;	//LB_c: 计算词频
				//LB_c: 到mapRstDoc中查询该docid是否出现过
				map<string,int>::iterator it = mapRstDoc.find(docid);
				//LB_c: 如果docid出现过
				if ( it != mapRstDoc.end() ){
				//LB_c: 获取词频((*it).second)加1存入doccnt
				doccnt = (*it).second + 1;
				//LB_c: 从mapRstDoc把该条记录删除,下面将重新插入
				mapRstDoc.erase(it);
				}

				//LB_c: 将该条记录重新插入到mapRstDoc,其实先删除再插入这条记录的结果就是docid的词频加了1
				//LB_c: 这里应该有点问题! 如果docid没出现过,那么doccnt的值为0,则插入到mapRstDoc的对应于docid
				// 的词频0,所以前面doccnt的初值是不是应该为1呢?
				mapRstDoc.insert( pair<string,int>(docid,doccnt) );

				//LB_c: 去掉分析过的docid更新strBucket,继续分析下一个文档ID
				strBucket = strBucket.substr(idx+1);
			}

			//LB_c: 下面这部分是处理strBucket中最后一个docid,因为while循环结束时,最后一个docid还没有处理
			// remember the last one
			docid = strBucket;
			doccnt = 0;
			map<string,int>::iterator it = mapRstDoc.find(docid);
			if ( it != mapRstDoc.end() ){
			doccnt = (*it).second + 1;
			mapRstDoc.erase(it);
			}
			mapRstDoc.insert( pair<string,int>(docid,doccnt) );
		}
		//LB_c: 这一部分处理完后,mapRstDoc存储的是一系列docid和该docid的词频。

		// sort by term frequencty
		//LB_c: 这部分是对刚才的带有词频的文档查询结果mapRstDoc进行了排序,排序结果存入到newRstDoc中。
		//LB_c: 注意newRstDoc的类型,第一个域为int表示docid的词频,第二个域是string表示docid,第三个域
		// 是排序规则----以键值(词频)的降序排列,注意newRstDoc是multimap,也就是键值可以重复。
		multimap<int, string, greater<int> > newRstDoc;
		map<string,int>::iterator it0 = mapRstDoc.begin();
		for ( ; it0 != mapRstDoc.end(); ++it0 ){
			newRstDoc.insert( pair<int,string>((*it0).second,(*it0).first) );
		}

		//LB_c: 这部分是将当前关键词(*itTerm)的排序查询结果newRstDoc插入到最终的查询结果setRelevantRst中,
		// 这里要参考前面的关键词查询结果。
		multimap<int,string>::iterator itNewRstDoc = newRstDoc.begin();	
		//LB_c: 将最终的查询结果setRelevantRst清空
		setRelevantRst.clear();	
		//LB_c: 循环读取newRstDoc中的每一条记录(这些记录是按docid的词频排序的),根据情况插入到最终结果中
		for ( ; itNewRstDoc != newRstDoc.end(); ++itNewRstDoc ){

			//LB_c: 获取该条记录的docid
			string docid = (*itNewRstDoc).second;		
			//LB_c: 如果当前关键词是第一个查询的关键词,则直接插入到结果集中
			if (bFirst==true) {
				setRelevantRst.insert(docid);
				continue;
			}

			//LB_c: 如果不是第一个关键词查询,则看已查询结果集setSRst中是否有该docid,也就是前面查询的关键词
			// 有没有出现在docid的网页中。这里也体现了TSE搜索的规则: 只有所有关键词都出现的网页才有效,部分关键
			// 词出现的网页不作为搜索结果。如果setSRst中有该docid说明docid的网页也包含前面查询的关键词, 则将
			// docid插入到最终结果集setRelevantRst中。
			if ( setSRst.find(docid) != setSRst.end() ){	
				setRelevantRst.insert(docid);
			}
		}

		//LB_c: 这里思考一下! 首先将setRelevantRst清空,然后将当前关键词(*itTerm)的排序结果newRstDoc插入到最终结果集
		// setRelevantRst中。也就是最终的结果排序是以最后一个查询关键词的词频排序的,即最后一个关键词出现次数多的网页
		// 排在前面。

		bFirst = false;
	}

	return true;
}


这一节之后,关于TSE查询服务子系统的介绍就只剩下最后一节——显示搜索结果了,本来想年前把它写完的,由于明天回家过年了,是在没有时间了,所以只能年后再继续了。回家happy去啦~~ 也预祝各位读者新年快乐,工作顺利~~


By:

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
TSE(Tiny Search Engine) ======================= (Temporary) Web home: http://162.105.80.44/~yhf/Realcourse/ TSE is free utility for non-interactive download of files from the Web. It supports HTTP. According to query word or url, it retrieve results from crawled pages. It can follow links in HTML pages and create output files in Tianwang (http://e.pku.edu.cn/) format or ISAM format files. Additionally, it provies link structures which can be used to rebuild the web frame. --------------------------- Main functions in the TSE: 1) normal crawling, named SE, e.g: crawling all pages in PKU scope. and retrieve results from crawled pages according to query word or url, 2) crawling images and corresponding pages, named ImgSE. --------------------------- INSTALL: 1) execute "tar xvfz tse.XXX.gz" --------------------------- Before running the program, note Note: The program is default for normal crawling (SE). For ImgSE, you should: 1. change codes with the following requirements, 1) In "Page.cpp" file, find two same functions "CPage::IsFilterLink(string plink)" One is for ImgSE whose urls must include "tupian", "photo", "ttjstk", etc. the other is for normal crawling. For ImgSE, remember to comment the paragraph and choose right "CPage::IsFilterLink(string plink)". For SE, remember to open the paragraph and choose righ "CPage::IsFilterLink(string plink)". 2) In Http.cpp file i. find "if( iPage.m_sContentType.find("image") != string::npos )" Comment the right paragraph. 3) In Crawl.cpp file, i. "if( iPage.m_sContentType != "text/html" Comment the right paragraph. ii. find "if(file_length < 40)" Choose right one line. iii. find "iMD5.GenerateMD5( (unsigned char*)iPage.m_sContent.c_str(), iPage.m_sContent.length() )" Comment the right paragraph. iv. find "if (iUrl.IsImageUrl(strUrl))" Comment the right paragraph. 2.sh Clean; (Note not remove link4History.url, you should commnet "rm -f link4History.url" line first) secondly use "link4History.url" as a seed file. "link4History" is produced while normal crawling (SE). --------------------------- EXECUTION: execute "make clean; sh Clean;make". 1) for normal crawling and retrieving ./Tse -c tse_seed.img According to query word or url, retrieve results from crawled pages ./Tse -s 2) for ImgSE ./Tse -c tse_seed.img After moving Tianwang.raw.* data to secure place, execute ./Tse -c link4History.url --------------------------- Detail functions: 1) suporting multithreads crawling pages 2) persistent HTTP connection 3) DNS cache 4) IP block 5) filter unreachable hosts 6) parsing hyperlinks from crawled pages 7) recursively crawling pages h) Outputing Tianwang format or ISAM format files --------------------------- Files in the package Tse --- Tse execute file tse_unreachHost.list --- unreachable hosts according to PKU IP block tse_seed.pku --- PKU seeds tse_ipblock --- PKU IP block ... Directories in the package hlink,include,lib,stack,uri directories --- Parse links from a page --------------------------- Please report bugs in TSE to MAINTAINERS: YAN Hongfei * Created: YAN Hongfei, Network lab of Peking University. * Created: July 15 2003. version 0.1.1 * # Can crawl web pages with a process * Updated: Aug 20 2003. version 1.0.0 !!!! * # Can crawl web pages with multithreads * Updated: Nov 08 2003. version 1.0.1 * # more classes in the codes * Updated: Nov 16 2003. version 1.1.0 * # integrate a new version linkparser provided by XIE Han * # according to all MD5 values of pages content, * for all the pages not seen before, store a new page * Updated: Nov 21 2003. version 1.1.1 * # record all duplicate urls in terms of content MD5

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值