【问题标题】:Extremely slow xpath search (ruby/nokogiri)极慢的 xpath 搜索(ruby/nokogiri)
【发布时间】:2013-11-07 23:15:40
【问题描述】:

我正在使用 Nokogiri/Ruby 解析一个非常大的 XML 文档(约 300k 行)。处理每条记录大约需要五分钟,我确定下面代码中的最后一行占用了 99% 的时间。关于如何加快搜索速度的任何建议?这可能是系统内存(或缺乏)的问题吗?

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

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

【问题讨论】:

  • 您的两个 xpath 搜索是多余的,因为它们都搜索整个文档。如果没有示例 XML,就不可能弄清楚您真正想要什么。尝试使用来自根目录的完整路径而不是 // 的单个 XPath。

标签: ruby xpath nokogiri


【解决方案1】:

快速修复

尝试使用来自根目录的完整路径而不是 // 的单个 XPath。

例子:

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>

假设您要按照account_number2 的顺序拉出&lt;item&gt;。代码如下:

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>

【讨论】:

  • 我走了第一条路线,效果很好,谢谢!!感谢您还提供了第二种策略,因为这是我接下来想尝试的。
  • 删除 one 斜线只为我节省了大约 45 秒(换句话说:从 47 秒缩短到 2 秒)。通过 ~4MB XML 查找
【解决方案2】:

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

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

xpathsearch 的 XPath 特定版本,具有用于 CSS 选择器的匹配 css 方法。 search 接受 CSS 和 XPath 选择器,并动态确定要使用的选择器。同样,at 的 CSS 和 XPath 推论分别为 at_cssat_xpath。我倾向于使用searchat,并且仅在我将XPath 误认为是CSS 导致Nokogiri 吓坏时才使用CSS 和XPath 变体。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-22
    相关资源
    最近更新 更多