由上一篇文章[原]自頂向下學搜索引擎——北大天網(wǎng)搜索引擎TSE分析及完全注釋[1]尋找搜索引擎入口 我們可以知道整個程序是從TSESearch.cpp 中的main函數(shù)開始的我們重點一下這段代碼
//TSESearch.cpp CQuery iQuery;
iQuery.GetInputs(); //具體程序開始執(zhí)行
// current query & result page number
iQuery.SetQuery();
iQuery.SetStart();
// begin to search
//開始具體搜索程序
gettimeofday(&begin_tv,&tz); //開始計時獲取程序運行時間差
iQuery.GetInvLists(mapBuckets); //將所有字符集存入映射變量中 瓶頸所在
iQuery.GetDocIdx(vecDocIdx); //將倒排索引存入向量中 瓶頸所在
CHzSeg iHzSeg; //include ChSeg/HzSeg.h
iQuery.m_sSegQuery = iHzSeg.SegmentSentenceMM(iDict, iQuery.m_sQuery); //將get到的查詢變量分詞分成 "我/ 愛/ 你們/ 的/ 格式"
vector vecTerm;
iQuery.ParseQuery(vecTerm); //將以"/"劃分開的關鍵字一一順序放入一個向量容器中
set setRelevantRst;
iQuery.GetRelevantRst(vecTerm, mapBuckets, setRelevantRst);
gettimeofday(&end_tv,&tz);
// search end
//搜索完畢按照順序我們首先深入進iQuery對象的類CQuery
//Query.cpp
1、GetInputs
這個方法的功能是將前臺get過來的變量轉(zhuǎn)換到HtmlInputs結(jié)構體數(shù)組中如下例子和代碼:
//假設前臺查詢的關鍵字是"1"著HtmlInputs中內(nèi)容輸出如下 //HtmlInputs[0].Name word //HtmlInputs[0].Value 1 //HtmlInputs[1].Name www //HtmlInputs[1].Value 搜索 //HtmlInputs[2].Name cdtype //HtmlInputs[2].Value GB
/*
* Get form information throught environment varible.
* return 0 if succeed, otherwise exit.
*/
/**
* 程序翻譯說明
* 處理GET過來的表單
*
* @access public
* @return string 0
*/
int CQuery::GetInputs()
{
int i,j;
char *mode = getenv("REQUEST_METHOD"); //返回環(huán)境變量的值 這里環(huán)境變量 REQUEST_METHOD 為 get 方法
char *tempstr; //GET變量字符串或POST字符串內(nèi)容
char *in_line;
int length; //GET變量串長度或POST內(nèi)容長度
cout << "Content-type: text/html\n\n";
//cout << "Cache-Control: no-cache\n";
//cout << "Expires: Tue, 08 Apr 1997 17:20:00 GMT\n";
//cout << "Expires: 0\n";
//cout << "Pragma: no-cache\n\n";
cout << "\n";
cout << "\n";
//cout << "\n";
//cout << "\n";
//cout << "\n";
cout << "\n";
cout.flush(); //釋放輸出緩沖區(qū) 輸出頭部head和之前的html標簽內(nèi)容
//cout <<"" << endl;
if (mode==NULL) return 1;
if (strcmp(mode, "POST") == 0)
{
length = atoi(getenv("CONTENT_LENGTH")); //如果是POST方法著獲得環(huán)境變量CONTENT_LENGTH的整型值
if (length==0 || length>=256)
return 1;
in_line = (char*)malloc(length + 1);
read(STDIN_FILENO, in_line, length);
in_line[length]='\0';
}
else if (strcmp(mode, "GET") == 0)
{
char* inputstr = getenv("QUERY_STRING"); //如果是GET方法著獲得環(huán)境變量QUERY_STRING的字符串值
length = strlen(inputstr);
if (inputstr==0 || length>=256)
return 1;
//獲取get內(nèi)容長度并把get ?后面的參數(shù)賦值給變量in_line
in_line = (char*)malloc(length + 1);
strcpy(in_line, inputstr); //小心溢出攻擊
}
tempstr = (char*)malloc(length + 1); //獲取post內(nèi)容或get內(nèi)容長度
if(tempstr == NULL)
{
printf("\n");
printf("\n");
printf("Major failure #1;please notify the webmaster\n");
printf("\n");
fflush(stdout); //輸出緩沖區(qū)
exit(2); //錯誤返回
}
j=0;
for (i=0; i char
strcpy(HtmlInputs[HtmlInputCount].Name,tempstr);
if (i == length - 1)
{
strcpy(HtmlInputs[HtmlInputCount].Value,"");
HtmlInputCount++;
}
j=0;
}
else if ((in_line[i] == '&') || (i==length-1))
{
if (i==length-1)
{
if(in_line[i] == '+')tempstr[j]=' ';
else tempstr[j] = in_line[i];
j++;
}
tempstr[j]='\0';
CStrFun::Translate(tempstr); //將URL編碼形式的參數(shù)轉(zhuǎn)換成字符型 %** -> char
strcpy(HtmlInputs[HtmlInputCount].Value,tempstr);
HtmlInputCount++;
j=0;
}
else if (in_line[i] == '+')
{
tempstr[j]=' ';
j++;
}
else
{
tempstr[j]=in_line[i]; //組合get中的變量如word www cdtype
j++;
}
//cout<";
//cout<";
//cout.flush();
}
/*
for (int kk = 0; kk < HtmlInputCount ; ++kk )
{
cout<<"Name="<";
cout<<"Value="<";
}
//假設前臺查詢的關鍵字是"1"輸出如下
//Name=word
//Value=1
//Name=www
//Value= 搜索
//Name=cdtype
//Value=GB
*/
if(in_line) free(in_line);
if(tempstr) free(tempstr);
return 0;
}
2、SetQuery
//Query.cpp
void CQuery::SetQuery()
{
string q = HtmlInputs[0].Value;
CStrFun::Str2Lower(q,q.size()); //大寫變小寫
m_sQuery = q; //準備查詢關鍵字
}
3、SetStart
void CQuery::SetQuery()
{
string q = HtmlInputs[0].Value;
CStrFun::Str2Lower(q,q.size()); //大寫變小寫word變量里的值
m_sQuery = q; //設置查詢關鍵字
}
4、GetInvLists
bool CQuery::GetInvLists(map<string, string> &mapBuckets) const
{
ifstream ifsInvInfo(INF_INFO_NAME.c_str(), ios::binary); //以二進制形式打開一個文件的輸入流緩沖,INF_INFO_NAME在頭文件Comm.h中定義了的, const string INF_INFO_NAME("./Data/sun.iidx");
//倒排索引文件索引字和文檔好之間有一個制表符"\t"
//朱德 14383 16151 16151 16151 1683 207 6302 7889 8218 8218 8637
//朱古力 1085 1222
if (!ifsInvInfo) {
cerr << "Cannot open " << INF_INFO_NAME << " for input\n";
return false;
}
string strLine, strWord, strDocNum;
//以行讀取輸入流緩沖到字符串對象strLine中并做處理
while (getline(ifsInvInfo, strLine)) {
string::size_type idx;
string tmp;
idx = strLine.find("\t");
strWord = strLine.substr(0,idx);
strDocNum = strLine.substr(idx+1);
mapBuckets.insert(map<string,string>::value_type (strWord, strDocNum)); //倒排表二項二維表存入映射中
/*
map<string, string>::iterator iter;
int kkk = 0;
for (iter = mapBuckets.begin(); kkk != 10; ++iter)
{
cout<<iter->first<<" "<<iter->second<<"<br>";
++kkk;
}
cout.flush();
*/
}
return true;
}
5、GetDocIdx
bool CQuery::GetDocIdx(vector &vecDocIdx) const
{
ifstream ifs(DOC_IDX_NAME.c_str(), ios::binary);
//0 0 bc9ce846d7987c4534f53d423380ba70
//1 76760 4f47a3cad91f7d35f4bb6b2a638420e5
//2 141624 d019433008538f65329ae8e39b86026c
if (!ifs) {
cerr << "Cannot open " << DOC_IDX_NAME << " for input\n"; //以二進制形式打開一個文件的輸入流緩沖,DOC_IDX_NAME在頭文件Comm.h中定義了的, const string INF_INFO_NAME("./Data/Doc.idx");
return false;
}
string strLine, strDocid, strUrl;
while (getline(ifs,strLine)){
DocIdx di;
sscanf( strLine.c_str(), "%d%d", &di.docid, &di.offset ); //只保留了前面兩項文檔號和偏移量
vecDocIdx.push_back(di); //導入結(jié)構體向量中
}
return true;
}