我想使用 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.