倒排索引序列化需分块处理,因std::map等结构无法直接用operator<<>>读写,应自定义序列化函数实现高效I/O。

用 std::ifstream 和 std::ofstream 读写倒排索引,核心是分块序列化
倒排索引本质是 std::map<:string std::vector>></:string> 这类结构,但直接用 operator 写二进制或文本都不可靠:标准容器内存布局不固定,<code>size_t 在 32/64 位系统下长度不同,且 std::string 内部指针不能直写。
必须自己控制序列化格式。最简方案是「纯文本分块」:每行一个词,后跟文档 ID 列表,用空格分隔。
- 写入时遍历
index_map,对每个term调用out - 读取时用
std::getline拆行,再用std::istringstream分词,首 token 是 term,其余转成size_t - 不推荐用
operator>>直接读整行到std::string后find_first_of(" ")—— 词本身含空格(如 "C++ template")就崩了
词典项排序和重复键合并,得在写入前做归一化
倒排索引要求词典项唯一、有序,否则读取后无法二分查找或合并。C++ 的 std::map 默认有序,但插入时若没去重,同一词多次出现会导致冗余数据甚至崩溃。
- 写入前必须调用
index_map[key].push_back(doc_id),而不是新建 key;用index_map.emplace(key, std::vector<size_t>{doc_id})</size_t>会覆盖已有项 - 如果原始数据已含重复 doc_id(比如同一篇文档多次命中),需手动 dedup:
std::sort + std::unique或用std::set<size_t></size_t>中转再转回vector - 注意大小写:默认
std::map区分大小写,若需忽略,构造时传std::less或自定义比较器,否则 "Apple" 和 "apple" 被当两个词
std::fstream 打开模式选错,会导致写入无声失败或读取乱码
常见错误是用 std::ios::binary 写文本格式,或用 std::ios::app 追加却没清空旧文件,导致索引重复膨胀。
立即学习“C++免费学习笔记(深入)”;
- 写入用
std::ofstream out("index.txt", std::ios::out)即可,默认覆盖;加| std::ios::trunc更明确 - 读取必须用
std::ifstream in("index.txt"),不要加binary—— Windows 下换行符\r\n会被当成两个字符,std::getline可能截断 - 打开后务必检查
if (!in.is_open() || !in.good()),否则后续读取返回空 vector 却不报错,调试时极难定位
内存映射不是必须的,小索引用普通流更稳
有人一上来就想用 mmap 或 boost::iostreams::mapped_file 提速,但对几 MB 以内的索引,反而增加复杂度和崩溃风险。
- 10 万词以内、平均倒排链长 std::ifstream 读取耗时通常
- 真正要上内存映射,前提是:索引 >100MB、查询频繁且只读、运行环境支持 POSIX
mmap或 WindowsCreateFileMapping - 用
mmap后仍要自己解析文本格式 —— 它只是把文件当内存数组暴露,不会自动帮你 split term 和 parse numbers
最易被忽略的是词边界处理:文本格式下必须确保 term 不含空格或换行,否则解析逻辑直接失效;上线前至少用含中文、连字符、点号的词(如 "c++"、"a.b")跑一遍测试。



















