1

さまざまなストアの製品情報を含む大きな (32 Mb) XML ファイルがたくさんあります。Heroku でホストされている Rails を使用しています。

これらの XML フィードを解析し、これらの製品をデータベースに書き込みたいと考えています。私は半作業ソリューションを持っていますが、非常に遅く、メモリを大量に消費します。

私はこれまで多かれ少なかれこれを使用してきました:

open_uri_fetched = open(xml_from_url)
xml_list = Nokogiri::HTML(open_uri_fetched)
xml_list.xpath("//product").each do |product|
// parsed nodes
// Model.create()
end

これはある程度機能しています。ただし、これにより Heroku でメモリの問題が発生し、スクリプトがクラッシュします。また、非常に遅いです (200 以上のフィードでこれを行います)。

Heroku は、私が今やろうとしている Nokogiri::XML::Reader を使用して問題を解決するように私に言いました。

私も使用して調べました:

ActiveRecord::Base.transaction do
Model.create()
end

Model.create() プロセスを高速化します。

1. 私の最初の質問: これは私の問題を解決するための正しい方法 (または少なくともまともな方法) ですか?

今、これは私がやろうとしていることです:

  reader = Nokogiri::XML::Reader(File.open('this_feed.xml'))
  reader.each do |node|
    if node.node_type == Nokogiri::XML::Reader::TYPE_ELEMENT
      if node.name.downcase == xname
        puts "Name: " + node.inner_xml
        use_name = node.inner_xml
      end
    end
  end

質問 2: しかし、モデルの作成コードはどこに置くのですか?

ActiveRecord::Base.transaction do
  Model.create(:name => use_name)
end

ループに入れると、ノードごとに作成しようとしますが、これは間違っています。xml-list 内の各製品の後に呼び出されるようにしたいですよね?

XML の読み取り中に構築されるハッシュを作成すると (そしてモデル作成の作成に使用されます)、最初に XML ファイルを開くのと同じくらいメモリを集中的に使用しませんか?

XML ファイルは、要するに次のようになります。

<?xml version="1.0" encoding="UTF-8" ?>
<products>
    <product>
        <name>This cool product</name>
        <categories>
            <category>Food</category>
            <category>Drinks</category>
        </categories>
        <SKU />
        <EAN />
        <description>A long description...</description>
        <model />
        <brand />
        <gender />
        <price>126.00</price>
        <regularPrice>126.00</regularPrice>
        <shippingPrice />
        <currency>SEK</currency>
        <productUrl>http://www.domain.com/1.html</productUrl>
        <graphicUrl>http://www.domain.com/1.jpg</graphicUrl>
        <inStock />
        <inStockQty />
        <deliveryTime />
    </product>
</products>
4

1 に答える 1

3

Reader はドキュメントを 1 回スキャンするだけです。状態を自分で追跡する必要があります: どの要素を見たか、気になる要素の中にいるかどうかなどです。

この要点は、Reader 構文を大幅に改善するあまり知られていない美しさです。非常に読みやすい方法で、状態を追跡します。

コメントから抜粋した使用方法の例を次に示します。

Xml::Parser.new(Nokogiri::XML::Reader(open(file))) do
  inside_element 'User' do
    for_element 'Name' do puts "Username: #{inner_xml}" end
    for_element 'Email' do puts "Email: #{inner_xml}" end

    for_element 'Address' do
      puts 'Start of address:'
      inside_element do
        for_element 'Street' do puts "Street: #{inner_xml}" end
        for_element 'Zipcode' do puts "Zipcode: #{inner_xml}" end
        for_element 'City' do puts "City: #{inner_xml}" end
      end
      puts 'End of address'
    end
  end
end

誰かが本当にこの小さな宝石から宝石を作るべきです。

あなたの場合、inside_element 'product'ブロックを作成し、必要な要素を抽出して、製品ブロックの最後にモデル インスタンスを作成できます。

于 2012-09-19T13:09:31.567 に答える