2012-01-09 2 views
0

カスタムのElasticSearch実装を使用して、定期的にライブのレガシーデータベースからすべてのドメインインスタンスのインデックスを再作成する必要があります。Grailsのバッチ読み取りの最適化

私が今までに見つけたすべての提案は、すべて最適化バッチ向けでした。の操作を書きました。

多くのテーブルには何百万ものレコードがありますが、domain.list().each { ... }という単純な解決策では、データセット全体を一度にメモリにロードするように見えます。

Hibernateを使用すると、ScrollableResultsは良い解決策のようですが、RecordSetレベルで動作し、実際のドメインオブジェクトを再作成しません。私はidフィールドをread()に使用することができますが、それは非効率的です。

Searchableプラグインは、効率的なreindex操作を実行しているようです。

ドメインインスタンスを一括して読み取るためのその他のオプションや最適化はありますか?


UPDATE

私は最近ScrollableResultSetに対するを使用すると、非効率的だろう示唆@BurtBeckwithからanswerとGrailsのメーリングリスト上の4歳のスレッドに出くわし。標準的なGORMメソッドを使用してレコードをページングし、バッチでセッションをクリアすることをお勧めします。

答えて

1

1)伝統的なJava forループを使用すると、少しオーバーヘッドが軽減されます。

2)データをチャンクすると役立つ可能性があります。 max:とoffset:を使用して、100または1000のチャンクを得ることができます。その場合、常に小さいセットを扱います。http://grails.org/doc/latest/ref/Domain%20Classes/list.html このテーブルのオブジェクトを変更する場合、または新しいデータワークフローの途中で追加されます。 (私はそれをテストするために残しておきます:)

3)すべてのIDを保持するためにSQLまたはHSQLを使用すると、Grails .load()を使用すると役立ちます。 http://grails.org/doc/latest/ref/Domain%20Classes/load.html

4)私は前のGrails /休止状態を使用して、いくつかの大規模なバッチジョブを実装しようとしましたが、それが本当にうまく機能しなかったことを発見しました。可能であれば、SQLを使用してデータベースと直接作業することをお勧めします。それははるかに速くなるでしょう。

+0

私はあなたがすべてのインスタンスIDのScrollableResultsクエリで正しい考えを持っていると思って、それらを個別に読み込んでいます。唯一の問題は、複合主キーを持つ従来のテーブルです。 – jamesallman

+0

DBの実装に応じて、オフセットを使用すると、繰り返し同じデータを選択しているため、膨大なオーバーヘッドが発生する可能性があります。これは単純なクエリではおそらく問題ではありませんが、より複雑なクエリには時間がかかります。 – Joseph

0

あなたがGORMまたは直接SQLか何かでページネータを使用することができます

class Paginator { 
    private static final Logger log = Logger.getLogger("grails.app.Paginator") 

    int batchSize 
    int totalCount 

    public void eachPage(Closure c) { 
     SessionFactory sessionFactory = Holders.applicationContext.sessionFactory 

     if(totalCount > 0) { 
      (0..totalCount -1).step(batchSize) { int offset -> 
       log.debug "Executing batch $offset to ${offset + batchSize}" 
       try { 
        c.call(batchSize, offset) 
        sessionFactory.currentSession.clear() 
       }catch(Exception e) { 
        log.error "Error encountered while executing batch [$offset - ${batchSize + offset}]" 
       } 
      } 
     } 
    } 
} 

そして

Paginator p = new Paginator(batchSize:500, totalCount: Domain.count()) 
p.eachPage {def max, def offset -> 
    List rows = Domain.list(max:max, offset:offset) 
    //do some thing with records 
} 

バッチで手動ロードレコードに以下に似たユーティリティクラスを使用することができます。

関連する問題