参考 wiki百科:https://zh.wikipedia.org/wiki/%E5%80%92%E6%8E%92%E7%B4%A2%E5%BC%95
比如说,现在有这些文章以及文章中含有的单词
以英文为例,下面是要被索引的文本:
文本0 - "it is what it is"
文本1 - "what is it"
文本2 - "it is a banana"
我们就能得到下面的反向文件索引:
"a": {2}
"banana": {2}
"is": {0, 1, 2}
"it": {0, 1, 2}
"what": {0, 1}
检索的条件"what", "is" 和 "it" 将对应这个集合: {0,1} {0,1,2} , {0,1,2}。
那么,同时含有这三个文件的文档就是上面的几个文件的交集,也就是0和1号是有这两个文件里面是有"what", "is" 和 "it" 三个单词的。
之所以通过取交集的方式可以找到哪些文件里面有这些单词其实是因为,这些若干集合的交集是个A,A里面的文件序号就一定是包含了这个words_vec里面的所有的单词的。
如果要用算法实现,先通过输入单词以及文件,得到倒排索引。然后假设输入的单词是个vector<string> vec。查找的逻辑大约是:
unordered_map <int , int > count_map ;// 文件的标号,以及文件出现的次数
unordered_map <string,sharede_ptr<unordered_set> > info ; //表示的单词和
for(auto str_it : words_vec){
//统计每个单词出现在哪些的文件中,也就是文件的标号,以及文件的标号出现的次数
shared_ptr<unordered_set> set_ptr ;
if( (set_ptr = info.find(*str_it) )!= info.end()) //找到了这个单词
{
//统计这些文件出现的次数
for(auto set_it = set_ptr->begin() ; set_it != set_ptr->end() ; set_it ++)
{
if(count_map.find( *set_it ) != count_map.end() )
{
count_map[*set_it ] ++;
}
else
{
count_map[*set_it ] = 1;
}
}
}
for(auto it = count_map.begin() ; it!= count_map.end() ; it++)
{
if(it->second == word_vec.size())
{
cout<<it->first<<endl;
}
}
}
对相同的文字,我们得到后面这些完全反向索引,有文档数量和当前查询的单词结果组成的的成对数据。 同样,文档数量和当前查询的单词结果都从零开始。所以,"banana": {(2, 3)} 就是说 "banana"在第三个文档里 而且在第三个文档的位置是第四个单词(地址为 3)。
"a": {(2, 2)}
"banana": {(2, 3)}
"is": {(0, 1), (0, 4), (1, 1), (2, 1)}
"it": {(0, 0), (0, 3), (1, 2), (2, 0)}
"what": {(0, 2), (1, 0)}
如果我们执行短语搜索"what is it" 我们得到这个短语的全部单词各自的结果所在文档为文档0和文档1。但是这个短语检索的连续的条件仅仅在文档1得到。
代码的实现是可以在统计每个文件出现的个数的时候,统计出出现的位置,最后判断下单词出现的位置是不是连续的,且是不是按照需要查找的那种顺序就可以了。
unordered_map <int , map<int>> count_map ;// 文件的标号,文件出现的位置,map的最后一个值减去最前面一个值以及map的size就可以判断出这个map里面的数据是不是连续的
unordered_map <string,sharede_ptr<unordered_set<int , int >> > info ; //< 单词 , <文件编号, 单词位置> >