爱悠闲 > TSE网页存储、中文分词、倒排索引生成

TSE网页存储、中文分词、倒排索引生成

分类: 自然语言处理  |  标签: 存储,html,url,vector,header,string  |  作者: cserchen 相关  |  发布日期 : 2014-06-14  |  热度 : 946°
  • TSE网页存储

 

根据驻留在内存里的set集合,取出没有爬取的网页连接,然后就去把它下载下来.

比如,下载了1000个网页,然后把这1000个HTML都放到一个文件里去,这个文件可能叫TianWang.raw.8415

意思就是线程号为8415的取的原始网页集合文件

对于每个在TianWang.raw.8415中的记录,都有一个对应的类叫CDocument(有点类似CPage.)

需要建立一个表,对每个记录(CDocument)在原始网页文件中的偏移,然后顺便提取他的网页内容摘要进行记录.

之后建立一个url摘要对应记录号的表.

好,这个过程的作用是什么呢?

比如某个时候,我想要提取url为www.google.cn的网页内容. 首先我去打开这个TianWang.raw.8415文件,然后

www.google.cn求MD5 摘要,通过这个摘要,找出这个url在TianWang.raw.8415中是第5个记录,那么知道了

他是第5个记录,再去查看他在TianWang.raw.8415中的偏移是1024,然后去读取接下来的网页,读多长,取决

于记录头中的长度字段信息.

以下是建立 记录<-->偏移量过程的关键代码,位于DocIndex.cpp中

while (getline(ifs, strLine)) {
   if (strLine[0]=='/0' || strLine[0]=='#' || strLine[0]=='/n'){
    nOffset = ifs.tellg();
    continue;
   }

    ofsDoc << iDocument.m_nDocId ;
    ofsDoc << "/t" << iDocument.m_nPos ;

}

 

 

  • TSE中文分词

 

TSE的字典用的是STL 中的MAP.关于英文字母的trie字典树,是一个26 叉树,查找效率0(logn).

现在,要把一篇网页内容分割成一个一个的关键词.TSE用的是最大正向减字法分词.

先用一个很大的数组接受html里,除了<>这些标签外的文字.

分成一个一个的句子来处理.

对一个句子,每次按照长度为ComLen来提取关键字,先用一个指针char* start指示开头,用char* end来指示

待匹配字符串尾. 如果start到end在字典里有匹配的词,就后移一个ComLen,继续匹配;如果没有这个词,就把

end往前移动一个位置继续匹配,直到又找到一个词,然后把start移动这个位置的后一个,end移动到

start+ComLen的位置,继续匹配.

关键步骤是无法匹配后,减少一个字符继续查字典,比如按照步长m来处理平均长度为d的句子,有k个句子

最坏情况是每次步长处理的时候,都没有找到匹配的单词,那么每次步长都要比较m次,查字典假设是红黑树

o(logn)的复杂度,那么最坏情况下 匹配成功一次后(只成功匹配了一个字符),start往后移动一个位置,所以总

共是mkdO(logn)

最大正向减字法,每次查字典的时候都是从最左边开始找,这是中文特有的分词,英文的话就按照空格可以

直接提取单词来匹配了.

 

  • TSE倒排索引生成

 

分词的代码在HzSeg.cpp中。

对raw格式的网页内容 进行分割的代码在DocSegment.cpp中

前面已经建立好2个表,一个是url对应着记录号,一个是记录号对应的偏移。

现在开始对网页进行处理,实际上只用到第2张表。

遍历这张表,把一个一个的记录取出来,存到CDocument对象里,将来要用时就知道

这个记录在原始文件raw里的偏移是多少,可以跳到那个位置去读

while (getline(ifsDoc,strLine)){
   int docid,pos,length;
   char chksum[33];

   memset(chksum, 0, 33);
   sscanf( strLine.c_str(), "%d%d%d%s", &docid, &pos, &length,chksum );
   iDocument.m_nDocId = docid;
   iDocument.m_nPos = pos;
   iDocument.m_nLength = length;
   iDocument.m_sChecksum = chksum;
   vecCDocument.push_back(iDocument);
}

然后从vector里面取出每个记录号,读取一个记录的所有内容(包括头)

然后移动致实际内容开始的地方

// skip Head
   int bytesRead = 0,newlines = 0;
   while (newlines != 2 && bytesRead != HEADER_BUF_SIZE-1) {
    if (*s == ' ')
     newlines++;
    else
     newlines = 0;
    s++;
    bytesRead++;
   }


把接下来的html正文内容传给iDocument.m_sBodyNoTags = s;

最后执行分词

string strLine = iDocument.m_sBodyNoTags;

CHzSeg iHzSeg;
   strLine = iHzSeg.SegmentSentenceMM(iDict,strLine);


分词的结果是记录ID号对应以"/"分割的关键字

重定向到正向索引文件中:

fout << docId << endl << strLine;
   fout << endl;


根据这些记录,生成一个文件