2008-09-18 10 views
6

Arbeiten an einem Projekt, das ein Protokoll der Ereignisse analysiert und dann ein Modell basierend auf den Eigenschaften dieser Ereignisse aktualisiert. Ich war ziemlich faul dabei, es "fertig zu machen" und mich mehr um die Voraboptimierung, den schlanken Code und die richtigen Entwurfsmuster zu kümmern. Meist ein selbstlernendes Experiment. Ich bin daran interessiert, welche Muster erfahrenere Designer für relevant halten oder welche Art von pseudo-codierter Objektarchitektur die beste, am leichtesten zu wartende und so weiter wäre.Entsprechendes Entwurfsmuster für einen Ereignisprotokollparser?

In einem einzelnen Protokoll können 500.000 Ereignisse auftreten. Es gibt ungefähr 60 Ereignistypen, die jeweils ungefähr 7 Basiseigenschaften gemeinsam haben und je nach Ereignistyp 0 bis 15 zusätzliche Eigenschaften haben. Der Ereignistyp ist die zweite Eigenschaft in der Protokolldatei in jeder Zeile.

Also habe ich einen wirklich hässlichen imperativen Parser versucht, der Zeile für Zeile durch das Protokoll läuft und dann Ereignisse Zeile für Zeile verarbeitet. Dann versuchte ich eine lexikalische Spezifikation, die ein "nextEvent" -Muster verwendet, das in einer Schleife aufgerufen und verarbeitet wird. Dann habe ich eine einfache alte "Parse" -Methode ausprobiert, die niemals zurückkehrt und nur Ereignisse zu registrierten Listener-Callbacks auslöst. Ich habe sowohl einen einzelnen Rückruf, unabhängig vom Ereignistyp, als auch eine für jeden Ereignistyp spezifische Rückrufmethode ausprobiert.

Ich habe versucht, eine Basis "Ereignis" -Klasse mit einer Union aller möglichen Eigenschaften. Ich habe versucht, den "neuen Ereignis" -Aufruf zu vermeiden (da es eine große Anzahl von Ereignissen geben kann und die Ereignisobjekte im Allgemeinen kurzlebig sind) und die Rückmeldemethoden pro Typ mit primitiven Eigenschaftsargumenten zu haben. Ich habe versucht, eine Unterklasse für jeden der 60 Ereignistypen mit einem abstrakten Event-Elternteil mit den 7 gemeinsamen Basiseigenschaften zu haben.

Ich habe vor kurzem versucht, das weiter zu nehmen und ein Befehlsmuster zu verwenden, um Ereignisbehandlungscode pro Ereignistyp zu setzen. Ich bin mir nicht sicher, ob ich das mag und es ist sehr ähnlich zu den Callbacks pro Typ Ansatz, nur Code ist innerhalb einer Ausführungsfunktion in den Typ-Unterklassen gegenüber den Callback-Methoden pro Typ.

Das Problem ist, dass viele der Modell-Update-Logik geteilt wird, und viel davon ist spezifisch für die Unterklasse, und ich bin gerade erst verwirrt über die ganze Sache. Ich hoffe, dass jemand mich wenigstens in eine Richtung weisen kann!

Antwort

3

Nun ... für eine Sache eher als eine einzelne Ereignisklasse mit einer Vereinigung aller Eigenschaften oder 61 Ereignisklassen (1 Basis, 60 Subs), in einem Szenario mit so viel Variation würde ich versucht werden eine einzelne Ereignisklasse zu haben, die eine Eigenschaftstasche verwendet (Wörterbuch, Hashtabelle, w/e treibt Ihr Boot), um Ereignisinformationen zu speichern. Der Typ des Ereignisses ist nur ein weiterer Eigenschaftswert, der in die Tasche gelegt wird. Der Hauptgrund, warum ich mich so lehne, ist nur, weil ich es verabscheuen würde, 60 abgeleitete Klassen von irgendetwas aufrechtzuerhalten.

Die große Frage ist ... was haben Sie zu tun mit den Ereignissen, wie Sie sie verarbeiten. Formatieren Sie sie in einem Bericht, organisieren Sie sie in einer Datenbanktabelle, wecken Sie Leute, wenn bestimmte Ereignisse auftreten ... was?

Ist dies ein After-the-fact-Parser oder ein Echtzeit-Event-Handler?Ich meine, überwachen Sie das Protokoll, wenn Ereignisse eintreffen, oder analysieren Sie Protokolldateien am nächsten Tag?

+0

