在 Clojure 中使用 data.zip 解析 XML 时出现 OutOfMemoryError

2023-12-31

我想使用 Clojure 从维基词典 XML 转储中提取标题。

I used head -n10000 > out-10000.xml创建原始怪物文件的较小版本。然后我用文本编辑器进行修剪,使其成为有效的 XML。我根据里面的行数重命名了文件(wc -l):

(def data-9764 "data/wiktionary-en-9764.xml") ; 354K
(def data-99224 "data/wiktionary-en-99224.xml") ; 4.1M
(def data-995066 "data/wiktionary-en-995066.xml") ; 34M
(def data-7999931 "data/wiktionary-en-7999931.xml") ; 222M

以下是 XML 结构的概述:

<mediawiki>
  <page>
    <title>dictionary</title>
    <revision>
      <id>20100608</id>
      <parentid>20056528</parentid>
      <timestamp>2013-04-06T01:14:29Z</timestamp>
      <text xml:space="preserve">
        ...
      </text>
    </revision>
  </page>
</mediawiki>

这是我尝试过的,基于这是“Clojure XML 解析”的答案 https://stackoverflow.com/a/9595315/109618:

(ns example.core
  (:use [clojure.data.zip.xml :only (attr text xml->)])
  (:require [clojure.xml :as xml]
            [clojure.zip :as zip]))

(defn titles
  "Extract titles from +filename+"
  [filename]
  (let [xml (xml/parse filename)
        zipped (zip/xml-zip xml)]
    (xml-> zipped :page :title text)))

(count (titles data-9764))
; 38

(count (titles data-99224))
; 779

(count (titles data-995066))
; 5172

(count (titles data-7999931))
; OutOfMemoryError Java heap space  java.util.Arrays.copyOfRange (Arrays.java:3209)

我的代码中做错了什么吗?或者这可能是我正在使用的库中的错误或限制?根据 REPL 实验,我使用的代码似乎很懒。在底层,Clojure 使用 SAX XML 解析器,因此仅此一个应该不是问题。

也可以看看:

  • clojure-xml/parse 是否返回惰性序列? https://stackoverflow.com/questions/11213083/does-clojure-xml-parse-return-a-lazy-sequence
  • Clojure 中的庞大 XML https://stackoverflow.com/questions/9939844/huge-xml-in-clojure

2013年4月30日更新:

我想分享一些来自 clojure IRC 频道的讨论。我在下面粘贴了编辑后的版本。 (我删除了用户名,但如果您想要信用,请告诉我;我将编辑并给您一个链接。)

整个标签一次读入内存xml/parse, 早在你打电话给 count 之前。和clojure.xml使用 ~lazy SAX 解析器生成一个急切的具体集合。延迟处理 XML 需要比你想象的更多的工作——而且这就是工作you做,而不是一些魔法clojure.xml可以为你做的。随意反驳 通过致电(count (xml/parse data-whatever)).

总结一下,即使在使用之前zip/xml-zip, this xml/parse导致OutOfMemoryError有足够大的文件:

(count (xml/parse filename))

目前,我正在探索其他 XML 处理选项。我的列表顶部是clojure.data.xml https://github.com/clojure/data.xml如所提到的https://stackoverflow.com/a/9946054/109618 https://stackoverflow.com/a/9946054/109618.


这是拉链数据结构的限制。 Zipper 旨在高效地导航各种类型的树,支持在树层次结构中上/下/左/右移动,并在近乎恒定的时间内进行就地编辑。

从树中的任何位置,拉链都需要能够重新构建原始树(应用编辑)。为此,它会跟踪树中当前节点、父节点以及当前节点左侧和右侧的所有兄弟节点,大量使用持久数据结构。

