什麼是倒排索引(反向索引)
以字或者詞爲關鍵字進行索引
正排索引是從文檔到關鍵字的映射,已知文檔求關鍵字。倒排索引是從關鍵字到文檔的映射,已知關鍵字求文檔。
百度搜索爲什麼這麼快?
使用了倒排,當然具體的實現會更加複雜,這裏只是簡單實現倒排索引(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 發佈