Berechneter Text -> Performance

  • Hallo


    ich habe mal eine Frage zum Thema Computed Text und Performance


    Wir haben eine merhsprachige Anwenung, die momentan die Stadard-Notes Features für Sprachverwaltung verwendet, also mehrere Masken in verschiedenen Sprachen.


    Da es relativ große Masken mit vielen Feldern sind, ist der Aufwand bei änderungen relativ groß.
    Um diesen zu minimieren, kam u.a. die Idee, die Feldbeschreibungen dynamisch über computed text zu laden. Wie würde sich das auf die Performance auswirken?


    Momentan wäre es etwa 200 Beschriftungen. Es wird erwartet, dass die Datenbank ein relativ hohes Dokumentenaufkommen haben wird. Die Größe der Dokumente ist jedoch eher gering, da es weder RT-Felder noch Attachments gibt.


    Hat jemand schon mal so etwas auprobiert und kann die vorgehensweise empfehlen, oder davon abraten?


    Vielen Dank!

  • Bei BERECHNETEM Text siehst du als Entwickler nicht mehr allzu viel. Und ganz ähnlich wird es dem Anwender bei allen berechneten Feldlösungen gehen, wenn er Volltextsuchen über ausgefüllte Masken versucht.


    Wenn du darauf aber verzichten kannst, ist eine denkbare und recht performante und schnelle Lösung das Einziehen von Teilmasken.


    Also: deine Maske enthält weit oben ein Feld, das dir die Dialogsprache des Benutzers gibt (mach es am besten vom Typ BERECHNET BEIM ANLEGEN und lösche es in den Maskenevents QUERYOPEN und QUERYCLOSE, wenn gespeichert wurde (ggf. auch POSTSAVE, wenn ihr nur noch mit 6er Clients arbeitet).


    Darunter kommt eine auf Formel basierende Teilmaske, z.B.


    @If(Dialogsprache="D";"BezeichnerD";Dialogsprache="F";"BezeichnerF";"BezeichnerE")


    In dieser Teilmaske, die nur aus HIDDEN FIELDS BERECHNET ZUR ANZEIGE besteht, stehen alle Feldbezeichner, z.B. das Feld xx_Kunde. In der deutschen Teilmaske BEZEICHNERD steht als Wert "Kunde" drin, in der englischen Teilmaske BEZEICHNERE steht als Wert "Customer" drin.


    Im sichtbaren Teil deiner Maske gibt es nun ein Feld d_Kunde BERECHNET ZUR ANZEIGE mit dem Wert xx_Kunde.


    Vorteil dieses Vorgehens ist die leichte Erweiterbarkeit um weitere Sprachen (Formel für Teilmaskeneinzug erweitern und weitere Teilmaske für neue Sprache hinzufügen) sowie weitere Felder mit sehr geringem Pflegeaufwand für die Programmierer und geringem Rechenaufwand für den Client.


    Am Anfang habe ich geschrieben, daß man nach Möglichkeit das Basisfeld DIALOGSPRACHE als BERECHNET BEIM ANLEGEN deklarieren sollte. Der Hintergrund ist, daß in manchen Notes-Clientversionen die BERECHNET ZUR ANZEIGE-Felder nicht richtig in Dialogboxen durchgereicht werden.

  • Die Lösung mit den berechneten Feldern ist aber auch nicht schlecht. Und wenn man es richtig macht, dann auch performant.


    Das könnte so aussehen:


    Da die Datenmenge groß wird, erstellt man eine zusätzliche Datenbank, in die alle Lookups der Maske verweisen. In dieser datenbank sind Stammdaten der Benutzer und Dokumente mit den jeweiligen Feldbezeichnungen in den jeweiligen Sprachen.


    In der besagten Maske wird zunächst per Lookup über @username auf die jeweiligen Stammdaten des Benutzers zugegriffen. Dort ist die Landessprache hinterlegt. Anhand der Landessprache werden dann über ein zweites Lookup alle Feldbezeichnungen aus den entsprechenden Dokumenten der neuen Datenbank gezogen. Diese müssen unbedingt in EINEM String zusammengefasst sein, damit ein einziger lookup ausreicht. Also z.B. ##01||bezeichner01##02||Bezeichner02##...


    Der String füllt dann in der besagten Maske ein Feld, das ganz oben steht. Dann wird dieser string für die einzelnen Felder geparst. z.B. so: @left(@right(Feld;"##01||");"##").


    Das parsen selbst fällt in Sachen performance gar nicht ins Gewicht.


    Gruss, Bernd

  • Der Vorteil von Mind1is Lösung - und das ist auch der einzige Vorteil, den ich erkennen kann - ist die strikte Trennung von Inhalten von der Entwicklung, wobei man sich durchaus fragen muß, ob diese Trennung wirklich vorhanden ist, denn der "Lindwurm" des DBLookup-Feldes muß irgendwo dem Eingeber der Daten bekannt sein und bei Erweiterungen usw. auch gepflegt werden.


    Eklatantester Nachteil ist aber die Auftrennung in mehrere Datenbanken. Fehlt einem (z.B. lokalen) Benutzer die Bezeichner-Datenbank, hat er leere Masken. Repliziert er die Bezeichner-Datenbank nicht regelmäßig, fehlen ihm alle Änderungen an den Bezeichnern. Ich spreche hier aus leidvoller Erfahrung. Wir haben z.Z. immer wieder Probleme mit separaten Schlüsselwortdatenbanken, wenn Anwendungs-Datenbanken von Server zu Server umgezogen werden. Die Anwender behalten für die "unwichtigen" Schlüsselwortdatenbanken einen Desktop-Link, der auf eine nicht mehr existierende DB auf einem stillgelegten Server zeigt - und können die Schlüsselwörter oft genug nicht auswählen. Viele unserer Kunden leben in einem Land mit dem Namen "Eine Ansicht mit diesem Namen konnte nicht gefunden werden".


    Zweiter Nachteil der Lösung von Mind1: Unübersichtlichkeit und schlechte Wartbarkeit. In der Anwendung muß man sich bei ihm ja für die Position eines Schlüsselworts entscheiden. Es folgen aufeinander z.B. Kundenname, Strasse, Ort, Land, Produktnummer, Produktname usw.
    Wenn ich dieses erst einmal in 17 Masken verwurstelt habe und Produktnummer immer das @Word(Lindwurm;5) ist, muß ich das Bundesland und Postfach irgendwann hinten anhängen, wenn es gebraucht wird. Man kann alles nur noch hinten anhängen. Zu gut deutsch: man startet in Mind1s Lösung relativ aufgeräumt und gut sortiert, bekommt aber einen immer undurchschaubareren Wust an unzusammenhängenden Nachträgen.


    Genau das umgeht der Vorschlag mit den Bezeichner-Teilmasken. Was zusammengehört, bleibt auch räumlich und gedanklich zusammen. Man kann durchaus themenbezogene Teilmasken für die Bezeichner erstellen und diese durch die Anwendungen in den verwendeten Templates aus einem Mastertemplate nachgestalten lassen.


    Mind1 hat seine Auslagerung in eine separate Datenbank ja vor allem deshalb gemacht, weil er die gleichen Bezeichner von verschiedenen Anwendungen nutzen (lassen) will. Anwender wissen es zu schätzen, wenn es möglichst wenige semantische Vieldeutigkeiten gibt. Wenn das Feld Autor einmal Autor, einmal Ersteller, dann wieder Bearbeiter oder Editor heißt, ist dem Verwirrspiel Tür und Tor geöffnet; GleichGemeintes soll auch immer gleich bezeichnet werden.

  • Ich persönlich kann nur dazu raten es in teilmasken zu machen, rieziges vorteil dabei ist das weitere sprachen sehr einfach werden, und anpassungen an ein feld, relativ einfach in alle teilmasken gemacht werden können.


    Berechnete text hat den nachteil das es am CLIENT zeit kostet, und damit den anwender aufgebrummt wird, während teilmasken einmalig als gestaltungselement gecached werden, und damit sofort verfügbar.


    Dabei kann auch eine sprache optisch anders aussehen als der andere (auch reinfolge technisch), damit den persönliche erfahrungen und bedienbarheit für den jeweilige anwender so gemacht werden kann wie es den passt.


    Ich sage dieses nachdem ich bereits 5 mehrsprachige anwendungen gemacht habe.. und den teilmasken variant ist definitiv der schnellste für den anwender.


    Ronka

  • Hi,


    Erstmal Danke für die Tipps!


    sorry, dass ich mich erst jetzt wieder melde, aber ich hatte in meinem Urlaub andere Dinge zum tun ;)


    Zu den Lösungen:


    Das mit den Teilmasken hört sich ganz gut an. Nur 1 Problem habe ich mit der Lösung von LN4ever


    Ich habe Autoren in der Datenbank, d.h das Feld für den Bezeichner kann nicht immer von den Usern gelöscht bzw neu berechnet werden. Aber das könnte man ja mit einer Profillösung umgehen. Die Benutzer haben Profile in der Datenbank. Dann könnten Sie ja dort ihre Sprache einstellen, und die Teilmaske wird anhand dieser Information geladen (sofern das geht)


    Werde ich mal ausprobieren ;)

  • Ein Beispiel, wie ich es in ANwendungen mache für die Berechnung des Feldes DIALOGSPRACHE:


    SpracheUser:=@GetProfileField("98SU";"SetupDialogsprache";@UserName);
    SpalteVorgabe:=@If(@IsMember("$$WebClient";@UserRoles);"SetupDefaultDialogspracheWeb";"SetupDefaultDialogspracheNC");
    tSprache:=@If(SpracheUser="";@GetProfileField("98SG";SpalteVorgabe);SpracheUser);
    dsprache:=@If(@IsError(tsprache) | tsprache = "";@If(@IsMember("$$WebClient";@UserRoles);"E";@Environment("ENV_Dialogsprache"));tsprache);
    regionSprache:=@LanguagePreference ([Region]);
    RSprache:=@If(@UpperCase(@Left(regionSprache;2))="DE";"D";"E");
    @If(@IsError(dsprache) | dsprache = "";RSprache;dsprache)


    Ich klappere also nacheinander ein paar Möglichkeiten ab:
    - wenn der User ein UserProfildokument hat, dann nimm seine dort eingestellte Sprache
    - wenn der User kein Profildokument hat, dann nimm die Vorgabesprache, die im Gesamtprofildokument für den aktuellen Typ (Notesclient oder Web) eingestellt ist
    - wenn eine bestimmte Umgebungsvariable gesetzt ist, dann nimm auch die, wenn der Benutzer mit dem Notesclient arbeitet
    - nimm die Installationssprache des NotesClients, wenn bisher nichts oder Fehler herauskamen (das ist im Browser auch dessen Spracheinstellung !)


    Dieses Feld wird auch für einen Autor oder Leser im UI-Dokument berechnet (auch wenn er es hinterher nicht abspeichern kann)


    Das Löschen des Feldes im QUERYOPEN nehme ich deswegen vor, weil beim Durchrechnen mit Masken (@Command([ToolsRefreshSelectedDocs]), doc.ComputeWithForm) das Feld leicht stehenbleibt, weil die Maskenevents nicht ausgeführt werden, und - da es vom Typ BERECHNET BEIM ANLEGEN ist, bereits einen Wert hat.


    Der QUERYOPEN-Event wirkt beim REMOVEn eines ITEMs auf die Durchreichung des Backend-Dokuments zum Frontend und funktioniert daher auch für einen Leser. Sein UI-Dokument hat das Feld zunächst nicht und stellt es im Frontend gemäß der für ihn gültigen Formel als neues Feld wieder her.


    Das Löschen beim Schließen des Dokuments ist für die Autoren für den "Normalfall" gemacht, wenn sie das Dokument ändernd speichern, damit das Dokument "sauber" ist. Beim Print würdest du es ansonsten in der zuletzt verwendeten Dialogsprache ausdrucken.