Herzlich willkommen auf dem Blog der exensio GmbH

exensio ist ein unabhängiges Software-Unternehmen von erfahrenen IT Beratern und Architekten. Zu unseren Kunden zählen namhafte deutsche Großunternehmen.

exensio verbessert das Kommunikations- und Informationsmanagement von Unternehmen. Auf Basis sinnvoller und zweckmäßiger Technologien erarbeiten wir flexible und übergreifende Lösungen für webbasierte Informationssysteme. Abhängig von den Kundenanforderungen realisieren wir Web Applikationen sowie Lösungen auf Basis von Web Content Management- und Portalsystemen. Integrativ, wirtschaftlich und anwenderfreundlich!

Hier gelangen Sie zur exensio GmbH.

Montag, 26. April 2010

Volltextsuche mit der Open-Source-Lösung Compass Search im Cluster

Wer sich mit Suchmaschinen für eigene Projekte beschäftigt, stößt zweifellos früher oder später auf Apache Lucene. Lucene ist eine Suchmaschinen-Bibliothek, die mit einer beeindruckenden Funktionsvielfalt ausgestattet ist. Sie ist in Java geschrieben, mittlerweile aber auch für viele andere Programmiersprachen verfügbar.

In diesem Eintrag geht es um die Einbindung einer Suche in ein WebLogic Portal Projekt, welches in einem Cluster auf WebLogic Servern läuft. Als Datenbank-Persistenzschicht wird Hibernate eingesetzt. Die Suche soll dabei Entitäten und deren Relationen erfassen und Funktionen wie unter anderem unscharfe Suche und boolesche Operatoren unterstützen und dabei einen gutes Ranking der Ergebnisse liefern.

Durchsuchen und Indizieren von Entitäten mit Relationen

In diesem Beispiel geht es um eine Applikation, mit der Projekte verwaltet werden können. Im vereinfachten Beispiel soll davon ausgegangen werden, dass es lediglich die Entität Project mit einigen Attributen sowie die Entität User mit einigen Attributen gibt. Dabei besteht zwischen Project und User folgende Relation: Ein Projekt ist immer einem User zugeordnet, ein User kann jedoch auch mehreren Projekten zugeordnet sein.

Bei der Suche soll dabei der Titel des Projekts, die Beschreibung des Projekts und der Vor- und Zuname des zugeordneten Autors (Entität User) durchsucht werden können.

Die folgende Abbildung zeigt die Entitäten und die vorherrschende Beziehung:

Das Framework Compass

Compass Search ist ein Framework, welches auf Lucene setzt und eine einfache (Java) API für Suche und Indizierung anbietet. Darüber hinaus lässt sich mit Compass Search die Suche direkt mit Hibernate und entsprechenden Annotationen in ein Projekt einbinden. Mit Compass Search besteht außerdem die Möglichkeit, den Suchindex über JDBC in einer relationalen Datenbank abzuspeichern. Letzteres ist mit Hibernate Search, einem Projekt, das einen ähnlichen Ansatz wie Compass Search verfolgt, nicht möglich, was den Einsatz bei Applikationen, die in einem Cluster laufen, ausschließt.

Damit Compass Search verwendet werden kann, muss es in das Projekt eingebunden werden. In erster Linie geht es dabei um das Hinzufügen der entsprechenden Jar-Dateien in den Classpath. Der Download mit Installationsanleitung findet sich auf der offiziellen Webseite von Compass Search.

Für unser Beispiel sieht die Konfiguration in der compass.cfg.xml, die im Classpath der Applikation liegt, wie folgt aus:

<compass-core-config xmlns="http://www.compass-project.org/schema/core-config"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.compass-project.org/schema/core-config
http://www.compass-project.org/schema/compass-core-config-2.2.xsd">

<compass name="default">
<connection>
<jdbc dialect="org.apache.lucene.store.jdbc.dialect.OracleDialect" managed="true">
<dataSourceProvider>
<jndi lookup="exensioExampleJndiDataSource" />
</dataSourceProvider>
</jdbc>
</connection>

<transaction factory="org.compass.core.transaction.JTASyncTransactionFactory" commitBeforeCompletion="true" lockPollInterval="200" lockTimeout="30">
</transaction>

<searchEngine>
<optimizer schedule="false" />
</searchEngine>