Nun, ich bin mir ziemlich sicher, dass ich bei den Grundeigenschaften als Ereigniseigenschaften bleiben möchte, da sie bekannt und konstant sind und mir die Leistung sehr wichtig ist. Ich möchte einen Bericht der zusammengefassten Informationen über Teile der Ereignisse generieren. Nach der Tat, aber ich will sequenziell (deterministisch?) Verarbeiten. – Josh

1

Möglicherweise Hashed Adapter Objects (wenn Sie eine gute Erklärung, es auf dem Netz finden können - sie scheinen zu fehlen.)

+0

Ich endete mit etwas wie diesem zusammen mit der Eigenschaft Tasche Ansatz. Ich extrahiere im Grunde nur den Ereignistyp als zweite Eigenschaft der Tasche und hänge die Handler an die 60 verschiedenen Typen an. Danke für den formellen Hinweis. – Josh

2

eine Flyweight Fabrik Strategie Objekte Betrachten wir eine pro ‚Klasse‘ der Veranstaltung.

Suchen Sie für jede Zeile mit Ereignisdaten die entsprechende Parsing-Strategie aus der Flyweight-Factory und übergeben Sie dann die Ereignisdaten an die Strategie für das Parsing. Jedes der 60 Strategieobjekte könnte derselben Klasse angehören, aber mit einer anderen Kombination von Feldparsing-Objekten konfiguriert sein. Es ist ein bisschen schwierig, genauer zu sein, ohne weitere Details.

+0

Die Parser-Komponente ist fertig, es ist ein endlicher Automat und funktioniert ziemlich gut für alle Ereignisse. Entschuldigung, wenn ich unklar war. Das Problem ist, ich weiß nicht, wie die Ereignisse nach dem Parsen zu verarbeiten sind. – Josh

0

Ich bin mir nicht sicher, ob ich das Problem richtig verstehe. Ich nehme an, dass es eine komplexe "Modellaktualisierungslogik" gibt. Verteile das nicht durch 60 Klassen, bewahre es an einem Ort auf, entferne es aus den Event-Klassen (Mediator-Muster, Art).

Ihr Mediator wird mit Ereignisklassen arbeiten (ich sehe nicht, wie Sie die Flyweight hier nutzen könnten), werden die Ereignisse selbst analysieren kann.

Wenn die Update-Regeln sehr kompliziert sind, können Sie das Problem mit einer allgemeinen Programmiersprache nicht wirklich angehen. Erwägen Sie, eine regelbasierte Engine oder etwas Ähnliches zu verwenden.

1

Direkt an der Spitze:

Ich mag den Vorschlag in der akzeptierten Antwort über nur eine Klasse mit einer Karte von Eigenschaften. Ich denke auch, das behvavior kann auch auf diese Weise zusammengebaut werden:

class Event 
{ 
    // maps property name to property value 
    private Map<String, String> properties; 

    // maps property name to model updater 
    private Map<String, ModelUpdater> updaters; 

    public void update(Model modelToUpdate) 
    { 
     foreach(String key in this.properties.keys) 
     { 
      ModelUpdater updater = this.updaters[key]; 
      String propertyValue = this.properties[key]; 

      updaters.updateModelUsingValue(model, propertyValue); 
     } 
    } 

} 

Die ModelUpdater Klasse nicht abgebildet. Es aktualisiert Ihr Modell basierend auf einer Eigenschaft. Ich habe die Schleife erfunden; Dies kann oder kann nicht sein, was Ihr Algorithmus tatsächlich ist. Ich würde ModelUpdater wahrscheinlich eher zu einer Schnittstelle machen. Jeder Implementierer wäre pro Eigenschaft und würde das Modell aktualisieren.

Dann würde mein "Hauptschleife" sein:

Model someModel; 

foreach(line in logFile) 
{ 
    Event e = EventFactory.createFrom(line); 
    e.update(someModel); 
} 

EventFactory baut die Ereignisse aus der Datei. Es füllt die zwei Karten basierend auf den Eigenschaften des Ereignisses auf. Dies bedeutet, dass es eine Art gibt, eine Eigenschaft mit dem zugehörigen Modellupdater zu vergleichen.

Ich habe keine ausgefallenen Musternamen für Sie. Wenn Sie einige komplexe Regeln haben, etwa wenn ein Ereignis die Eigenschaften A, B und C hat, dann ignorieren Sie den Modellaktualisierer für B, dann muss dieser Ansatz irgendwie erweitert werden. Höchstwahrscheinlich müssen Sie möglicherweise einige Regeln in die EventFactory einfügen, indem Sie das Regelobjektmuster verwenden. Da hast du einen Musternamen für dich!