Autor Thema: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)  (Gelesen 3921 mal)

Offline thkn777

  • Aktives Mitglied
  • ***
  • Beiträge: 176
Hallo zusammen,
eines gleich vorneweg: wenn jemandem ein besserer Titel für den Thread einfällt - ich ändere das gerne noch ab für's spätere leichte Finden.

DAS IST KEIN FRAGE-THREAD. Ich beschreibe einen möglichen Lösungsvorschlag, ressourcensparend und schnell mehrfach auftretende Werte in Listen zu zählen. Wenn Ihr so ein Problem habt oder es Euch einfach nur interessiert - einfach mal reinlesen. Wenn nicht... lest bitte lieber einen anderen Thread und helft dem Fragesteller bei seinem Problem!  ;)

++++++

Ich hatte letztens das Problem, daß ein Agent viel zu lange lief. Größenordnung 15-20 Minuten auf einem ordentlichen Notes-Server. Außerdem ging die CPU-Last auf 50%, 'ne Menge I/O... das Ende vom Lied: der Agent sollte optimiert werden.

Was sollte gelöst werden? Eigentlich eine einfache Aufgabe: Zählen, wie oft Schlüsselworte in Dokumenten vorkommen.
- es gibt X Schlüsselwörter, je Schlüsselwort ein Dokument (sagen wir, FORM="swort")
- es gibt Y Dokumente, die diese Schlüsselwörter in 2 Items enthalten können (Dokument FORM="dokument")
- Item1 = single value text
- Item2 = multi value text

Besonderheiten Item2: hier handelt es sich um eine Historie, je Element wird das Datum geführt und getrennt durch Leerzeichen das zu diesem Datum verwendete Schlüsselwort.

Bsp.
- Schlüsselworte: eins, zwei, drei
- Dokument1, Item1="eins", Item2="01.01.2015 zwei","25.12.2014 drei"
- Dokument2, Item1="zwei", Item2="03.01.2015 eins","02.01.2015 zwei","02.01.2015 zwei"

Hier sieht man schon das Problem im Dokument2: das Element "02.01.2015 zwei" tritt doppelt auf. Ja, das ist in dieser Applikation zulässig und hat eine (sinnvolle) Bedeutung.


"Standard-Ansatz": LISTE
Eine sinnvolle Möglichkeit, das Problem zu lösen (also "wie oft taucht in allen Dokumenten Schlüsselwort zwei auf" usw. für alle Schlüsselworte): alle Dokumente z.B. mit LotusScript durchlaufen, eine Liste mit Index=Schlüsselwort aufbauen und bei jedem gefundenen Schlüsselwort das Listenelement um eins erhöhen.

Ist man durch alle Dokumente durch, liefert Liste(Schlüsselwort) die Anzahl des Vorkommens. In unserem Beispiel (2 Dokumente) also Liste("zwei")=4.

Diese "Listen"-Lösung lief statt 15-20 Minuten ca. 15-20 Sekunden. Neue Agenten wurden in der nächsten Minute in die Queue gestellt, starteten nicht sofort danach. D.h. es ist noch Nachlaufzeit (Housekeeping: Speicher aufräumen) im Nachgang nötig.


Alternativ-Ansatz: "LOOKUP-VIEW"
Ich fand das noch zu langsam und zu umständlich, außerdem plusterte sich die Liste im RAM auf. Anderer Ansatz: Lookup-Ansicht. Das scheitert im ersten Moment daran, daß man zwar Multivalue-Items anzeigen kann, auch mit Mehrfachwerten getrennt, aber je Schlüsselwort gibt's nur eine Zeile in der Ansicht. Für Dokument2 (siehe Bsp. oben) bekomme ich, wenn ich Item1 und Item2 sinnvoll zusammenfasse (Stichwort Datum wegschneiden) nur zwei Zeilen angezeigt:

eins
zwei

Ich MÖCHTE aber eine Anzeige der Form:

eins
zwei
zwei
zwei

damit ich eben direkt in der Ansicht zählen kann, daß "zwei" dreimal auftrat im Dokument.

