我想知道基于不同字段搜索大型数据集的最佳方法是什么。 例如,Person对象定义如下:
Person:
first name
last name
phone numbers
我有100k Person类型的对象,我想根据任何一个字段搜索特定的人?
我尝试使用不同的字段对数据集进行排序,以便我可以在O(logn)时间内执行搜索操作,但我知道这不是正确的方法。
答案 0 :(得分:1)
您可以尝试Boost.MultiIndex
:
Boost Multi-index Containers Library提供了一个名为multi_index_container的类模板,它可以构建容器,维护一个或多个具有不同排序和访问语义的标记:
但是如果你想尝试自己 - 那么最简单的解决方案就是:为所有数据使用一个容器,另外还要保留几个带有适当索引的地图:
class Indixer
{
vector<Record> values; // without specific order
unordered_map<field_type1, Record*> index1; // Search: O(1) average
unordered_map<field_type2, Record*> index2; // Search: O(1) average
map<field_type3, Record*> index3; // Search: O(log N) worst case
public:
// ...
};
您可以使用std::unordered_map
获得O(1)平均访问权限。这是一个例子:
#include <initializer_list>
#include <unordered_map>
#include <functional>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <utility>
#include <vector>
#include <string>
using namespace std;
struct Record
{
string first_name, last_name;
};
class Indexer
{
typedef vector<Record> Container;
typedef Record *Handle;
Container values;
unordered_map<string, Handle> first_name_index, last_name_index;
public:
Indexer(Container &&x) : values(move(x))
{
for(auto &x : values)
{
first_name_index[x.first_name] = &x;
last_name_index[x.last_name] = &x;
}
}
const Record &first_name(const string &x)
{
return *first_name_index[x];
}
const Record &last_name(const string &x)
{
return *last_name_index[x];
}
};
int main()
{
vector<Record> v = {{"F1", "L1"}, {"F2", "L2"}};
Indexer x(move(v));
cout << x.first_name("F1").last_name << endl;
cout << x.first_name("F2").last_name << endl;
cout << x.last_name("L1").first_name << endl;
cout << x.last_name("L2").first_name << endl;
}
输出是:
L1
L2
F1
F2
答案 1 :(得分:1)
对此没有一个答案,因为正确的答案(严重)取决于您对速度与额外存储的关注程度。
如果您想要绝对最大速度,并且根本不关心使用额外存储,是的,您可以创建三个数据副本,一个按每个字段排序,输入搜索时,只需使用适当的一。这可能不会像它可能首先出现的那样糟糕。假设您的字符串平均每个大约10个字节,因此结构的总大小约为30个字节。其中100'000个每个副本大约3兆字节,总计大约9兆字节。有一段时间本来是显而易见的 - 但是现在一台典型的机器至少有8个千兆字节的RAM,它并不是那么可怕。
假设你排除了这一点,下一个最明显的可能性是在原始数据中构建索引 - 将原始数据放入一个数组,然后为每个字段构建一个索引,其中索引中的每个条目都包含数据对于一个字段,以及主数据的指针/下标。每个索引条目可以是~14个字节,因此每个索引大约是整个数据的一半大小。只有三个字段,你不会节省很多,但你确实节省了一些 - 而且极其的复杂性成本最低。通过更多字段,您可以节省更多。
另一种可能性是将索引实现为哈希表。这里的主要优点是您可以避免重复存储日期。例如,如果计算每个桶有2个条目的16位散列,则可以在~512K字节中存储一个索引。如果存储桶已满,但两个条目都不匹配您的输入,则重新哈希并尝试另一个存储桶。继续前进,直到找到你的物品或找到一个空桶。