从大 xml 文件中提取大 xml 块的最佳方法
Best way to extract big xml block from large xml file
我正在使用 XPath 从 XML 文件中提取大块。我的 xml 文件很大,它们来自 PubMed。我的文件类型的一个示例是:
ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/medline17n0001.xml.gz
所以,通过使用
Node result = (Node)xPath.evaluate("PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]", doc, XPathConstants.NODE);
我用 PMIDtoSearch 得到了这篇文章,非常完美。但这需要很多时间。我必须执行大约 800.000 次,因此使用此解决方案需要两个多月的时间。有些块有超过 400 行,每个 xml 文件有超过 400 万行。
我也尝试过这样的解决方案 getElementsByTagName
功能,但它花费的时间几乎相同。
你知道如何改进解决方案吗?
谢谢。
这是执行 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);
}
我把你的文档加载到 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 或其他任何内容,然后取回目标文档片段。
正如@KevinBrown 所建议的,数据库很可能是正确的答案。但如果这是一次性过程,可能有一些解决方案比您的解决方案运行速度快得多,但不需要学习如何设置 XML 数据库的复杂性。
在您使用的方法中,有两个主要成本:解析 XML 文档以在内存中创建树,然后搜索内存中的文档以查找特定的 ID 值。我猜解析成本可能比搜索成本大一个数量级。
因此,要获得良好的性能,有两个要素:
首先,您需要确保每个源文档只解析一次(而不是每个查询一次)。你告诉我们的还不够多,我无法判断你是否已经在这样做了。
其次,如果您要从单个文档中检索许多数据块,您希望在执行此操作时无需对每个数据进行串行搜索。实现这一点的最佳方法是使用构建索引来优化查询的查询处理器(例如 Saxon-EE)。或者,您可以构建索引 "by hand",例如使用 XQuery 3.1 映射,或使用 XSLT 中的 xsl:key 功能。
我正在使用 XPath 从 XML 文件中提取大块。我的 xml 文件很大,它们来自 PubMed。我的文件类型的一个示例是:
ftp://ftp.ncbi.nlm.nih.gov/pubmed/baseline/medline17n0001.xml.gz
所以,通过使用
Node result = (Node)xPath.evaluate("PubmedArticleSet/PubmedArticle[MedlineCitation/PMID = "+PMIDtoSearch+"]", doc, XPathConstants.NODE);
我用 PMIDtoSearch 得到了这篇文章,非常完美。但这需要很多时间。我必须执行大约 800.000 次,因此使用此解决方案需要两个多月的时间。有些块有超过 400 行,每个 xml 文件有超过 400 万行。
我也尝试过这样的解决方案 getElementsByTagName
功能,但它花费的时间几乎相同。
你知道如何改进解决方案吗?
谢谢。
这是执行 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);
}
我把你的文档加载到 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 或其他任何内容,然后取回目标文档片段。
正如@KevinBrown 所建议的,数据库很可能是正确的答案。但如果这是一次性过程,可能有一些解决方案比您的解决方案运行速度快得多,但不需要学习如何设置 XML 数据库的复杂性。
在您使用的方法中,有两个主要成本:解析 XML 文档以在内存中创建树,然后搜索内存中的文档以查找特定的 ID 值。我猜解析成本可能比搜索成本大一个数量级。
因此,要获得良好的性能,有两个要素:
首先,您需要确保每个源文档只解析一次(而不是每个查询一次)。你告诉我们的还不够多,我无法判断你是否已经在这样做了。
其次,如果您要从单个文档中检索许多数据块,您希望在执行此操作时无需对每个数据进行串行搜索。实现这一点的最佳方法是使用构建索引来优化查询的查询处理器(例如 Saxon-EE)。或者,您可以构建索引 "by hand",例如使用 XQuery 3.1 映射,或使用 XSLT 中的 xsl:key 功能。