从大型xml文件中提取大型xml块的最佳方法

3
我正在使用XPath从XML文件中提取大块内容。我的XML文件很大,它们来自PubMed。我的文件类型示例是:ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/medline17n0001.xml.gz。因此,通过使用XPath表达式,我可以轻松地提取所需的信息。
 Node result = (Node)xPath.evaluate("PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]", doc, XPathConstants.NODE);

我使用 PMIDtoSearch 获取文章,这很完美。但是这需要很长时间。我需要做大约 800,000 次,所以使用这种解决方案需要超过两个月的时间。有些块有超过 400 行,每个 XML 文件有超过 4 百万行。
我也尝试了像 getElementsByTagName 函数这样的解决方案,但它几乎需要同样的时间。
您知道如何改进这个解决方案吗?
谢谢。

我会编写 XQuery 代码来获取 GZIP 文件,解压缩并将其存储到 exist-db 中。然后对该存储的文档编写 XQuery 代码。 - Kevin Brown
您的连接可能会被网络服务限速。 - Thufir
3个回答

4

我将您的文档加载到exist-db中,然后执行了您的查询,基本上是这样的:

xquery version "3.0";
let $medline := '/db/Medline/Data'
let $doc := 'medline17n0001.xml'
let $PMID := request:get-parameter("PMID", "")
let $article := doc(concat($medline,'/',$doc))/PubmedArticleSet/PubmedArticle[MedlineCitation/PMID=$PMID]
return
$article

从远程服务器返回文档需要400毫秒。如果我加强了那台服务器,我会期望这个时间更短,并且它可以处理多个并发请求。或者,如果你把所有东西都放在本地,速度会更快。

你自己试试吧,我把数据留在了一个测试服务器上(记住,这是查询加利福尼亚州的亚马逊微型服务器):

http://54.241.15.166/get-article2.xq?PMID=8

http://54.241.15.166/get-article2.xq?PMID=6

http://54.241.15.166/get-article2.xq?PMID=1

当然,整个文档都在那里。你只需将查询更改为PMID=667或999或其他内容,即可获取目标文档片段。

2
正如@KevinBrown所建议的,数据库可能是正确的答案。但如果这是一次性过程,可能有比您的解决方案更快的解决方案,但不需要学习设置XML数据库的复杂性。
在您正在使用的方法中,有两个主要成本:解析XML文档以在内存中创建树,然后搜索内存中的文档以找到特定的ID值。我猜测解析成本可能比搜索成本高一个数量级。
因此,要实现良好的性能,需要两个要素:
第一,您需要确保每个源文档仅解析一次(而不是每次查询一次)。您没有告诉我们足够的信息,以便我能够告诉您是否已经做到了这一点。
第二,如果您从单个文档检索多个数据块,则希望在不进行每个数据块的串行搜索的情况下完成此操作。实现这一点的最佳方法是使用构建索引以优化查询的查询处理器(例如Saxon-EE)。或者,您可以手动构建索引,例如使用XQuery 3.1映射或使用XSLT中的xsl:key功能。

这是个好观点。那个数据集我熟悉。它大约有21,000 MB的数据。如果只需要处理一次,也许没问题。但话说回来,我可以偷懒,因为我有一个很棒的Amazon服务器镜像,已经加载了exist-db和其他许多组件,我可以在5分钟内启动它。 - Kevin Brown

0
这是执行xpath查询的代码...在我的笔记本电脑上,结果看起来不错...无论pmid值如何,它都只需要大约1秒钟左右。您打算如何提取文本?我可以更新代码以针对此进行定位。
public static void main(String[] args) throws VTDException{
        VTDGen vg = new VTDGen();
        if (!vg.parseFile("d:\\xml\\medline17n0001.xml", false))
            return;
        VTDNav vn = vg.getNav();
        AutoPilot ap = new AutoPilot(vn);
        System.out.println("nesting level"+vn.getNestingLevel());
        String PMIDtoSearch =  "30000";
        ap.selectXPath("/PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]");
        System.out.println("====>"+ap.getExprString());
        int i=0,count=0;
        System.out.println(" token count ====> "+ vn.getTokenCount() );
        while((i=ap.evalXPath())!=-1){
            count++;
            System.out.println("string ====>"+vn.toString(i));
        }
        System.out.println(" count ===> "+count);
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接