信息检索导论中提到的倒排索引构建方法:
内存式单遍扫描索引构建方法(SPIMI : Single-pass in-memeory indexing):
思想:将一个文档集分割成几个大小相等的部分,参考标准就是分成的每个块可以一次性的装入内存
将处理每个块产生的词典写入磁盘,对于下一个块则重新采用新的词典。只要硬盘空间足够大,
SPIMI就能索引任何大小的文档集。
算法流程(在执行过程中反复调用SPIMI-Invert函数直到将全部文档集处理完成):
SPIMI-Invert(token_stream)
1 output_file = NEWFILE()
2 dictionary = NEWHASH()
3 while(free memory available)
4 do token ← next(token_stream)
5 if term(token) !∈dictionary // 即不在词典中
6 then postings_list = AddToDictionary(dictionary, term(token)) // 加入词典并返回词典位置
7 else postings_list = GetPostingList(dictionary, term(token)) // 找到词典位置
8 if full(postings_list) // 关键词对应存储倒排文档的数据结构可用空间是否已满
9 then postings_list = DoublePostingList(dictinary, term(token)) // 重新分配关键词对应存储倒排文档的数据结构可用空间 使其变为原来2倍
10 AddToPostingsList(postings_list, docId(token)) // 将文档信息放入倒排表中
11 sorted_terms ← SortTerms(dictionary) //对词典排序(便于以后合并词典)
12 WriteBlockToDisk(sorted_terms, dictionary, output_file) // 将倒排信息写入磁盘
13 return output_file
说明:1. 在算法中每个倒排记录表是动态增长的。由于事先不知道每个词项的倒排记录表的大小,算法一开始会
分配一个较小的倒排记录表空间,每次当改空间放满的时候,就会申请加倍的空间(程序8,9行)
2. 当内存耗尽时包括词典和倒排记录表的索引块会被写到磁盘上,在这之前,为了使倒排记录表按照词典的
顺序排序起来加快最后的合并过程,要对词项进行排序操作(程序第11行)
3. 每次对SPIMI-Inverter的调用都会写到一块磁盘上。
4. SPIMI的最后一步就是将多个块合并成最后的倒排索引
本人已经实现上述算法(代码拙劣,未敢贴出),大体设计思路如下:
上述算法中所用的词典这里选择用哈希表实现。所有的hash函数为暴雪的hash算法(用100万个不重复的字符串测试没有出现冲突)哈希表的定义如下
struct MPQHashTable *hash_table = new struct MPQHashTable[HASH_LENGTH]; 其中struct MPQHashTable的定义如下:
// 哈希索引表定义
struct MPQHashTable
{
// 以下三个变量是暴雪算法所用,用于确定关键字位置
long nHashA;
long nHashB;
bool bExists;
string key_name; // 关键字名称
int key_count; // 关键字出现的次数
int current_doc_count; // 关键字对应的文档数
int max_doc_count; // 初始化每个关键字可以对应的最大文档数目
struct DocInfo *doc_nodes; //关键字对应的文档
// ......
};
struct doc_node // 文档的信息
{
string id ; // 文档ID
int class_one ; // 订阅源
string class_two; // 频道分类
int class_three; //网站类ID
string time ; // 时间
int weight ; // 文档权值
};
每提取出一个关键词以及对应文档信息后,就检查关键字是否在hash表中,如果不在hash表中,则首先初始化关键字对应hash位置的 struct DocInfo *doc_nodes, 并将关键字和文档信息放到哈希表中。 如果关键字在hash表中,检查struct DocInfo *doc_nodes空间是否用尽,如果用尽的话重新分配,否则将关键字和文档信息放到哈希表中。
当哈希表已经存满或者文档读取完成之后,将内存中的倒排信息排序。即对struct MPQHashTable *hash_table按照关键字排序。然后将信息输出到文档。
假设正排文件处理完成了,生成了n个小的倒排文档, 需要将这些倒排文档合并。合并倒排文件实现思路是:
首先定义map类型:map
然后打开n个已经排序好的倒排文件,每个文件每次扫描一行,提取出关键字和对应文档信息。并在map中查找当前提取的关键字是否已经存在 如果关键字已经存在的话更新map中关键字的信息(即合并map中关键对应文档以及当前扫描的关键字对应文档)否则的话将关键字插入到map集合中。 当每次扫描完所有文件的一行后,检查map集合中的数量是否已经达到了阀值(阀值为自己设定,相当于缓存区的最大值,防止内存溢出)如果已经达到阀值则找到上一次扫描文件完成后的关键字的最小值temp_key, 并找到temp_key对应map的位置,将map 的begin 到end 之间的关键字对应文档信息输出然后删除map中begin和end 之间的值。然后继续对所有文件扫描下一行,直到文件结束。将map中的所有信息输出,倒排索引合并完成。
倒排索引数据结构应该是如下形式:
举例:
假定有如下正排文档:,每一行的信息分别为(中间用###隔开):文档ID、订阅源(子频道)、 频道分类、 网站类ID(大频道)、时间、 md5、文档权值、关键词
TA011121600045170###347###A0###2###20111214213127###86b4bc20eb98b1eb21932ebf5dcfcca5###1###兰州###空气质量#
TA011121600045168###347###A0###2###20111215181000###e9cc79096791d0325457ada45479c574###1###山东#
TA011121600045173###347###A0###2###20111215182200###6ba5c35e22695afb0a9b17eb0e9bb244###1###东营###山东###滨州###发改委#
TA011121600045175###347###A0###2###20111215043400###a0a16c9f361275f370ddbb98b6f3c0d2###1###国民生计#
TA011121600045177###347###A0###2###20111213154600###728bbe41dbca2df0f590bcba948f605f###1###遵义###贵州#
TA011121600045171###347###A0###2###20111214215950###ff5aed86a2dd71326f82b4f854f4309c###1###宁夏###固原#
TA011121600045174###347###A0###2###20111214170531###fcff1bfb8346408be408aabfb5a9f6e3###1###北戴河###皇岛#
TA011121600045176###347###A0###2###20111214160605###e11cb22662f5991703480bc479bc3409###1###行政强制法#
TA011121600045178###347###A0###2###20111215062300###f4ba726460233b182412adcc4f782738###1###细则#
TA011121600045181###347###A0###2###20111212191416###d4b5ba42b451a8c056834c01b292807d###1###西藏###农业部#
TA011121600045189###347###A0###2###20111213153300###c1bee53a1f2b4bbfd21962c33c9a16f9###1###邯郸###河北省#
TA011121600045182###347###A0###2###20111210214352###8ecd3fa5f3e03ba7dc0e6a492519a1b0###1###自然灾害###贵州#
TA011121600045192###347###A0###2###20111211181900###8546f99853ef7767ffac9e293194a96b###1###北京地铁#
TA011121600045187###347###A0###2###20111210190100###82caf9d9aeef4c6d25625d87fce8cac8###1###社会安全事件#
TA011121600045185###347###A0###2###20111213075829###357d633eae1c8dd886f3cfaa487c89f1###1###黑龙江#
TA011121600045194###347###A0###2###20111214211000###4fa041d7af68c16312fbc28d8e7dcfae###1###交通事故#
TA011121600045190###347###A0###2###20111207040038###a726dd72da62c3c5ad4232dc3c9646d3###1###通州###党代会###人民大学###中国人民大学#
TA011121600045197###347###A0###2###20111213224800###70af80c50546d5d1809a0d3d55e13736###1###邯郸#
TA011121600045199###347###A0###2###20111213210300###c765ce48ff7482ee91b7c9bd1500ad13###1###新疆#
TA011121600045201###347###A0###2###20111207052805###834970138e1030ce769b7e4b1fae6f6c###1###湖北###教育厅#
我们要做的就是根据关键字生成倒排文档如下:
兰州 6 1
20111214 1 TA011121600045170 347 A0 2 86b4bc20eb98b1eb21932ebf5dcfcca5 1
20111108 1 TA011121800009974 687 A0 436 17af5499fd53df772949ae81736e9bce 1
20111030 1 TA011121800010436 687 A0 436 ce560003a1858a418dc0ee9772d69639 1
20111029 4 TA011121600072676 687 A0 436 e8075db72fab580e0a40e1f31d11700a 1
20111026 1 TA011121800009775 687 A0 436 31eb67c38197b95bf846120dd8f98891 1
20111019 1 TA011121600068509 577 A0 394 e125e59722c3b01c0c7f6d8ee5911451 1
空气质量 21 2
20111216 1 TE011121700004271 598 E0 2 1f3bf43232b34f086b01be8b933967ae 1
20111214 2 TA011121600045170 347 A0 2 86b4bc20eb98b1eb21932ebf5dcfcca5 1
20111209 1 TA011121600067953 577 A0 394 f04f4aba854042f7d221010b7215a61a 1
20111207 1 TA011121600068667 577 A0 394 898f3d0a91b90813d5dde8ccdd14120d 1
20111118 1 TA011121800011263 573 A0 390 4e0bc3ee0ab58c73f857e56e27971244 1
20111109 1 TA011121800009253 687 A0 436 83dd71dcb751fdbdb3ec36a7d896d437 1
..........(数据有省略)
山东 30 3
20111214 1 TA011121600068241 577 A0 394 b25ca86db973c60bdd12b16163269b12 1
20111213 1 TA011121600068107 577 A0 394 d8116c3e94a25ff4ff611b60f2b836d0 1
20111212 2 TA011121700004439 620 A0 172 5779211a892b2eebefeb2dd0c1d708fc 1
20111118 1 TE011121700004377 622 E0 172 ee2bfb759f3bd992c4cfc99b68fd6066 1
20111111 1 TA011121800009216 687 A0 436 c6085144d0d391bf46a6b9f3dc813eeb 1
..........(数据有省略)
东营 5 4
20111215 2 TA011121600045173 347 A0 2 6ba5c35e22695afb0a9b17eb0e9bb244 1
20111201 1 TA011121700026609 687 A0 436 5e0a6b919021d9491f8f8d98498bebc2 1
20111101 1 TA011121800009456 687 A0 436 6e733369497cd6435548fd1c0f082e6d 1
20111027 1 TA011121800010270 687 A0 436 977a9d70c2d57b3e7cc72ee7df63ec1a 1
20110530 1 TA011121600045461 347 A0 2 0755596f2fbe3f40de5cc8f92b1aede0 1