<mappings>
<class name="com.exensio.examples.persistence.entity.Project" />
<class name="com.exensio.examples.persistence.entity.User" />
</mappings>
</compass>

</compass-core-config>

Im ersten Abschnitt wird die Verbindung zur Datenbank definiert. In diesem Beispiel greifen wir auf eine im WebLogic Server definierte JNDI Datenquelle zurück. An dieser Stelle könnten auch direkt JDBC-Daten mit Benutzer und Passwort angegeben werden, was jedoch aus Performance-Gründen nicht zu empfehlen ist.

Eine weitere interessante Konfiguration ist das Mapping am Ende, bei welchem die Entitäten angegeben werden müssen, die Compass-Annotationen enthalten und bei der Suche betrachtet werden sollen.

Die Annotationen in den Java-Dateien sehen wie folgt aus und sind selbstklärend. Eine Übersicht über die vorhandenen Annotationen findet sich in der Dokumentation unter Kapitel 6 "OSEM - Object/Search Engine Mapping".

Aus Übersichtsgründen sind nur Teile der Entitäten angegeben.

Project.java

@Entity
@Searchable
public class Project implements IProject {
@Id
@SearchableId
private Long id;

@ManyToOne(fetch = FetchType.LAZY)
@SearchableComponent(prefix = "user_")
private User user;

@SearchableProperty(boost = 2.0f)
private String title;

@SearchableProperty
private String description;

// Getter and Setter will stay unmodified
}


User.java

@Searchable(root=false)
public class User {
@Id
@SearchableId
private Long id;

@SearchableProperty
private String firstname;

@SearchableProperty
private String lastname;

// Getter and Setter will stay unmodified
}

Wichtig ist die Annotation Searchable, bei der über die Eigenschaft root angegeben wird, welche Klasse die Wurzelentität darstellt.

Indizieren

Damit später auch etwas gefunden werden kann, müssen die Daten noch indiziert werden. Compass Search bietet die Möglichkeit über Hibernate Events bei jedem Schreibzugriff automatisch die neuen Werte zu indizieren bzw. alte Werte zu löschen. Die entsprechenden Listener müssen in der Compass Konfiguration angegeben werden.

Da in diesem Beispiel jedoch das programmatische Indizieren gezeigt werden soll, wird auf die automatische Indizierung nun nicht weiter eingegangen. Die nötige Konfiguration ist in dieser Dokumentation gut beschrieben.

// Load compass configuration
CompassConfiguration conf = new CompassConfiguration();
URL cfg = getClass().getClassLoader().getResource("compass.cfg.xml");
conf.configure(cfg);
compass = conf.buildCompass();

// Get a compass session
CompassSession compassSession = compass.openSession();

// Start with getting all projects
List<project> projects = exensioCompassExampleService.getAllProjects();

// Begin the compass transaction block
CompassTransaction compassTransaction = null;
try {
compassTransaction = compassSession.beginTransaction();

// Iterate through the list of projects
Project p = null;
for (int i = 0; i < projects.size(); i++) {
p = projects.get(i);

// Save annotated project to the index
compassSession.save(p);

// Commit with the specified commit interval or if at
// the end of the project list
if (((i % transactionCommitInterval) == 0) || (i == (projects.size() - 1))) {
compassTransaction.commit();
}
}

// Start optimizing
compass.getSearchEngineOptimizer().optimize();
} catch (CompassException ex) {
if (compassTransaction != null) {
compassTransaction.rollback();
logger.error("Compass Indexer: Had to rollback the Compass transaction because of a Compass exception.",ex);
} else {
logger.error("Compass Indexer: Compass exception (compass transaction is null)",ex);
}
} finally {
compassSession.close();
}

Suchen

Ähnlich einfach wie das Indizieren ist das Suchen. Der Aufruf dazu lautet:

CompassHits hits = session.find(searchString);

Anwendungsbeispiele

Mit Compass und Lucene können komplexe sowie gezielte Suchanfragen abgeschickt werden. Eine Suche nach description:"exensio GmbH integriert Compass Search" würde all jene Projekte als Resultat liefern, die in der Beschreibung den Text "exensio GmbH integriert Compass Search" haben. Nach dem Nachnamen eines Autors kann über das in der Annotation angegebene Präfix gesucht werden: user_lastname:Schmidt

