6

統計を行うためにいくつかのPythonスクリプトを使用しています。ログの1つの種類の内容は、次のようになります。私はこれをAログと呼びます。すべてのAログの形式は次のとおりです。

[2012-09-12 12:23:33] SOME_UNIQ_ID filesize

私がそれを呼んでいる別のログBログの形式は次のとおりです。

[2012-09-12 12:24:00] SOME_UNIQ_ID

Aログのレコード数がBログにもあることをカウントし、同じレコードIDを持つ2つのレコードのタイムギャップを取得する必要があります。私の実装では、常にロードし、BログのIDをマップにロードしてから繰り返します。 IDがマップに存在するかどうかを確認するためのAログ。問題は、メモリが多すぎるため、Bログに1億件近くのレコードがあるためです。パフォーマンスとメモリ使用量を改善するための提案はありますか?ありがとう。

4

6 に答える 6

3

「A」がメモリに収まるかどうかに応じてルックアップを逆にして、「B」を順番にスキャンしてみてください。

それ以外の場合は、(timestamp、uniq_id、rest_of_line)を含む2つのテーブル(log_a、log_b)を含むSQLite3データベースにログファイルをロードしてから、でSQL結合を実行しuniq_id、その結果に対して必要な処理を実行します。これにより、メモリオーバーヘッドが低く抑えられ、SQLエンジンが結合を実行できるようになりますが、もちろん、ディスク上のログファイルを効果的に複製する必要があります(ただし、ほとんどのシステムでは通常、これは問題になりません)。

import sqlite3
from datetime import datetime

db = sqlite3.connect(':memory:')

db.execute('create table log_a (timestamp, uniq_id, filesize)')
a = ['[2012-09-12 12:23:33] SOME_UNIQ_ID filesize']
for line in a:
    timestamp, uniq_id, filesize = line.rsplit(' ', 2)
    db.execute('insert into log_a values(?, ?, ?)', (timestamp, uniq_id, filesize))
db.commit()

db.execute('create table log_b (timestamp, uniq_id)')
b = ['[2012-09-12 13:23:33] SOME_UNIQ_ID']
for line in b:
    timestamp, uniq_id = line.rsplit(' ', 1)
    db.execute('insert into log_b values(?, ?)', (timestamp, uniq_id))
db.commit()

TIME_FORMAT = '[%Y-%m-%d %H:%M:%S]'
for matches in db.execute('select * from log_a join log_b using (uniq_id)'):
    log_a_ts = datetime.strptime(matches[0], TIME_FORMAT)
    log_b_ts = datetime.strptime(matches[3], TIME_FORMAT)
    print matches[1], 'has a difference of', abs(log_a_ts - log_b_ts)
    # 'SOME_UNIQ_ID has a difference of 1:00:00'
    # '1:00:00' == datetime.timedelta(0, 3600)

ご了承ください:

  • .connectonsqlite3はファイル名である必要があります
  • aそしてbあなたのファイルでなければなりません
于 2012-09-15T08:40:01.257 に答える
1

これを試して:

  • 両方のファイルを外部で並べ替える
  • Aログファイルを読み取り、SOME_UNIQ_ID(A)を保存します
  • Bログファイルを読み取り、SOME_UNIQ_IDを保存します(B)
  • SOME_UNIQ_ID(B)とSOME_UNIQ_ID(A)を比較します
    • それより少ない場合は、Bログファイルを再度読み取ります
    • 大きい場合は、Aログファイルを再度読み取り、保存されているSOME_UNIQ_IDと比較します(B)
    • 等しい場合は、時間のギャップを見つけます

外部ソーティングが効率的に機能すると仮定すると、プロセスは両方のファイルを1回だけ読み取ることになります。

于 2012-09-15T08:54:37.383 に答える
0

まず、IDの形式は何ですか?グローバルにユニークですか?

これらの3つのオプションのいずれかを選択します。

  • データベースを使用する
  • 2セットのIDの和集合
  • Unixツール

私はあなたが2番目のオプションを好むと思います。AとBからIDだけをロードします。IDが32ビット整数に収まると仮定すると、メモリ使用量は1GB未満になります。次に、同じIDの日時をロードし、ギャップを計算します。要件には、最初のオプションが最適です。

于 2012-09-15T08:43:50.860 に答える
0

一意のIDを(アルファベット順や数値などで)並べ替えることができる場合は、比較をバッチ処理できます。

この例では、IDが1〜10^7の範囲の数値であるとします。次に、最初に最初の10 ^ 6要素をハッシュテーブルに配置し、2番目のファイルを順次スキャンして、一致するレコードを見つけることができます。

pseudopythonでは、これをテストしていません。

for i in xrange(0,9):
    for line in file1:
        time, id = line.split(']')
        id = int(id)
        if i * 10**6 < id < (i+1) * 10**6:
            hash_table[id] = time

    for line in file2:
        time, id = line.split(']') # needs a second split to get the id
        id = int(id)
        if id in hashtable:
            # compare timestamps

IDが数値でない場合は、文字キーを使用してバッチを作成できます。

if id.startswith(a_letter_from_the_alphabet):
    hash_table[id] = time
于 2012-09-15T08:57:44.023 に答える
0

ボトルネックはタイムスタンプの変換であるため、このアクションを、AログとBログが生成される多くの分離マシンに分割します。これらのマシンは文字列スタンプをエポックタイムに変換し、これらすべてのログを使用して計算するCENTERマシン結果は元の方法のほぼ1/20時間かかります。皆さんのおかげで、ここに私の解決策を投稿します。

于 2012-09-16T07:43:13.830 に答える
0

datetimeuniqueidentifier表示された形式の一意のIDの両方をサポートするデータベースを使用することをお勧めします。これはWindowからのものであり、タスクにWindowsを使用する場合は、たとえばMicrosoft SQL 2008 R2 Expressエディション(無料)を使用できます。2つのテーブルはいかなる種類のキーも使用しません。

MS SQLのbcpユーティリティを使用できます。これは、テキストファイル(またはBULK INSERTコマンド)からデータを挿入するための最速の方法の1つです 。

uniqueidentifierのインデックスは、すべてのrecorが挿入された後にのみ作成する必要があります。そうしないと、インデックスが存在するため、挿入操作が遅くなります。次に、内部結合は技術的に可能な限り高速である必要があります。

于 2012-09-16T09:50:06.797 に答える