そのため、ログ ファイルから約 8,000 万ページ ビューをインポートしようとしています。それらをセッションとしてデータベースに入れようとしています。つまり、20分間隔で区切られたページビューのグループです。
最終的に、私のユーザーデータベースでは、各ユーザーに次のような辞書オブジェクトのリストを持たせたいと思います:
{
'id': 'user1'
'sessions':[
{
"start" : ISODate("2011-04-03T23:21:59.639Z"),
"end" : ISODate("2011-04-03T23:50:05.518Z"),
"page_loads" : 136
},
{
"start" : ISODate("another date"),
"end" : ISODate("later date"),
"page_loads" : 20
},
]
}
かなり単純なはずです。だから私はこのスクリプトを書きました:
howManyLinesTotal = 9999999 #i've done: wc -l in bash before to find the file size
blank_dict = {'page_loads':0, 'start':0, 'end':0}
latest_sessions = defaultdict(lambda: blank_dict)
for line in f: #opens a gigantic gzip file called "f"
line = line.split('\t') #each entry is tab-delimited with: user \t datetime \t page_on_my_site
user = line[1] #grab the data from this line in the file
timestamp = datetime.utcfromtimestamp(float(line[2]))
latest_sessions[user]['page_loads'] += 1 #add one to this user's current session
if latest_sessions[user]['start'] == 0: #put in the start time if there isn't one
latest_sessions[user]['start'] = timestamp
if latest_sessions[user]['end'] == 0: #put in the end time if there isn't one
latest_sessions[user]['end'] = timestamp
else: #otherwise calculate if the new end time is 20 mins later
diff = (timestamp - latest_sessions[user]['end']).seconds
if diff > 1200: #if so, save the session to the database
db.update({'id':user}, {'$push':{'sessions':latest_sessions[user]}})
latest_sessions[user] = blank_dict
else:
latest_sessions[user]['end'] = timestamp #otherwise just replace this endtime
count += 1
if count % 100000 == 0: #output some nice stats every 100,000 lines
print str(count) + '/' + str(howManyLinesTotal)
#now put the remaining last sessions in
for user in latest_sessions:
db.update({'id':user}, {'$push':{'sessions':latest_sessions[user]}})
1行あたり約0.002秒= 8000万ページビューのファイルで44時間です。
これには、2TB 7200rpm seagate HDD、32 GB の RAM、および 3.4Ghz デュアルコア i3 プロセッサが搭載されています。
今回は合理的に聞こえるでしょうか、それとも私は恐ろしい間違いを犯していますか?
編集: 約 90,000 人以上のユーザー、つまり defaultdict のキーを調べています。
EDIT2: これは、はるかに小さい 106 MB ファイルの cProfile 出力です。テスト目的で、実際の mongoDB の保存をコメントアウトしました: http://pastebin.com/4XGtvYWD
EDIT3: これは cProfile の棒グラフ分析です: http://i.imgur.com/K6pu6xx.png