Per Standardeinstellung durchsucht Compass alle Felder, so dass eine Suche nach exensio auf alle indizierten Attribute geht. In unserem Fall würde das Vorkommen von exensio im Titel eines Projekts jedoch höher bewertet werden (boost-Eigenschaft in der Annotation, siehe oben) und dadurch jene Projekte zuerst in der Ergebnismenge zurückliefern.

Fazit

Mit dem Compass Search Framework kann auf einfache Weise eine funktionsreiche und performante Suche in kleine sowie große Applikationen integriert werden. Beim Speichern des Indexes kann entweder das Dateisystem oder eine Datenbank benutzt werden, was somit den Betrieb im Cluster ermöglicht. Auch die Integration in JVM-nahe Cluster-Software wie Terracotta ist möglich.

Wenn gewünscht kann das Indizieren im Hintergrund über Hibernate Listener integriert werden, so dass es keine Verzögerung zwischen Suchresultaten und den tatsächlich vorhandenen Daten in der Applikation gibt.

Über die Einbindung von Apache Tika können nicht nur reine Texte sondern auch viele gängige Dateiformate indiziert werden. Dazu zählen beispielsweise diverse Office-Formate wie Microsoft Word, Excel und Powerpoint sowie Adobe PDF.

Samstag, 24. April 2010

User-Interface-Design mit Wireframes

In einer fachlichen Spezifikation ist das geschriebene Wort – wie auch in anderen Bereichen – dehnbar.  Aus diesem Grund wird in Spezifikationen gerne visualisiert,  beispielsweise durch den Einsatz von UML. Für die Beschreibung von User Interfaces (UI) bietet es sich hier an, die Spezifikation mit Grafiken anzureichern. Für die Erstellung dieser UI-Grafiken wird gerne Photoshop benutzt. Dies hat jedoch zum einen den Nachteil, dass dies sehr aufwändig sein kann und zum anderen wird gerne zunächst die Ästhetik diskutiert. Wir alle kennen die Aussage „die Farben gefallen mir aber noch nicht so sehr“ obwohl in diesem frühen Stadium zuerst das Fachliche geklärt werden sollte. Aus diesem Grund benutzen wir bei exensio zuerst Wireframes. Diese werden dann – wenn die fachlichen Fragen in Bezug auf das UI geklärt sind – mittels Photoshop reingezeichnet bzw. als HTML Prototyp umgesetzt.
Was sind Wireframes?
Ein Wireframe ist die konzeptionelle Darstellung eines UI-Prototypen. Diese werden bewusst in schwarzweiß gehalten,  um ästhetische Fragen zu unterbinden. Wireframes können per Hand oder toolunterstützt gezeichnet werden. Wir bei exensio benutzen hierzu das Tool Balsamiq Mockups [1]. Es erlaubt die Gestaltung von sehr komplexen UIs mit einer einfachen und intuitiven Oberfläche.  Das Bild unten zeigt ein Beispiel.


Referenzen
[1] Balsamiq Mockups

Freitag, 23. April 2010

Content Modellierung

Eines unserer Kernthemen ist die Konzeption und Umsetzung von Informationsportalen. Wie der Name bereits sagt, stellen Informationsportale Informationen aus verschiedensten Quellen dem Anwender zur Verfügung. Das Besondere dabei ist die Personalisierung. Informationen werden anhand des individuellen Bedarfs eines Benutzers zur Verfügung gestellt. D.h. nicht mehr der Benutzer sucht nach den für ihn geeigneten Informationen sondern Informationen, die für den Benutzer wichtig sind, werden ihm einfach zugänglich zur Verfügung gestellt. Anhand des Benutzerprofils werden die relevanten Informationen aus den verschiedenen Informationsquellen zusammengestellt und dem Benutzer angeboten. Damit das ganze auch funktioniert, sind verschiedene Dinge erforderlich. Neben dem bereits genannten Benutzerprofil mit den Stammdaten und Interessengebieten des Benutzers ist es dringend erforderlich, dass die Informationen in strukturierter Form zur Verfügung stehen. Diese Strukturierung ist bereits in der Konzeptionsphase zu erarbeiten. Wir nennen die dafür notwendige Aktivität Content Modellierung.