Die Lösung für die erste (sortierte) Spalte der Lookup-View:
- Trennzeichen T definieren, das in Schlüsselwörtern nicht vorkommt, z.B. "~~"
- Item2 mit einer @For(x:=0; x<=@Elements(Item2)... Schleife durchlaufen
- aus einem gefundenen Schlüsselwort einen String bauen der Form Schlüsselwort+T+@NoteId+T+@Text(x) und alles in einer neuen Liste zusammenfügen
- dazu dann noch Item1 als Item1+T+@NoteId+T+"0"
- über die neue Liste ein @Trim und fertig.

Die Zeilen in der Ansicht sehen jetzt prinzipiell so aus (siehe Beispiel oben, Dokument1 und Dokument2 mit ausgedachten NoteID's):
eins~~NT00005555~~1
eins~~NT0000AAAA~~0
zwei~~NT00005555~~0
zwei~~NT00005555~~2
zwei~~NT00005555~~3
zwei~~NT0000AAAA~~1
drei~~NT0000AAAA~~2

In LotusScript kann man sich jetzt einfach mit
Set vec = LookupView.Getallentriesbykey(Schlüsselwort & Trennzeichen, False)
eine ViewentryCollection geben lassen und die Anzahl der Elemente zählen.

Für unser Beispiel:
Set vec = LookupView.Getallentriesbykey("zwei" & "~~", False)
Print Cstr(vec.Count)

erzeugt als Ausgabe "4".

Im o.g. Agenten durchläuft man dann einfach alle Schlüsselwortdokumente einmal, ermittelt für jedes Schlüsselwort die Summe des Auftretens in den Dokumenten und schreibt den Wert ggf. zurück in das Schlüsselwortdokument für spätere Auswertungen.

Der Index der Lookup-View ist angenehm klein, der Agent läuft jetzt im Schnitt 2s und verbraucht praktisch keinen RAM. Folgeagenten starten praktisch sofort nach Ende des Zähl-Agenten.

Für viele Aufgabenstellungen sind Listen toll, für die o.g. ist der Weg über die spezielle Lookup-Ansicht nochmal schneller und ressourcensparender. Ich war selbst überrascht, wie groß der Unterschied war. Selbst wenn der Ansichts-Index neu aufgebaut werden muß, läuft der Agent nur 5s.

Wer viel mit großen Listen arbeitet weiß, daß sowohl Aufbau als auch Abbau der Liste im RAM Zeit frißt, teilweise Minuten. Gerade Agenten, die im 5-Minuten-Takt laufen sollen, haben so bei steigender Datenmenge zwangsläufig irgendwann "Aussetzer" und werden ggf. erst zum übernächsten 5-Minuten-Intervall in die Amgr-Queue eingestellt.

Vielleicht eine Möglichkeit für den einen oder anderen, an der Stelle den "Turbo" zu zünden. Viel Erfolg beim Ausprobieren!
« Letzte Änderung: 04.05.15 - 14:53:06 von thkn777 »

Offline Tode

  • Moderatoren
  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 6.883
  • Geschlecht: Männlich
  • Geht nicht, gibt's (fast) nicht... *g*
Re: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)
« Antwort #1 am: 04.05.15 - 19:40:02 »
Wen Du in die erste Spalte Deiner View eine 1 schreibst, dann in den Eigenschaften "Gesamtsumme" aktivierst, und die zweite Spalte kategorisierst nach Deinem Feld, dann kannst Du über einen notesViewNavigator einfach von Kategorie zu Kategorie springen, und NotesViewEntry.ColumnValues(0) auslesen, das sollte nochmal schneller sein...
Gruss
Torsten (Tode)

P.S.: Da mein Nickname immer mal wieder für Verwirrung sorgt: Tode hat NICHTS mit Tod zu tun. So klingt es einfach, wenn ein 2- Jähriger versucht "Torsten" zu sagen... das klingt dann so: "Tooode" (langes O, das r, s und n werden verschluckt, das t wird zum badischen d)

Offline pram

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.170
  • Geschlecht: Männlich
    • Foconis Object Framework
Re: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)
« Antwort #2 am: 05.05.15 - 07:23:58 »
Auch wenns kein Fragethread ist, aber ein bisschen hirnt es mich doch  ;D
Alternativ-Ansatz: "LOOKUP-VIEW"
Ich fand das noch zu langsam und zu umständlich, außerdem plusterte sich die Liste im RAM auf. Anderer Ansatz: Lookup-Ansicht. Das scheitert im ersten Moment daran, daß man zwar Multivalue-Items anzeigen kann, auch mit Mehrfachwerten getrennt, aber je Schlüsselwort gibt's nur eine Zeile in der Ansicht. Für Dokument2 (siehe Bsp. oben) bekomme ich, wenn ich Item1 und Item2 sinnvoll zusammenfasse (Stichwort Datum wegschneiden) nur zwei Zeilen angezeigt:

eins
zwei
Konnte ich kaum glauben, aber habs gerade ausprobiert und du hast recht. Meine erste Idee war auch die, wie Tode es vorgeschlagen hat, dies wird aber aus o.g. "Optimierung" nicht funktionieren, da doppelte Werte nur einfach gezählt werden.

Man muss also je Dokument vorhalten, wie oft welcher Wert vorkommt. Das kann man ggf. auch in der SELECT-Formel berechnen (ein Trick, den ich auch viel zu selten nutze)

Select Formel:
Code
FIELD _all := @Trim(item:item2);
FIELD _kategorie := @Unique(_all);
FIELD _anzahl := @Transform(_kategorie;"x";@Sum(@Transform(_all;"y";@If(x=y;1;0))));
SELECT Form="Test"
1. Zeile berechnet ALLE zu zählenden Werte (in deinem Fall aus Historie ausschneiden)
2. Zeile berechnet die Kategorien
3. Zeile berechnet als "parallelen Mehrfachwert" die Vorkommnisse in _all je Kategorie