您使用的过滤器函数从节点最左边的子节点开始,并逐一向右进行,一路测试谓词。最左边的孩子的拉链从其左侧兄弟姐妹的空向量开始(注意:l []部分来源zip/down https://github.com/clojure/clojure/blob/clojure-1.5.1/src/clj/clojure/zip.clj#L109)。每次向右移动时,它都会将最后访问的节点添加到左手兄弟姐妹的向量中(:l (conj l node) in 拉链/右 https://github.com/clojure/clojure/blob/clojure-1.5.1/src/clj/clojure/zip.clj#L149)。当您到达最右边的子节点时,您已经构建了树中该级别中所有节点的内存向量,对于像您这样的宽树,这可能会导致 OOM 错误。

作为解决方法,如果您知道顶级元素只是列表的容器<page>元素,我建议使用拉链在页面元素内导航,然后使用map处理页面:

(defn titles
  "Extract titles from +filename+"
  [filename]
  (let [xml (xml/parse filename)]
    (map #(xml-> (zip/xml-zip %) :title text)
         (:content xml))))

因此,基本上,我们避免将 zip 抽象用于整个 xml 输入的顶层,从而避免将整个 xml 保存在内存中。这意味着,对于更大的 xml,其中每个第一级子级都很大,我们可能必须在 XML 结构的第二级中再次跳过使用拉链,依此类推......

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Clojure 中使用 data.zip 解析 XML 时出现 OutOfMemoryError 的相关文章

随机推荐

  • 在加载上下文中加载非托管静态 dll

    我有本机非托管 dll 它是静态的 如果我想并行运行它 每次需要库做一些工作时都必须加载它 在 NET 中 我会使用 AppDomain 并在需要时加载此 dll 但在 NET Core 中 AppDomain 已经消失 暂时 我查看了 A
  • 路由关注和多态模型:如何共享控制器和视图?

    给定路线 Example Application routes draw do concern commentable do resources comments end resources articles concerns commen
  • GeoPandas 中的格式/圆形数字图例标签

    我正在寻找一种方法来格式化 舍入这些地图中的数字图例标签 plot GeoPandas 中的函数 例如 gdf plot column pop2010 scheme QUANTILES k 4 这给了我一个有很多小数位的图例 我希望图例标签
  • 将应用程序渲染到主体时,语义 UI 侧边栏会使用 ReactJS 抛出控制台错误

    有什么方法可以在不使用 HTML 正文中的 id 标签的情况下将 Semantic UI 侧边栏渲染到 React 应用程序中 我想避免必须将 React 组件渲染到 HTML 正文中的 tagis 例如不使用 div div 我正在使用
  • 将 Scala 类作为参数传递?

    我希望将一个类作为参数传递给 Scala 函数 如下所示 def sampleFunc c Class List Any 附带问题 参数中的类型应该是 Class 还是 Class 我传递 Class 类型的原因是检查对象是否属于特定类型
  • 如何将 UIImageView 设置为圆角以适应宽高比模式

    我通常使用以下代码来设置圆角 imageView layer cornerRadius 10 当 imageView 设置为 Aspect Fill 时 它会起作用 但是当imageView设置为Aspect Fit模式时 imageVie
  • 在 Node.js 上使用 aes-ecb 加密二进制数据

    我尝试在 Node js 上进行加密 但糟糕的是我无法获得与在线网站相同的结果 我想用二进制密钥加密一些二进制数据 我使用教程节点站点 https nodejs org api crypto html crypto class cipher
  • nginx - 从上游服务器读取自定义标头

    我使用 nginx 作为反向代理 并尝试从上游服务器 Apache 的响应中读取自定义标头 但没有成功 Apache 的响应如下 HTTP 1 0 200 OK Date Fri 14 Sep 2012 20 18 29 GMT Serve
  • ListView 适配器和焦点状态

    我有一些列表视图 这是项目视图的代码
  • Matplotlib 图未使用 ipywidgets 滑块更新

    我有以下代码来生成一个简单的图表 matplotlib notebook from ipywidgets import import numpy as np import matplotlib pyplot as plt x np lins
  • 无法自动选择 Xcode 项目

    当我在正确的目录中输入 pod install 时 我总是得到这个 分析依赖关系 Could not automatically select an Xcode project Specify one in your Podfile lik
  • SQL 计算所有行而不是计算单个行

    我有一个从数据库请求数据的 SQL 语句 SELECT ID To Poster Content Time ifnull Aura 0 as Aura FROM SELECT FROM SELECT DISTINCT FROM messag
  • WCF 票证基础身份验证

    我正在编写使用 wsHttpBinding 绑定的 WCF 服务 该服务不是托管在 IIS 中而是托管在 Windows 服务中 我希望在服务中有一个 Login user pass 方法 如果用户有效 它将向客户端提供一张票证 谁能帮助我
  • Swift 4 Decodable:嵌套数组的结构

    鉴于以下 JSON 文档 我想创建一个struct有四个属性 filmCount Int year Int category 字符串 以及actor 演员阵列 filmCount 5 year 2018 category Other act
  • 将循环缓冲区就地移动/对齐/旋转为零

    我正在使用循环缓冲区将数据推送到列表的任一端 完成后 我想对齐缓冲区 以便列表中的第一个元素位于位置零 并且可以像常规数组一样使用 而无需任何花哨的索引开销 所以我有我的循环list有能力N 它有n从任意索引开始的元素f 移动 旋转所有元素
  • 用鸭子类型语言模拟静态类型的各个方面

    在我目前的工作中 我正在构建一套严重依赖于对象的 Perl 脚本 使用 Perl 的bless 在哈希上尽可能接近 OO 现在 由于缺乏更好的表达方式 我公司的大多数程序员都不是很聪明 更糟糕的是 他们不喜欢阅读文档 并且似乎在理解其他人的
  • 检查 SaveAs 是否成功 VBA

    我需要什么样的语句来检查vba中的SaveAs操作是否成功 Sub saveBookAs wb SaveAs fileName newFile End Sub 您不需要语句来检查工作簿是否已保存 如果Save As进程失败 那么该行将自动出
  • 详细命名空间常用来做什么

    在一些较大的项目或库 例如 Eigen 中 您可以看到诸如internal or detail 我明白什么是internal有好处 但是什么是detail常用于 是否有任何通用约定将代码分发到这样的命名空间中 特别是在具有公共接口的库的情况
  • Flutter Firebase Cloud Messaging onMessage 被触发两次

    我已经实现了 firebase messaging flutter 包建议的基本配置 但是 每次我在 flutter 应用程序上收到通知时 onMessage 都会被触发两次 我正在使用 firebase messaging 6 0 9 D
  • 在 Clojure 中使用 data.zip 解析 XML 时出现 OutOfMemoryError

    我想使用 Clojure 从维基词典 XML 转储中提取标题 I used head n10000 gt out 10000 xml创建原始怪物文件的较小版本 然后我用文本编辑器进行修剪 使其成为有效的 XML 我根据里面的行数重命名了文件