Was ist Content Modellierung?
Content Modellierung dient der Strukturierung und Kategorisierung der Informationen, die im Portal darzustellen sind. Ähnlich einem Datenmodell für eine Applikation werden die Informationen für das Portal modelliert. Ein solches Modell besteht aus Content Typen und deren Beziehungen. Beispielsweise kann es einen Content Typ Nachricht geben. Ein solcher Content Typ wird durch Metaattribute und Attribute beschrieben. Metaattribute enthalten Daten über Daten, d.h. sie beschreiben den Content. Beispielsweise sind der Autor, das Erstellungsdatum oder die Keywords klassische Metadaten. Attribute hingegen enthalten die eigentlichen Informationen. Im Falle des Content Typs Nachricht könnten dies die Attribute Titel, Untertitel, Text, Referenzen und Kontakt sein. Aus den Content Typen und deren Beziehungen ergibt sich dann das Content Modell. Dinge wie Vererbung und Spezialisierung, die man aus der objektorientierten Modellierung kennt, finden auch hier ihre Anwendung - zumindest für das fachliche Modell. So könnte beispielsweise der Content Typ Nachricht noch Spezialisierungen haben wie Rundschreiben oder Pressemeldung.

Wozu dient diese Modellierung?
Auf Basis der Attribute (und auch Metadaten) können zum einen Informationen gezielt ermittelt und dem Benutzer zur Verfügung gestellt werden. Beispielsweise können einem Mitarbeiter, der einem bestimmten Standort zugeordnet ist, auch nur die Standort-relevanten Nachrichten angzeigt werden. Zum anderen können durch die Strukturierung auch Teile der Informationen zur Verfügung gestellt werden. So ist es eventuell erforderlich, auf der Startseite des Portals, lediglich die Titel und die Zusammenfassung der Nachricht darzustellen. Liegen diese Information nicht strukturiert in separaten Attributen vor, wäre dies nicht möglich.
Wie auch bei der Datenmodellierung gilt es bei der Content Modellierung, Mass zu halten. Es muss nicht zwanghaft alles strukturiert abgebildet werden. Die Notwendigkeit besteht dann, wenn entweder Informationen personalisiert oder auszugsweise dargestellt werden sollen. Auch Aspekte der Content Wiederverwendung spielen eine Rolle. So kann beispielsweise strukturierte Information über Produkte an den verschiedensten Stellen wiederverwendet werden - sei es als Überblicksinformation auf den Webseiten oder mehr detaillierte Informationen auf den internen Marketingseiten oder im Bereich Vertrieb.

Beispiel Content Model

Wer sich weiter für das Thema Modellierung und Strukturierung von Informationen interessiert, dem empfehle ich das Studium des Buches "Single Source Publishing" von Sissi Closs [1]. Die Zielrichtung geht zwar eher in die Richtung des Publizierens von Dokumentationen - man erhält aber einige Anregungen, die sich direkt auf das Thema Content Modellierung für Informationsportale abbilden lassen.

Referenzen:
[1] Buch "Single Source Publishing" von Sissi Closs

Sonntag, 18. April 2010

JRockit und fragmentierter Heap

Der Heap in einer JVM fragmentiert durch das Allokieren von Speicher für Objekte von unterschiedlicher Größe und Lebenszeit. Besonders problematisch ist dies beim Hochladen von großen Dateien. Sichtbar wird dies durch folgenden Logfile-Eintrag:
java.lang.OutOfMemoryError: allocLargeObjectOrArray - Object size: 262160, Num elements: 262144
In diesem Fall wurde vergeblich versucht 262160 Byte zu allokieren.
Was kann man tun?
Unter [1] findet sich eine wertvolle Anleitung. Hier die Infos, was wir gemacht haben:

  • Heapsize anpassen, ich bin jedoch kein Freund eines zu großen Heaps, da dies sehr lange GC Zyklen zur Folge hat. Es ist meistens besser in einem Cluster einen weiteren WebLogic Server hinzuzufügen, als den Heap zu groß zu wählen. Wir haben folgende Settings gewählt: -Xms1356m –Xmx1356m
  • Um sicherzustellen, dass der WebLogic Server Nodemanager die JRockit automatisch bei einem OutOfMemoryError starten kann, haben wir den Schalter –XxexitOnOutOfMemory benutzt. Hierbei bendet sich die Jrockit automatisch und läuft nicht in einem halbtoten Zustand weiter.
  • Um die GC überwachen zu können haben wir diesen Schalter hinzugefügt -Xverbose:gcpause 
  • Ein weiterer wichtiger Parameter ist die Verdichtung des freien Heaps, sprich eine Defragmentierung. Hierbei sollte vorsichtig vorgegangen werden. Wir haben uns für folgenden Wert entschieden: -XXcompactratio=10
  • Des Weiteren haben wir noch die Generational GC mit -Xgc:gencon gesetzt.