Macht man dann noch eine kategorisierte Spalte auf "_kategorie" und eine Summenspalte auf "_anzahl" (jeweils Mehrfachwerte getrennt anzeigen), so kann man das Ergebnis direkt in der zugeklappten Ansicht ablesen.


Gruß
Roland
Roland Praml

IBM Certified Application Developer - Lotus Notes and Domino 8
Ich verwende das Foconis Object Framework

Offline thkn777

  • Aktives Mitglied
  • ***
  • Beiträge: 176
Re: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)
« Antwort #3 am: 05.05.15 - 10:07:18 »
@pram
Danke für den Summen-Trick per @Transform - das gucke ich mir nochmal genauer an! Ich wollte sowas in der Art eigentlich auch machen, bin dann aber bei "mit @For geht's ja auch" falsch / zu früh abgebogen. @Transform sollte nochmal einen Tick schneller sein als @For wenn ich mich recht entsinne - vor allem bei steigender Anzahl Iterationen.

Statt hochzuzählen, kann man übrigens auch einfach ein @Unique dahintersetzen, das funktioniert auch. Ich weiß allerdings nicht, ob es da bei größeren Views nicht mal zu Überläufen kommen kann und wollte das in einer produktiven Umgebung auch nicht ausprobieren. Performance ist ungefähr gleich.

@Beide
Die Sachen, die ich bisher mit ViewNavigatoren gemacht habe, waren alles andere als schnell.
Jetzt der wichtigere Grund: ViewNavigator wollte ich nicht nehmen. Wir beide ... äh... mögen uns nicht.  :-[ ::)  :-:
« Letzte Änderung: 05.05.15 - 10:18:05 von thkn777 »

Offline pram

  • Gold Platin u.s.w. member:)
  • *****
  • Beiträge: 1.170
  • Geschlecht: Männlich
    • Foconis Object Framework
Re: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)
« Antwort #4 am: 05.05.15 - 23:20:00 »
Möchte hier nur nochmal was zum Verständnis ergänzen
... Ich weiß allerdings nicht, ob es da bei größeren Views nicht mal zu Überläufen kommen kann ...
Die Formel im SELECT wird je Dokument ausgeführt, da läuft dann auch nichts über.
Die berechneten (virtuellen) Felder kann man dann in der Ansicht in Spaltenformeln oder auch im SELECT verwenden,
(z.B.: SELECT Form = "Test" & _all != "")

Wenn ich im Nachgang so recht überlege, wird die Formel aber wohl auf jedes Dokument in der DB angewendet und dann geprüft ob der Select "true" ist.
Ggf wäre es sinnvoll, die aufwändige Berechnung noch mit einem @If(Form="Test";@Do(...berechnungen...);"") zu optimieren.

Noch ein bisschen OT: Den Trick, dass man im Select virtuelle Felder erzeugen kann, habe ich gefunden, als ich nach einer Lösung für verschiedene hierarchische Ansichten gesucht habe.
Die Hierarchie einer Ansicht wird ja normal (und ausschließlich) über $REF gesteuert.
Definiert man nun $REF im Select um mit:
FIELD $REF := @if(Form = "Response"; $REF2;@Unavailable)
so zeigt die Ansicht die Antworten gemäß $REF2 an.  :o
(Um $REF2 im Dokument zu erzeugen muss man makeResponse auf einem Temp-Doc aufrufen und das dadurch entstehende $REF Feld mit geändertem Namen rauskopieren)

Gruß
Roland
Roland Praml

IBM Certified Application Developer - Lotus Notes and Domino 8
Ich verwende das Foconis Object Framework

Offline thkn777

  • Aktives Mitglied
  • ***
  • Beiträge: 176
Re: Vorkommen von Werten in Listen (Anzahl) - Performance (Tip)
« Antwort #5 am: 06.05.15 - 13:23:56 »
@pram
Ich weiß allerdings nicht, ob es da bei größeren Views nicht mal zu Überläufen kommen kann

Ich meinte eher: wenn in einer Ansicht bei einem view.Refresh() plötzlich ein paar Zehntausend bis Millionen @Unique-Werte erzeugt werden sollen... ob es ob der schieren Anzahl dieser quasi "auf einmal" generierten Werte irgendwo zu Problemen kommen könnte.

Weißt schon... N Dokumente * X Historieneinträge - das kann bei einer stark genutzten Db schnell mal größere Werte annehmen.

Frau G**gle hat zu diesem Thema keine Limits ausgespuckt, aber das heißt ja nicht, daß da keine sind.  ;)

 

Impressum Atnotes.de  -  Powered by Syslords Solutions  -  Datenschutz