2

I'm using Nokogiri/Ruby to parse a very large XML document (~300k lines). It's been taking around five minutes to process each record, and I determined that the last line in the code below is taking up 99% of that time. Any suggestions on how to speed up the search? Could it be an issue with system memory (or lack thereof) by any chance?

doc = Nokogiri::XML(File.read(ARGV[0]))
orders = doc.xpath("//order")

order = orders.xpath("//order[account_number=#{sap_account}]")
4

2 回答 2

3

快速修复

尝试使用来自根目录的完整路径而不是//.

例子:

order = doc.at("/full/path/to/order[account_number=#{sap_account}]")

扫描整个//文档,因此在尝试提高性能时首先要摆脱它。

如果您真的想加快速度,请使用 SAX 或 Reader 接口。

真正的速度:阅读器界面

Reader 接口(以及 SAX)会更快,因为它不必将整个文档解析为 DOM;它将简单地一次线性地通过文档一个节点。这让您在牺牲便利性的情况下提高速度(没有查询和回溯)。相反,您必须针对所需条件测试每个节点。

这是一个使用 Reader 接口(比 SAX 简单一点)的示例。假设您有以下文件:

<orders>
  <order account_number="1">
    <item>Foo</item>
  </order>
  <order account_number="2">
    <item>Bar</item>
  </order>
  <order account_number="3">
    <item>Baz</item>
  </order>
</orders>

假设您想按of<item>的顺序拉出。这是代码:account_number2

require 'nokogiri'
filename = ARGV[0]
sap_account = "2"

File.open(filename) do |file|
  Nokogiri::XML::Reader.from_io(file).each do |node|
    if node.name == 'order' and node.attribute('account_number') == sap_account
      puts node.inner_xml
    end
  end
end

输出:

<item>Bar</item>
于 2013-11-08T01:52:43.453 回答
1

虽然将一个或多个节点的搜索分解为多个步骤通常很有用,但看起来您真的可以一次性完成:

doc = Nokogiri::XML(File.read(ARGV[0]))
order = doc.xpath("//order[account_number=#{sap_account}]")

如果该节点只能出现一次,请使用:

order = doc.at("//order[account_number=#{sap_account}]")

不同之处在于xpath返回一个NodeSet,它是一个节点的集合。NodeSet 支持许多相同的方法,但它们可能会导致细微的差异,因为它们被应用于类似数组的结构而不是单个节点。at返回第一个匹配节点,因此您对返回的节点所做的任何进一步处理将仅适用于该节点,而不适用于其他节点。

xpath是 的 XPath 特定版本search,具有 CSS 选择器的匹配css方法。search接受 CSS 和 XPath 选择器并确定使用哪个。类似地,分别具有和at的 CSS 和 XPath 推论。当我将 XPath 误认为是 CSS 导致 Nokogiri 抓狂时,我倾向于使用并且仅使用 CSS 和 XPath 变体。at_cssat_xpathsearchat

Nokogiri 搜索和查找应该非常快//order[account_number=#{sap_account}],即使在 300K 行中,如果它有足够的内存可以玩。

如果没有,请认真考虑将 XML 导入数据库并在那里进行搜索。XML 并不是真的要用作数据存储,因此对 XML 文件的处理可能会逆流而上,让您的生活更加艰难。使用索引字段创建模式并将其导入数据库,可以大大加快您的处理速度。

于 2013-11-08T02:41:42.957 回答