【问题标题】:parsing/scanning through a 17gb xml file通过 17gb xml 文件解析/扫描
【发布时间】:2013-05-28 17:16:29
【问题描述】:

我正在尝试解析 stackoverflow 转储文件 (Posts.xml- 17gb)。格式为:

<posts>
<row Id="15228715" PostTypeId="1" />
.
<row Id="15228716" PostTypeId="2" ParentId="1600647" LastActivityDate="2013-03-05T16:13:24.897"/>
</posts>

我必须将每个问题与他们的答案“分组”。基本上找到一个问题(posttypeid=1)使用另一行的 parentId 找到它的答案并将其存储在 db 中。

我尝试使用 querypath (DOM) 执行此操作,但它一直在 exiting(139) 。我的猜测是因为文件很大,我的电脑无法处理它,即使交换空间很大。

我考虑过 xmlreader,但是当我使用 xmlreader 看到它时,程序会多次读取文件(查找问题、寻找答案、重复很多次),因此不可行。我错了吗?

还有其他方法/方式吗?

救命!

这是一次解析。

【问题讨论】:

  • 改用SimpleXMLIterator ....
  • @Baba 不是。见lxr.php.net/xref/PHP_TRUNK/ext/simplexml/simplexml.c#2249。它会将整个文件加载到内存中,然后对其进行迭代。
  • XMLReader 将遍历每个节点而不将整个文件加载到内存中,但除非您另有说明,否则它只会这样做一次。
  • 不得不将 16 GB 中的 15 个放入交换空间然后从中读取,这很有趣。这需要几个小时。
  • 我会考虑手动阅读文件,从一个标签到下一个标签。我在这里没有看到任何其他方式不必交换?

标签: php xml xml-parsing


【解决方案1】:

使用 PHP xmlreader 似乎是正确的做法。

原因: 因为你的说法:

我必须将每个问题与他们的答案“分组”。基本上找到一个 question (posttypeid=1) 使用另一行的 parentId 找到答案 并将其存储在数据库中。

据我了解,您喜欢建立一个包含问题和答案的数据库。因此,没有理由在 XML 级别上进行“分组”。将所有相关信息放入数据库并在数据库级别进行分组 - 使用 db 命令(sql ...)。

您必须使用类似“使用目标解析器方法”之类的东西,例如 [使用xml 在 Python 中进行高性能 XML 解析(即使是用于 Python,这也是一个好的开始)。这应该可以通过 XMLReader 实现。

【讨论】:

    【解决方案2】:

    因为您处理这个大文件的方式不是连续的,而是需要直接访问,所以我认为唯一可行的选择是将数据加载到 XML 数据库中。

    【讨论】:

    • 同意。有时我认为人们忽略了最简单的解决方案。
    【解决方案3】:

    我考虑过 xmlreader,但是当我使用 xmlreader 看到它时,程序会多次读取文件(查找问题、寻找答案、重复很多次),因此不可行。我错了吗?

    是的,你错了。使用 XMLReader,您可以指定自己想要遍历文件的频率(您通常会执行一次一次)。对于您的情况,我认为您没有理由甚至不能在每个 &lt;row&gt; 元素上插入这个 1:1。您可以根据属性决定要插入哪个数据库(表?)。

    我通常建议使用一组迭代器,使使用 XMLReader 进行遍历更容易。它被称为 XMLReaderIterator 并允许在 XMLReader 之上 foreach 以便代码通常更易于阅读和编写:

    $reader = new XMLReader();
    $reader->open($xmlFile);
    
    /* @var $users XMLReaderNode[] - iterate over all <post><row> elements */
    $posts = new XMLElementIterator($reader, 'row');
    foreach ($posts as $post)
    {
        $isAnswerInsteadOfQuestion = (bool)$post->getAttribute('ParentId')
    
        $importer = $isAnswerInsteadOfQuestion 
                    ? $importerAnswers 
                    : $importerQuestions;
    
        $importer->importRowNode($post);
    }
    

    如果您担心顺序(例如,您可能担心某些答案父母的答案不可用,而答案是可用的),我会在导入器层内小心,而不是在遍历内。

    取决于这种情况是否经常发生,非常频繁,从不或完全不会使用不同的策略。例如。对于从不,我会直接插入到激活外键约束的数据库表中。如果经常,我会为整个导入创建一个插入事务,其中键约束被解除并在最后重新激活。

    【讨论】:

    • 感谢您的宝贵时间,您是对的,我错了。我成功地使用 xmlreader 解决了我的困境。我注意到的两件事:答案总是在问题之后(显然)并且答案出现在接下来的几千行中(很少有例外是可以的),所以编写了脚本来缓存几千个问题,寻找他们的答案,array_splice阵列的一半并重复!再次感谢
    • "PHP 致命错误:找不到类 'XMLElementIterator'"
    猜你喜欢
    • 1970-01-01
    • 2010-11-26
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-03
    • 1970-01-01
    • 2011-01-09
    相关资源
    最近更新 更多