2017-02-25 4 views
2

ich einen Python-Skript geschrieben Apache-Logs zu analysieren und speichern sie in mongodb in folgendem Format:Wie ein Dokument vorhandenes Dokument in mongodb anhängen

{ 
    "_id": ObjectId("589e77cf74eea90879f49c80"), 
    "http_version": "HTTP/1.1", 
    "time": ISODate("2017-02-11T02:32:46Z"), 
    "server_ip": "x.x.x.x", 
    "method": "GET", 
    "content_length": 529, 
    "referral": "-", 
    "uri": "/xxxxxxx.sdsd", 
    "agent": "Mozilla/5.00 (Nikto/2.1.5) (Evasions:None) (Test:map_codes)", 
    "status_code": 404 
} 

Ich brauche die Zählung von 404, 200 zu finden und 302 Anfragen pro IP-Adresse. Ich habe ein weiteres Skript geschrieben, um die Werte zu holen und in einem Wörterbuch zu speichern. Das Skript dauert jedoch 2 Minuten, um die Ergebnisse abzurufen.

Muss ich meine Python-Codelogik ändern oder Soll ich die Art ändern, wie ich die Daten in MongoDB speichere?

Jede Hilfe wird sehr geschätzt.

Antwort

1

Sie können aggregation verwenden, um die Gruppe status_code zu gruppieren und dann ein Array mit der Zählung für jede Gruppe status_code/server_ip abzurufen. In mongoDB Shell es wäre:

db.http_bank.aggregate([{ 
    $group: { 
     "_id": { 
      "status_code": "$status_code", 
      "server_ip": "$server_ip" 
     }, 
     "count": { "$sum": 1 } 
    } 
}, { 
    $match: { 
     "_id.status_code": { "$in": [200, 302, 404] } 
    } 
}]) 

die gibt:

{ "_id" : { "status_code" : 404, "server_ip" : "1.1.1.1" }, "count" : 2 } 
{ "_id" : { "status_code" : 302, "server_ip" : "3.3.3.3" }, "count" : 2 } 
{ "_id" : { "status_code" : 200, "server_ip" : "1.1.1.1" }, "count" : 1 } 
{ "_id" : { "status_code" : 302, "server_ip" : "2.2.2.2" }, "count" : 1 } 

In Python können Sie wie this tun:

from pymongo import MongoClient 
import datetime 

db = MongoClient().testDB 

pipeline = [ 
    { 
     "$match": 
     { 
      "time": 
      { 
       "$gte": datetime.datetime(2015, 1, 1, 00, 00, 00), 
       "$lte": datetime.datetime(2018, 1, 1, 00, 00, 00) 
      } 
     } 
    }, 
    { 
     "$group": { 
      "_id": { 
       "status_code": "$status_code", 
       "server_ip": "$server_ip" 
      }, 
      "count": { 
       "$sum": 1 
      } 
     } 
    }, 
    { 
     "$match": { 
      "_id.status_code": { 
       "$in" : [200,302,404] 
      } 
     } 
    } 
] 

res = list(db.http_bank.aggregate(pipeline)) 

dict_status_code={} 
dict_status_code[1]={} 

for i, val in enumerate(res): 

    data = { 
     str(int(val["_id"]["status_code"])) : val["count"] 
    } 
    key = val["_id"]["server_ip"] 
    print key, " ==> ", data 

geben:

1.1.1.1 ==> {'404': 2} 
3.3.3.3 ==> {'302': 2} 
1.1.1.1 ==> {'200': 1} 
2.2.2.2 ==> {'302': 1} 
+0

Das funktionierte wie ein Zauber. Es war 3 Minuten vorher. Jetzt dauert es 50 Sekunden, um alle Daten zu holen. – vijay

+1

50 Sekunden ist immer noch sehr langsam für so eine grundlegende Abfrage stellen Sie sicher, meine Antwort zu überprüfen. – leonziyo

+0

Ich habe 400K Dokumente in einer einzigen Sammlung. – vijay

0

Haben Sie habe einen Index auf deiner Sammlung? Wenn nicht, dann ist das der Grund, warum es langsam läuft. Sie können eine in der Shell wie folgt erstellen:

db.http_bank.createIndex({ server_ip: 1, status_code: 1 }) 

Dies kann eine Weile dauern, abhängig von der Größe Ihrer Sammlung.

Übrigens sollten Sie das Aggregationsframework wie die andere Antwort vorschlagen, aber Sie werden den Index in beide Richtungen benötigen, also erstellen Sie das zuerst.

Verwandte Themen