我想使用 Clojure 从维基词典 XML 转储中提取标题。
我曾经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 Parsing”的回答:
(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 解析器,因此仅此一项不应该是问题。
也可以看看:
2013 年 4 月 30 日更新:
我想分享一些来自 clojure IRC 频道的讨论。我在下面粘贴了一个经过编辑的版本。(我删除了用户名,但如果你想要信用,请告诉我;我会编辑并给你一个链接。)
xml/parse
整个标签在你调用 count 之前就被一次性读入内存。并clojure.xml
使用 ~lazy SAX 解析器生成急切的具体集合。懒惰地处理 XML 需要的工作比你想象的要多得多——这将是你 做的工作,而不是什么魔法clojure.xml
可以为你做的。随意打电话反驳(count (xml/parse data-whatever))
。
总而言之,即使在使用之前zip/xml-zip
,这也会xml/parse
导致OutOfMemoryError
文件足够大:
(count (xml/parse filename))
目前,我正在探索其他 XML 处理选项。在我的列表顶部是https://stackoverflow.com/a/9946054/109618中提到的clojure.data.xml。