Übersicht
Durch die Entwicklung eines DataStore-Plugins können Sie Fess um die Fähigkeit zur Inhaltserfassung aus neuen Datenquellen erweitern. Ein DataStore ruft Datensätze aus externen Systemen wie Datenbanken, APIs oder Dateien ab, wandelt sie gemäß dem in der Administrationsoberfläche konfigurierten Mapping-Skript in Indexfelder um und registriert sie anschließend im Index von Fess.
Alle öffentlich verfügbaren Konnektoren (fess-ds-*) für CSV, JSON, Datenbanken, Git und verschiedene Cloud-Dienste sind nach diesem Mechanismus implementiert. Als Implementierungsvorlage steht fess-ds-example zur Verfügung. Beim Erstellen eines neuen Konnektors ist es daher am einfachsten, dieses Repository zu kopieren und darauf aufzubauen.
Grundstruktur
Ein DataStore-Plugin besteht aus den folgenden drei Elementen:
Erstellen einer Klasse, die von
AbstractDataStoreerbtImplementieren der beiden Methoden
getName()undstoreData()Registrieren als Komponente in
fess_ds++.xml
Minimale Implementierung
Bemerkung
getName() und storeData() sind beide protected deklarierte abstrakte Methoden. Beachten Sie, dass sich das Paket von DataConfig in Fess 15.x unter org.codelibs.fess.opensearch.config.exentity befindet (das frühere org.codelibs.fess.es.config.exentity wurde entfernt).
Komponenten-Registrierung
Damit Fess den erstellten DataStore erkennt, wird die Komponente in src/main/resources/fess_ds++.xml registriert.
Durch <postConstruct name="register"> wird nach der Erzeugung der Komponente automatisch die von AbstractDataStore bereitgestellte Methode register() aufgerufen, wodurch sich die Komponente selbst bei DataStoreFactory registriert. Der dabei registrierte Name ist der Rückgabewert von getName() (im obigen Beispiel ExampleDataStore) und entspricht dem „Handler-Name“, der in der Datenspeicher-Konfiguration der Administrationsoberfläche ausgewählt wird.
AbstractDataStore
Wichtige Methoden
| Methode | Kategorie | Beschreibung |
|---|---|---|
getName() | Implementierung (erforderlich) | Abstrakte Methode, die den Handler-Namen des DataStore zurückgibt. Es ist üblich, getClass().getSimpleName() zurückzugeben |
storeData() | Implementierung (erforderlich) | Abstrakte Methode, die Datenabruf, -umwandlung und Index-Registrierung durchführt |
register() | Geerbt (in der Regel keine Änderung nötig) | Wird über postConstruct in fess_ds++.xml automatisch aufgerufen und registriert die Komponente bei DataStoreFactory |
store() | Geerbt (Framework-Aufruf) | Einstiegspunkt, der vom Framework aufgerufen wird. Bereitet u. a. defaultDataMap vor und ruft storeData() auf |
convertValue() | Geerbt (Hilfsmethode) | Wertet den Wert (das Template) aus scriptMap mit der Skript-Engine aus |
getScriptType() | Geerbt (Hilfsmethode) | Ruft den Parameter script_type ab (Standard ist Groovy) |
getReadInterval() | Geerbt (Hilfsmethode) | Ruft den Parameter readInterval (in Millisekunden) ab |
sleep() | Geerbt (Hilfsmethode) | Wartet die angegebene Anzahl an Millisekunden (wird zum Warten zwischen Datensätzen verwendet) |
Parameter von storeData
An die Methode storeData() übergebene Parameter:
| Parameter | Typ | Beschreibung |
|---|---|---|
dataConfig | DataConfig | Datenspeicher-Konfiguration (ID, Handler-Name, Parameter, Skript usw.) |
callback | IndexUpdateCallback | Callback zur Registrierung des erzeugten Dokuments im Index |
paramMap | DataStoreParams | Konfigurationswerte aus dem Feld „Parameter“ der Administrationsoberfläche. Zugriff über getAsString(key) / getAsString(key, default) / get(key) / asMap() / containsKey(key) |
scriptMap | Map<String, String> | Konfiguration aus dem Feld „Skript“ der Administrationsoberfläche. Der Schlüssel ist der Indexfeldname, der Wert das auszuwertende Skript-Template |
defaultDataMap | Map<String, Object> | Standardfeldwerte jedes Dokuments (Konfigurations-ID, Boost, Rolle, MIME-Type, virtueller Host usw.), die vom Framework bereitgestellt werden |
Warnung
Der Typ von paramMap ist nicht Map<String, String>, sondern DataStoreParams. Da DataStoreParams das Interface Map nicht implementiert, verwenden Sie zum Abrufen von Werten nicht get(), sondern getAsString(), das einen String zurückgibt.
Ablauf der Datenverarbeitung
Die Implementierung von storeData() verarbeitet Daten in folgendem Ablauf.
Abrufen der Quelldatensätze aus dem externen System.
Erstellen von
resultMapdurch Zusammenführen der Felder des Quelldatensatzes mitparamMap.asMap()(das Skript wird gegen diesesresultMapausgewertet).Auswerten jedes Eintrags von
scriptMapmitconvertValue(scriptType, template, resultMap)und Speichern des Ergebnisses indataMap. Wichtig ist, dass das Mapping nicht im Code fest verdrahtet ist, sondern vom Administrator im Feld „Skript“ definiert wird.Aufrufen von
callback.store(paramMap, dataMap), um das Dokument im Index zu registrieren.
Implementierungsbeispiel
Einfacher DataStore
Ein Beispiel, das Datensätze von einer externen API abruft und im Index registriert.
fetchRecords() ist eine eigene Methode, die die Liste der Datensätze vom externen System abruft. Die Feldnamen der einzelnen abgerufenen Datensätze (Map<String, Object>) sind die Namen, auf die im Skript von scriptMap verwiesen werden kann. DataStoreException ist eine Klasse aus dem Paket org.codelibs.fess.exception.
Unterstützung für Paginierung
Beim Umgang mit großen Datenmengen erfolgt die Verarbeitung seitenweise. Wenn die Verarbeitung pro Datensatz (Erstellen von resultMap, Auswerten von scriptMap, Aufruf von callback.store()) in eine Methode wie processRecord() ausgelagert wird, lässt sie sich von der Abruflogik trennen.
Implementierung der Authentifizierung
Die Authentifizierung gegenüber dem externen System wird auf Seiten des Konnektors implementiert. Das folgende Beispiel verwendet eine gängige HTTP-Client-Bibliothek und ist keine von Fess bereitgestellte API. Binden Sie die verwendete Bibliothek als Abhängigkeit des Plugins ein.
OAuth 2.0
API-Key-Authentifizierung
Fehlerbehandlung
Bei fatalen Fehlern, die die Verarbeitung abbrechen sollen, wird DataStoreException geworfen.
Bemerkung
Bei tatsächlichen Konnektoren wie fess-ds-example wird CrawlingAccessException pro Datensatz abgefangen, damit ein Fehler bei einem einzelnen Datensatz nicht den gesamten Crawl-Vorgang stoppt; die fehlerhafte URL wird dabei bei FailureUrlService protokolliert. Außerdem wird über das Abbruch-Flag von DataStoreCrawlingException gesteuert, ob der gesamte Crawl-Vorgang abgebrochen werden soll. Wenn Sie einen robusten Konnektor implementieren möchten, orientieren Sie sich an der Implementierung von ExampleDataStore.
Tests
Unit-Tests
Fess-Plugins werden mit LastaDiTestCase aus UTFlute getestet. Die Tests werden mit JUnit 5 (Jupiter) geschrieben. Indem IndexUpdateCallback durch eine Implementierung ersetzt wird, die die registrierten dataMap-Werte sammelt, lässt sich das Mapping-Ergebnis ohne Mock-Bibliothek überprüfen.
Bemerkung
Da setUp in der Basisklasse bereits mit @BeforeEach versehen ist, muss beim Überschreiben keine Lifecycle-Annotation erneut hinzugefügt werden. Jeder Testmethode wird @Test (org.junit.jupiter.api.Test) hinzugefügt.
Build und Installation
pom.xml
Das Plugin wird als jar mit fess-parent als übergeordnetem POM gebaut. Die Abhängigkeiten von fess und opensearch werden zur Laufzeit von Fess selbst bereitgestellt und daher als provided deklariert.
Für Tests werden JUnit 5 und org.dbflute.utflute:utflute-lastaflute verwendet.
Build
Im Verzeichnis target/ wird fess-ds-example-15.8.0.jar erzeugt.
Installation
Installieren Sie das erzeugte JAR in Fess und starten Sie Fess neu. Details zum Installationsvorgang finden Sie unter Plug-ins. Erstellen Sie nach der Installation über „Crawler > Datenspeicher“ in der Administrationsoberfläche eine neue Konfiguration und geben Sie als „Handler-Name“ den von getName() zurückgegebenen Namen an (in diesem Beispiel ExampleDataStore).
Konfigurationsbeispiel
Konfigurationsbeispiel in der Administrationsoberfläche:
Parameter
Im Feld „Parameter“ werden die Schlüssel und Werte angegeben, die der Konnektor aus paramMap ausliest.
Skript
Im Feld „Skript“ wird das Mapping im Format linke Seite=rechte Seite angegeben. Die linke Seite ist der Indexfeldname, die rechte Seite ein Skript (standardmäßig Groovy), das auf ein Feld des Quelldatensatzes verweist. Das folgende Beispiel gilt für den Fall, dass der Quelldatensatz die Felder url / title / content / updated_at / content_type besitzt.
Bemerkung
Welche Feldnamen auf der rechten Seite referenziert werden können, hängt von den Werten ab, die der Konnektor in resultMap ablegt (Werte aus paramMap und Felder des Quelldatensatzes). Bei bestehenden Konnektoren wie CSV oder JSON kann ein eigenes Präfix wie data.* vorangestellt sein; weitere Details finden Sie in der Dokumentation des jeweiligen Konnektors.
Referenzinformationen
Plugin-Architektur - Plugin-Architektur
Plug-ins - Plugin-Installation
Übersicht der Datenspeicher-Konnektoren - Übersicht der Datenspeicher-Konnektoren
fess-ds-example - Implementierungsvorlage für DataStore-Plugins
GitHub: fess-ds-* - Beispiele veröffentlichter Konnektoren