C++ 在C+中存储、加载和使用反向索引的最佳方法+;(约500个月)
我正在开发一个使用TF-IDF和余弦相似性的小型搜索引擎。当添加页面时,我会建立一个反向索引,以保持不同页面中的单词频率。我删除了停止词和更常见的词,复数/动词/等词干 我的倒排索引如下所示:C++ 在C+中存储、加载和使用反向索引的最佳方法+;(约500个月),c++,performance,data-structures,inverted-index,C++,Performance,Data Structures,Inverted Index,我正在开发一个使用TF-IDF和余弦相似性的小型搜索引擎。当添加页面时,我会建立一个反向索引,以保持不同页面中的单词频率。我删除了停止词和更常见的词,复数/动词/等词干 我的倒排索引如下所示: map< string, map<int, float> > index [ word_a => [ id_doc=>frequency, id_doc2=>frequency2, ... ], word_b => [ id_doc->
map< string, map<int, float> > index
[
word_a => [ id_doc=>frequency, id_doc2=>frequency2, ... ],
word_b => [ id_doc->frequency, id_doc2=>frequency2, ... ],
...
]
然后我在搜索时加载它:
ifstream ifs_index("index.sr", ios::binary);
boost::archive::bynary_iarchive ia(ifs_index);
ia >> index;
但是它的速度非常慢,加载需要10秒的时间
map
对于反向索引是否足够有效提前感谢您的帮助 答案在很大程度上取决于您是否需要支持与机器RAM相当或更大的数据,以及在您的典型用例中,您是否可能访问所有索引数据,或者只访问其中的一小部分 如果您确信您的数据将适合您的机器的内存,您可以尝试优化您现在使用的基于地图的结构。将数据存储在地图中应该可以提供相当快的访问速度,但是当您将数据从磁盘加载到内存中时,总会有一些初始开销。此外,如果只使用索引的一小部分,这种方法可能会非常浪费,因为您总是读取和写入整个索引,并将其全部保存在内存中 下面我列出了一些您可以尝试的建议,但是在您花太多时间去做这些建议之前,请确保您确实衡量了哪些改进了负载和运行时间,哪些没有。如果不在您使用的实际数据上分析实际工作代码,这些只是猜测,可能是完全错误的
实现为一棵树(通常为黑红树)。在许多情况下,map
可能会为您提供更好的性能和更好的内存使用(例如,更少的分配和更少的碎片)hash_映射
- 尝试减小数据的大小—更少的数据意味着从磁盘读取数据会更快,可能会减少内存分配,有时由于更好的局部性,内存性能会更好。例如,您可以考虑使用<代码>浮点来存储频率,但也许您只能将发生次数作为“代码”>未签名的短存储在MAP值中,并且在单独的映射存储中存储每个文档的所有单词的数量(也都是一个简短的)。使用这两个数字,您可以重新计算频率,但在将数据保存到磁盘时使用更少的磁盘空间,这可能导致更快的加载时间
- 您的映射有很多条目,在这种情况下,有时使用自定义内存分配器有助于提高性能
如果您的数据可能会超出计算机RAM的大小,我建议您使用内存映射文件来存储数据。这种方法可能需要重新建模您的数据结构,或者使用自定义STL分配器,或者使用完全自定义的数据结构,而不是
std::map
,但如果做得好,可能会提高性能一个数量级。特别是,这种方法使您不必一次将整个结构加载到内存中,因此您的启动时间将显著提高,但代价是,当您第一次接触结构的不同部分时,会出现与磁盘访问相关的轻微延迟。主题相当广泛,需要对代码进行更深入的更改,而不仅仅是调整地图,但是如果您计划处理大量数据,您当然应该看看mmap
和朋友。谢谢您的回答,我设法用无符号short int
而不是频率的float来大幅减小索引的大小。
ifstream ifs_index("index.sr", ios::binary);
boost::archive::bynary_iarchive ia(ifs_index);
ia >> index;