什么是倒排索引(反向索引)
以字或者词为关键字进行索引
正排索引是从文档到关键字的映射,已知文档求关键字。倒排索引是从关键字到文档的映射,已知关键字求文档。
百度搜索为什么这么快?
使用了倒排,当然具体的实现会更加复杂,这里只是简单实现倒排索引(inverted index)。
具体主要做了,把多个文档中的单词切出来(为了简单起见直接空格分开单词),然后建立如上图所示的数据结构,每个单词后面挂上一串文档。
这样用户输入一个单词,我们就能找到这个有哪些文档中出现过这个单词(为了简单起见,没有存单词在文档中具体的位置)
如何查找用户输入的单词,即单词库用什么存储,这里用了字典树。
实现
#include <algorithm>
#include <fstream>
#include <iostream>
#include <vector>
#include <string>
const std::string _CHARS = "abcdefghijklmnopqrstuvwxyz0123456789.:-_/";
const size_t MAX_NODES = 41;
class node
{
public:
node() { clear(); }
node(char z) { clear(); }
~node()
{
for (int x = 0; x < MAX_NODES; x++)
{
if (next[x])
delete next[x];
}
}
void clear()
{
for (int x = 0; x < MAX_NODES; x++)
{
next[x] = 0;
isWord = false;
}
}
bool isWord; // 是否是一个单词
std::vector<std::string> files; // 文件列表
node *next[MAX_NODES]; // 字典树
};
class Index
{
public:
void add(std::string s, std::string fileName)
{
std::transform(s.begin(), s.end(), s.begin(), tolower);
std::string h;
for (std::string::iterator i = s.begin(); i != s.end(); i++)
{
if (*i == 32)
{ // 空格的ascii
pushFileName(addWord(h), fileName);
h.clear();
}
h.append(1, *i);
}
if (h.length())
{
pushFileName(addWord(h), fileName);
}
}
void findWord(std::string s)
{
std::vector<std::string> v = find(s);
if (!v.size())
{
std::cout << s + " was not found!\n";
return;
}
std::cout << s << " found in:\n";
for (std::vector<std::string>::iterator i = v.begin(); i != v.end(); i++)
{
std::cout << *i << "\n";
}
std::cout << "\n";
}
private:
node root;
/*
对输入的字符串s,遍历root下的字典树,并将该单词最后一个字符的位置设置isWord。
返回最后一个字符的指针。
*/
node *addWord(std::string s)
{
size_t idx;
node *rt = &root, *n;
for (std::string::iterator i = s.begin(); i != s.end(); i++)
{
idx = _CHARS.find(*i);
if (idx < MAX_NODES)
{
n = rt->next[idx];
if (n)
{
rt = n;
continue;
}
n = new node(*i);
rt->next[idx] = n;
rt = n;
}
}
rt->isWord = true;
return rt;
}
/*
在单词的字典树末尾节点下插入文档的名字。
*/
void pushFileName(node *n, std::string fn)
{
std::vector<std::string>::iterator i = std::find(n->files.begin(), n->files.end(), fn);
if (i == n->files.end())
n->files.push_back(fn);
}
const std::vector<std::string> &find(std::string s)
{
size_t idx;
std::transform(s.begin(), s.end(), s.begin(), tolower);
node *rt = &root;
for (std::string::iterator i = s.begin(); i != s.end(); i++)
{
idx = _CHARS.find(*i);
if (idx < MAX_NODES)
{
if (!rt->next[idx])
return std::vector<std::string>();
rt = rt->next[idx];
}
}
if (rt->isWord)
return rt->files;
return std::vector<std::string>();
}
};
int main(int argc, char *argv[])
{
Index t;
std::string s;
std::string files[] = {"file1.txt", "f_text.txt", "text_1b.txt"};
for (int x = 0; x < 3; x++)
{
std::ifstream f;
f.open(files[x].c_str(), std::ios::in);
if (f.good())
{
while (!f.eof())
{
f >> s;
t.add(s, files[x]);
s.clear();
}
f.close();
}
}
while (true)
{
std::cout << "Enter one word to search for ,return to exit; ";
std::getline(std::cin, s);
if (!s.length())
break;
t.findWord(s);
}
return 0;
}
参考链接
本文由博客群发一文多发等运营工具平台 OpenWrite 发布