0

約 200,000 のエンティティのリストがあり、それらのエンティティごとに特定の RESTful API を照会する必要があり、200,000 のエンティティすべてが JSON 形式で txt ファイルに保存されます。これを行う簡単な方法は、200,000 個のエンティティのリストを調べて 1 つずつクエリを実行し、返された JSON をリストに追加し、それが完了したらすべてをテキスト ファイルに追加することです。何かのようなもの:

from apiWrapper import api
from entities import listEntities #list of the 200,000 entities
a=api()
fullEntityList=[]
for entity in listEntities:
fullEntityList.append(a.getFullEntity(entity))

with open("fullEntities.txt","w") as f:
    simplejson.dump(fullEntityList,f)

API への 200,000 件のクエリには約 10 時間ほどかかるため、明らかにこれは信頼できません。そのため、ファイルに書き込む前に何かエラーが発生すると思います。チャンクで書くのが正しい方法だと思いますが、実装方法がわかりません。何か案は?また、データベースでこれを行うことはできません。

4

3 に答える 3

2

それらを SQLite データベースに書き込むことをお勧めします。これは、私自身の小さな Web スパイダー アプリケーションで行う方法です。キーを非常に簡単にクエリして、既に取得したキーを確認できるためです。このようにして、アプリケーションは中断したところから簡単に続行できます。特に、来週追加される新しいエントリが 1000 件ほどある場合は特にそうです。

最初からアプリケーションに「リカバリ」を設計してください。予期しない例外 (たとえば、ネットワークの輻輳によるタイムアウト) が発生した場合、最初から再起動する必要はなく、まだ正常に取得できていないクエリのみを再起動する必要があります。200.000 クエリで、99.9% のアップタイムは、200 回の失敗を予期する必要があることを意味します!

スペースの効率とパフォーマンスのために、データベース blob にダンプする前に json を zlib で圧縮するなど、圧縮形式を使用することで成果が得られる可能性があります。

スパイダーが複数のホストで同時に実行されない限り、SQLite は適切な選択です。単一のアプリケーションの場合、sqlite は最適です。

于 2013-01-14T07:00:56.067 に答える
1

簡単な方法は、ファイルを'a'(追加) モードで開き、ファイルが入ってくるたびに 1 つずつ書き込むことです。

より良い方法は、ジョブ キューを使用することです。これにより、a.getFullEntityワーカー スレッドへの呼び出しを生成し、結果が戻ってきたときに必要な方法で処理したり、失敗した場合の再試行をスケジュールしたりできます。 を参照してくださいQueue

于 2013-01-14T05:22:29.680 に答える
0

また、ファイルの書き込みを行う別のスレッドを使用Queueし、すべてのエンティティの記録を保持するために使用します。始めたときは5分でできると思っていたのですが、少し大変でした。simplejson そして私が知っている他のすべてのそのようなライブラリは部分的な書き込みをサポートしていない[ので、最初にリストの1つの要素を書き込んだり,、後で別の要素を追加したりすることはできません]。次に、各エンティティを個別にダンプします。

(私はあなたのAPIを持っていないので)それをチェックすることができずに、あなたは試すことができます:

import threading
import Queue
import simplejson
from apiWrapper import api
from entities import listEntities #list of the 200,000 entities

CHUNK_SIZE = 1000

class EntityWriter(threading.Thread):
    lines_written = False
    _filename = "fullEntities.txt"

    def __init__(self, queue):
        super(EntityWriter, self).__init()
        self._q = queue
        self.running = False

    def run(self):
        self.running = True
        with open(self._filename,"a") as f:
            while True:
                try:
                    entity = self._q.get(block=False)
                    if not EntityWriter.lines_written:
                        EntityWriter.lines_written = True
                        f.write("[")
                        simplejson.dump(entity,f)
                    else:
                        f.write(",\n")
                        simplejson.dump(entity,f)
                except Queue.Empty:
                    break
        self.running = False

    def finish_file(self):
         with open(self._filename,"a") as f:
             f.write("]")


a=api()
fullEntityQueue=Queue.Queue(2*CHUNK_SIZE)
n_entities = len(listEntities)
writer = None
for i, entity in listEntities:
    fullEntityQueue.append(a.getFullEntity(entity))
    if (i+1) % CHUNK_SIZE == 0 or i == n_entities-1:
        if writer is None or not writer.running:
            writer = EntityWriter(fullEntityQueue)
            writer.start()
writer.join()
writer.finish_file()

このスクリプトの機能

メインループは引き続きエンティティのリストを繰り返し処理し、それぞれの完全な情報を取得します。その後、各エンティティはキューに入れられます。1000エンティティごとに(そしてリストの最後に)、メインスレッドと並行して実行されるEntityWriter-Threadが起動されます。このEntityWritergetはからQueue、目的の出力ファイルにダンプします。

上記のように、JSONをリストにするために、いくつかの追加のロジックが[必要,です]。結果のファイルは、原則として、simplejsonリロードするときに理解されるはずです。

于 2013-01-14T08:27:33.413 に答える