我有一个大约 36 GB 的 json 文件(来自维基数据),我想更有效地访问它。目前我在 C++ 中使用 rapidjsons SAX 风格的 API——但是解析整个文件在我的机器上花费了大约 7415200 毫秒(=120 分钟)。我想根据 json 对象中的两个主键('name' 或 'entity-key' -> 即 'Stack Overflow' 或 'Q549037')之一访问此文件中的 json 对象。这意味着我必须在最坏的情况下解析当前的整个文件。
所以我想到了两种方法:
- 将大文件拆分为数十亿个小文件 - 文件名指示名称/实体键(即 Q549037.json/Stack_Overflow.json 或 Q549037#Stack_Overflow.json)-> 不确定存储中的过载
- 构建某种从主键到文件中
ftell()
位置的索引。建立索引大约需要 120 分钟(就像现在解析一样),但访问速度应该会更快- 即使用类似两个
std::unorderedmap
的东西(可能再次遇到内存问题) - 索引文件 - 创建两个文件:一个包含按名称排序的条目,另一个按实体键排序(创建这些文件可能需要更长的时间,因为排序)
- 即使用类似两个
解决此类问题的最佳做法是什么? 我应该遵循哪种方法?还有其他想法吗?
最佳答案
我认为性能问题不是由于解析造成的。使用 RapidJSON 的 SAX API 应该已经提供了良好的性能和内存友好。如果您需要访问 JSON 中的每个值,这可能已经是最好的解决方案。
但是,从问题描述来看,一次读取所有值似乎不是您的要求。您想要读取特定标准(例如,通过主键)的一些(可能是少量)值。然后读取/解析所有内容不适合这种情况。
您将需要一些索引机制。用文件位置做这件事是可能的。如果这些位置的数据也是有效的 JSON,您可以查找并将其流式传输到 RapidJSON 以解析该 JSON 值(通过 kParseStopWhenDoneFlag
解析完整的 JSON 后,RapidJSON 可以停止解析)。
其他选项是将 JSON 转换为某种数据库,SQL 数据库、键值数据库或自定义数据库。借助提供的索引工具,您可以快速查询数据。这可能需要很长时间才能转换,但对于以后的检索具有良好的性能。
请注意,JSON 是一种交换格式。它不是为大数据的快速个人查询而设计的。
更新:最近发现有个项目semi-index可能适合您的需求。
关于c++ - 如何有效地解析 C++ 中的大数据 json 文件(wikidata)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28391434/