万恶的考试终于结束了,同学们说的各种跪的节奏,按照他们说“哪里不会考哪里,妈妈再也不用担心我不挂科了...”,我没啥感觉,只是考完了,这几天恶心的生活也就结束了,平时学得不踏实,真是...下学期还是稍微听一下课吧,虽然听不懂...
闲话少叙,说说这道题,是一个同学让我帮忙的,话说后来还给了点吃的,满足啊...
就是给给一个文档集,利用倒排挡索引技术,实现
1.输入布尔表达式,如:输入hello&world,输出同时存在这两个单词的文档名
2.输入一个词组,输出存在这个词组的文档名
看到这道题我就感觉自己不会,但是经不住女生,所以硬着头皮上吧,google了一下倒排索引技术;
倒排索引(英语:Inverted index),也常被称为反向索引、置入档案或反向档案,是一种索引方法,被用来存储在全文搜索下某个单词在一个文档或者一组文档中的存储位置的映射。它是文档检索系统中最常用的数据结构。
有两种不同的反向索引形式:
1、一条记录的水平反向索引(或者反向档案索引)包含每个引用单词的文档的列表。
2、一个单词的水平反向索引(或者完全反向索引)又包含每个单词在一个文档中的位置。
后者的形式提供了更多的兼容性(比如短语搜索),但是需要更多的时间和空间来创建。
找了一下相关的文章,找到July的(这不算侵犯姓名权吧)了...可是看不懂,而且这任务让我一个晚上搞定,好吧,还是弄一个山寨版的吧...
首先通过index.txt文件,里面存放的是文件的ID及其对应的路径,其中ID后续用于找到文件名;
这一段不知道是从哪位仁兄那借的,由于时间有一段了,找不到了,如有看到,请评论,我会加上的...甚是感激;
void ReverseIndex()
{
//重定向从index.txt中读入,输出到result.txt其中index.txt,result.txt都是在当前目录下
freopen("index.txt", "r", stdin);
init();
int id; //id名
string filepath; //文件路径名
while(cin>>id>>filepath)//从index中读入id名和文件路径名
{
filecount++;
path[filecount] = filepath;
int th = 0;
ifstream fin(filepath.c_str());//打开文件路径下的文件,参数应是c风格的字符串
string s;
while(fin>>s)//一个单词一个单词地读入
{
th++;
//if(indextable[s][i])
indextable[s].push_back(M * id + th);//把当前单词对应的文件名加入到单词对应的ID数组中
}
}
fclose(stdin);
fflush(stdin);
freopen("result.txt","w",stdout);
map<string,vector<int> >::iterator map_it;//索引表迭代器
map_it=indextable.begin();
while(map_it!=indextable.end())//遍历整个索引表输出,因为MAP的键值是严格弱排序,因此输出是字典序
{
string tmp = map_it->first;
cout<<tmp<<" ";
for(int i = 0; i != indextable[tmp].size(); i++)
cout<<indextable[tmp][i]<<" ";
cout<<endl;
map_it++;
}
fclose(stdout);
fflush(stdout);//将输出缓冲区清空
}
这一段的结果是建立了一个单词与对应的M * id + th;其中th是单词是在文档的第几个单词,M是10000或者100000,得到该值之后%M,就可以得到在文档中的位置,当然,文档中的单词个数不能大于M...
将这个根本的文件解决之后,就可以讨论问题了;
1.输入布尔表达式,如:输入hello&world,输出同时存在这两个单词的文档名
2.输入一个词组,输出存在这个词组的文档名
1问题通过录入数据,将&隔开处理即可,另外2词组问题即是空格(词组只处理了一个两单词的数组,不定位的输入只会处理前两位);
在这次问题中,由于文件的重定向问题导致了很多问题,不能向控制台输入输出等,后来好不容易可以输出了,但是竟然读取不了输入数据,当然,这个问题后续也没解决,只是将判断及录入的情况放在前面讨论了,后面进行重定向输出的...
总之,这一次还是学到很多东西的,贴下代码吧(文件index.txt,result.txt以及index.txt里的文件记得补上。。。)
#include<iostream>
#include<fstream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<map>
#include<vector>
#include<algorithm>
const int M = 100000;
using namespace std;
int a[100] = {0};
int filecount = 0; //文件的个数
string path[100] = "";
int words = 0; //仅仅查找单词时 单词的个数
map<string,vector<int> > indextable;//倒排索引表
void init() //初始化表
{
indextable.clear();
}
void ReverseIndex()
{
//重定向从index.txt中读入,输出到result.txt其中index.txt,result.txt都是在当前目录下
freopen("index.txt", "r", stdin);
init();
int id; //id名
string filepath; //文件路径名
while(cin>>id>>filepath)//从index中读入id名和文件路径名
{
filecount++;
path[filecount] = filepath;
int th = 0;
ifstream fin(filepath.c_str());//打开文件路径下的文件,参数应是c风格的字符串
string s;
while(fin>>s)//一个单词一个单词地读入
{
th++;
//if(indextable[s][i])
indextable[s].push_back(M * id + th);//把当前单词对应的文件名加入到单词对应的ID数组中
}
}
fclose(stdin);
fflush(stdin);
freopen("result.txt","w",stdout);
map<string,vector<int> >::iterator map_it;//索引表迭代器
map_it=indextable.begin();
while(map_it!=indextable.end())//遍历整个索引表输出,因为MAP的键值是严格弱排序,因此输出是字典序
{
string tmp = map_it->first;
cout<<tmp<<" ";
for(int i = 0; i != indextable[tmp].size(); i++)
cout<<indextable[tmp][i]<<" ";
cout<<endl;
map_it++;
}
fclose(stdout);
fflush(stdout);//将输出缓冲区清空
}
void searchphrase(string arr[], int index)
{
freopen("CON", "w", stdout); //定向输出到控制台
/*map<string,vector<int> >::iterator map_it;//索引表迭代器
map_it=indextable.begin();*/
for(int i = 0; i < indextable[arr[0]].size(); i++)
{
for(int j = 0; j != indextable[arr[1]].size(); j++)
{
if(indextable[arr[0]][i] + 1 == indextable[arr[1]][j])
{
a[indextable[arr[0]][i] / M] = 1;
}
}
}
//fclose(stdout);
/*for(int i = 0; i < 100; i++)
{
if(a[i] != 0)
cout<<i<<endl;
}*/
/*for(int i = 0; i < index; i++)
{
for(int j = 0; j != indextable[arr[i]].size(); j++)
a[indextable[arr[i]][j]] = 1;
//cout<<endl;
}*/
}
void searchwords(string arr[])
{
freopen("CON", "w", stdout); //定向输出到控制台
/*for(int j = 0; j != indextable[arr[0]].size(); j++)
a[indextable[arr[0]][j] / 10000] = 1;*/
for(int i = 0; i < words; i++)
{
int remarks[100] = {0};
for(int j = 0; j != indextable[arr[i]].size(); j++)
{
if(remarks[indextable[arr[i]][j] / M] == 0 )
{
a[indextable[arr[i]][j] / M] += 1;
remarks[indextable[arr[i]][j] / M] = 1;
}
}
}
for(int i = 1; i <= filecount; i++)
{
//cout<<a[i]<<endl;
a[i] /= words;
}
/*for(int i = 0; i < words; i++)
{
for(int j = 0; j != indextable[arr[i]].size(); j++)
{
cout<<indextable[arr[i]][j]<<" ";
}
cout<<endl;
}*/
}
void display()
{
//cout<<"jh";
int find = 0;
for(int i = 1; i <= filecount; i++)
{
if(a[i] == 1)
{
cout<<path[i]<<endl;
find++;
}
}
if(find == 0)
cout<<"查询数据不存在";
cout<<endl;
fclose(stdout);
}
int main()
{
string ch;
int i, j; //得到单词个数
cout<<"请选择是\n\t1.输入数个单词(以&隔开)\n\t2.输入词组(以空格隔开)\n\t请选择(1, 2):";
int n;
cin>>n;
int index = 2;
string arr[M];
switch(n)
{
case 1:
cout<<"请输入查询消息(1或多个单词):";
cin>>ch;
j = 0;
for(i = 0; i < ch.length(); i++) //分割
{
if(ch[i] == '&')
{
arr[words++] = ch.substr(j, i - j);
j = i + 1;
}
}
if(i > j)
arr[words++] = ch.substr(j, i - j);
/*for(int i = 0; i < words; i++)
{
cout<<arr[i]<<endl;
}*/
break;
case 2:
cout<<"请输入词组中单词的个数(目前只解决两个单词的词组)\n\t";
//cin>>index;
cout<<"请输入查询消息:";
for(int i = 0; i < index; i++)
{
cin>>arr[i];
}
break;
default:
cout<<"输入失败";
break;
}
/*cin>>ch;
cout<<ch;*/
/*string arr[M];
for(int i = 0; ch[i]!; i++)*/
ReverseIndex();
if(n == 1)
{
searchwords(arr);
}
else
{
searchphrase(arr, index);
}
display();
return 0;
}
仓促所成,还望各位多多指点...
明天回到我大安徽,回家过年...
想必学生党差不多放假了吧,放假愉快...
o(∩_∩)o