Hier die gesamte Parameterliste:
-Xms1356m –Xmx1356m -Xgc:gencon –XxexitOnOutOfMemory -Xverbose:gcpause

Noch eine Anmerkung zur Heapsize. In unserem Fall handelte es sich um einen Windows 2003 Server mit 16GByte Memory und eingeschalteter (Physical Address Extension)PAE .
Unter [2] findet sich eine interessante Info bzgl. Speicherverfügbarkeit von JRockit unter Windows mit PAE. JRockit hat hier gegenüber der Sun JVM den Vorteil, dass der Speicher nicht zusammenhängend sein muss. Jedoch muss hier beachtet werden, dass in einem JRockit Prozess auch etwaige DLLs von nativen Java Bibliotheken (z.B. SAPJco oder Documentum) liegen. Dies war bei uns der Fall.

Referenzen:
[1]Repost: Tips and tricks for dealing with a fragmented Java heap
[2]Repost: How to get (almost) 3 GB heap on Windows!

WebLogic Portal 10.3.2 und Java Server Faces (JSF)

Es hat sich herumgesprochen, dass Oracle das Apache Beehive Framework  nicht länger unterstützen wird. Die Entwicklung von Portlets soll nun mittels JSF realisiert werden. Aktuell wird jedoch nur die SUN JSF Referenz-Implementierung von Oracle unterstützt. Siehe [1].
Dies ist verständlich, da es sehr viele JSF Frameworks auf dem Markt gibt. Es sind jedoch vor allem die auf Ajax basierenden Frameworks, wie ICEfaces oder ADF Faces, die den Einsatz von JSF reizvoll erscheinen lassen. Wie sieht es mit der Integration solcher Frameworks in das WebLogic Portal aus?
Ist ICEfaces oder ADF Faces im WebLogic Portal möglich?
Der Einsatz von ICEfaces oder ADF Faces für eine reine Web Applikation ohne WebLogic Portal ist ohne Probleme möglich. Werden diese Frameworks im WebLogic Portal benutzt, wird die Angelegenheit jedoch etwas komplexer. In WebLogic Portal 10.3.2 wird  (per default) ein JSF 1.2  Portlet mittels der JSR 329 Faces Portlet Bridge in ein JSR 286 konformes Portlet gewandelt. Bei ICEfaces ist hier z.B. das Problem, dass die ICEfaces Bridge nicht durch eine andere JSF Bridge (z.B.  JSR 329 Bridge) ersetzt werden kann. Ich stand vor 2 Jahren vor dem Problem mit WebLogic Portal 10, es scheint bei WebLogic Portal 10.3.2 immer noch zu existieren. Siehe [2] bzw [3].
Bei ADF Faces geht aktuell nur der Weg über Oracle Web-Center und WSRP. Siehe [4].
JSF lieber doch nicht?
Das exzellente Whitepaper [5] von Peter Laird und Tim Breeden – auch wenn es für WebLogic Portal 10.3 geschrieben wurde – gibt einen guten Einblick in die Entwicklung von JSF basierten Portlets. Meiner Meinung nach sollte man diesem Dokument folgen und erst einmal auf ICEfaces verzichten. Des Weiteren kann man hinterfragen, ob alle ICEFaces Controls benötigt werden. Mittels jQuery lässt sich bekannterweise  auch ein gelungenes UI erstellen.
Was machen Projekte in denen hauptsächlich Beehive Erfahrung existiert?
In einem aktuellen Projekt haben wir dies lange mit unserem Kunden diskutiert. Wir haben uns dann dazu entschieden, momentan mit Beehive  zu starten und später auf JSF 2.0, sobald es vom WebLogic Portal unterstützt wird, zu migrieren. Hierbei ist eine klare Trennung von Präsentations- und Businesslogik (in diesem Projekt mittels EJB 3.0) notwendig.

Referenzen:
[1] Oracle WebLogic Portal 10.3.2 Supported Standards
[2] Forums for ICEfaces
[3] Forums for ICEfaces
[4] Configuring Portlets That Use ADF Faces Rich Client Components
[5] Developing JSF Portlets with WebLogic Portal