Fusion und JavaScript: Gemeinsame Skripte, Utility-Funktionen und Unit-Tests
Lernen Sie, wie Sie JavaScript in die Pipeline Stages von Fusion laden können und entdecken Sie verschiedene praktische Funktionen.
Übersicht
Lucidworks Fusion verwendet ein Daten-Pipeline-Paradigma sowohl für die Dateneingabe (Index-Pipelines) als auch für die Suche (Query Pipelines). Eine Pipeline besteht aus einer oder mehreren geordneten Pipeline-Stufen. Jede Stufe nimmt Eingaben von der vorhergehenden Stufe auf und liefert Eingaben an die folgende Stufe. Im Fall der Index-Pipeline ist die Eingabe ein Dokument, das vor der Indizierung in Apache Solr umgewandelt werden muss.
Im Fall von Query Pipelines manipulieren die ersten Stufen eine Abfrageanfrage. Eine mittlere Stufe übergibt die Anfrage an Solr und die folgenden Stufen können zur Bearbeitung der Abfrageantwort verwendet werden.
Die in Lucidworks Fusion enthaltenen Out-of-the-Box-Phasen ermöglichen es dem Benutzer, viele gängige Aufgaben auszuführen, wie z.B. die Feldzuordnung für eine Index-Pipeline oder spezielle Facettenabfragen für die Query-Pipeline. Wie in einem früheren Artikel beschrieben, haben viele Projekte jedoch spezielle Anforderungen, für die die Flexibilität der JavaScript-Stage benötigt wird.
Die Codeschnipsel in diesem Artikel wurden der Einfachheit halber vereinfacht und gekürzt. Die vollständigen Beispiele können Sie von meinem GitHub Repo https://github.com/andrewshumway/FusionPipelineUtilities herunterladen .
JavaScript auf die nächste Stufe bringen mit Shared Scripts, Utility-Funktionen und Unit-Tests
Es ist schön und gut, ein paar Skripte in eine Pipeline einzubauen, um benutzerdefinierte Lookups oder Parsing-Logik durchzuführen, aber anspruchsvolle Ingestion-Strategien könnten von einigen fortgeschritteneren Techniken profitieren.
- Reduzieren Sie Wartungsprobleme durch die Wiederverwendung häufig benötigter Dienstprogramme und Funktionen. Einige der fortschrittlichen Funktionen der Nashorn JavaScript-Engine machen das Kopieren/Einfügen von Code in mehrere Pipelines weitgehend überflüssig. Die Beibehaltung einer einzigen Kopie verringert die Probleme bei der Codepflege.
- Verwenden Sie eine moderne IDE für die Bearbeitung. Der Code-Editor in Fusion ist zwar funktional, bietet aber wenig Hilfe bei der Code-Vervollständigung, der Syntax-Hervorhebung, der Erkennung von Tippfehlern, der Beleuchtung globaler Variablen oder der allgemeinen Beschleunigung der Entwicklung.
- Verwenden Sie Unit-Tests, um Bugs zu reduzieren und die Funktionsfähigkeit eines Deployments sicherzustellen.
Skripte wiederverwenden
Lucidworks Fusion verwendet die standardmäßige Nashorn JavaScript-Engine, die mit Java 8 ausgeliefert wird. Der Befehl load(), kombiniert mit einem Immediately Invoked Function Expression (IIFE), ermöglicht es einem kleinen Pipeline-Skript, ein anderes Skript zu laden. Dies ermöglicht die gemeinsame Nutzung von Funktionen in verschiedenen Pipelines. Hier ist ein Beispiel:
var loadLibrary = function(url){ var lib = null; try{ logger.info('nn*********n*Try to library load from: ' + url); lib = load(url);// jshint ignore:line logger.info('nn**********n* The library loaded from: ' + url); }catch(e){ logger.error('nn******n* The script at ' + url + ' is missing or invalidn’ + e.message); } return lib; };
Hilfe von einer IDE erhalten
Jede Art von JavaScript-Funktion oder -Objekten kann in der utilLib.js enthalten sein, wie oben gezeigt. Unten sehen Sie ein einfaches Beispiel für eine Bibliothek, die zwei praktische Funktionen enthält.
Erklärende Hinweise:
- Die Wrapping-Struktur, d.h. (function(){…}).call(this); bildet die IIFE-Struktur, mit der das util-Objekt gekapselt wird. Dies ist zwar nicht unbedingt erforderlich, bietet aber eine Syntax, die von der IntelliJ IDE leicht verstanden wird.
- Der globals-Kommentar am oberen Rand sowie der jshint-Kommentar am unteren Rand sind Hinweise für die in der IDE verwendete JSHint-Codevalidierungsmaschine. Diese unterdrücken Fehlerbedingungen, die sich aus der Nashorn load()-Funktionalität und globalen Variablen ergeben, die von der Java-Umgebung gesetzt werden, die die JavaScript Pipeline Stage aufruft.
- Die IDE wird potenziell illegalen Code rot unterstrichen haben. So können Sie Tippfehler korrigieren, ohne das Skript wiederholt testen und eine Protokolldatei durchforsten zu müssen, nur um eine kryptische Fehlermeldung der Nashorn-Engine zu finden. Beachten Sie auch die Verwendung der Anweisung „use strict“. Dadurch wird JSHint angewiesen, auch nach Dingen wie der versehentlichen Deklaration von globalen Variablen zu suchen.
/* globals Java,arguments*/ (function(){ "use strict"; var util = {}; util.isJavaType = function(obj){ return (obj && typeof obj.getClass === 'function' && typeof obj.notify === 'function' && typeof obj.hashCode === 'function'); } /** * For Java objects, return the short name, * e.g. 'String' for a java.lang.String * * JavaScript objects, usually use lower case. * e.g. 'string' for a JavaScript String * */ util.getTypeOf = function getTypeOf(obj){ 'use strict'; var typ = 'unknown'; //test for java objects if( util.isJavaType(obj)){ typ = obj.getClass().getSimpleName(); }else if (obj === null){ typ = 'null'; }else if (typeof(obj) === typeof(undefined)){ typ = 'undefined'; }else if (typeof(obj) === typeof(String())){ typ = 'string'; }else if (typeof(obj) === typeof([])) { typ = 'array'; } else if (Object.prototype.toString.call(obj) === '[object Date]'){ typ = 'date'; }else { typ = obj ? typeof(obj) :typ; } return typ; }; //return util to make it publicly accessible return util; }).call(this); // jshint ignore: line
Überblick über die Nutzenfunktionen
Im Folgenden finden Sie eine zusammenfassende Beschreibung einiger der in utilLib.js enthaltenen Hilfsfunktionen
index.concatMV(doc, feldname, delim) Gibt eine abgegrenzte Zeichenkette mit allen Werten für ein bestimmtes Feld zurück. Wenn das Feld „Namen“ Werte für „James“, „Jim“, „Jamie“ und „Jim“ enthält, würde der Aufruf von index.concatMV(doc, „Namen“, ‚, ‚) „James, Jim, Jamie“ zurückgeben.
index.getFieldNames(doc, pattern) Gibt ein Array von Feldnamen in doc zurück, die dem regulären Ausdruck pattern entsprechen.
index.trimField(doc, fieldName) Entfernt alle Leerzeichen aus allen Werten des angegebenen Feldes. Führende und abschließende Leerzeichen werden abgeschnitten und überflüssige Leerzeichen innerhalb von Werten werden durch ein einzelnes Leerzeichen ersetzt.
util.concat(varargs) Hier kann varargs ein oder mehrere Argumente von String oder String[] sein. Sie werden alle zu einem einzigen String konkateniert und zurückgegeben.
util.dateToISOString(date) Konvertiert ein Java-Datum oder JavaScript-Datum in einen ISO 8601-formatierten String.
util.dedup(arr) Entfernt überflüssige Elemente in einem Array.
util. decrypt(toDecrypt) Entschlüsselt einen AES-verschlüsselten String.
util. encrypt(toEncrypt) Verschlüsselt einen String mit AES-Verschlüsselung.
util. getFusionConfigProperties() Liest die Standarddatei Fusion config/config.properties ein und gibt sie als Java Properties-Objekt zurück.
util.isoStringToDate(dateString) Konvertiert einen ISO 8601-formatierten String in ein Java-Datum.
util. queryHttp2Json(url) Führt einen HTTP GET auf eine URL aus und parst die Antwort in JSON.
util.stripTags(markupString) Entfernt Markup-Tags aus einem HTML- oder XML-String.
util.truncateString(text, len, useWordBoundary) Schneidet Text auf eine Länge von len ab. Wenn useWordBoundary true ist, wird an der Wortgrenze kurz vor len abgebrochen.
Testen des Codes
Automatisierte Unit-Tests von Fusion-Stages können kompliziert sein. Unit-Tests für gemeinsam genutzte Utility-Funktionen, die für die Verwendung in Fusion-Stages vorgesehen sind, sind sogar noch schwieriger. Ein vollständiges Test-Harness würde den Rahmen dieses Blogs sprengen, aber das Wesentliche lässt sich mit dem Kommandozeilen-Dienstprogramm curl oder einem REST-Client wie Postman bewerkstelligen.
- Beginnen Sie mit einem bekannten Zustand in Form eines vorgefertigten PipelineDocuments. Um ein Beispiel für das benötigte JSON zu sehen, schauen Sie sich an, was von der Logging Stage, die mit Fusion geliefert wird, produziert wird.
- POSTen Sie das PipelineDocument Fusion mit der Index Pipelines API. Sie müssen eine ID und einen Sammlungsnamen als Parameter sowie den abschließenden Pfad „/index“ übergeben, um die Pipeline aufzurufen.
- Die POST-Operation sollte das Dokument so zurückgeben, wie es von der Pipeline geändert wurde. Prüfen Sie es und signalisieren Sie bei Bedarf Pass- oder Fail-Ereignisse.
Unit-Tests können auch manuell durchgeführt werden, indem Sie die Pipeline in Fusion ausführen. Dies kann Teil einer Workbench-Simulation oder eines tatsächlichen Ingestion/Abfragevorgangs sein. Die utilLib.js enthält ein rudimentäres Test-Harness für die Ausführung von Tests und den Vergleich der Ergebnisse mit einem erwarteten String-Wert. Die Ergebnisse der Tests werden sowohl in das connections.log oder api.log geschrieben als auch in die Kontext-Map der Stage in das Element _runtime_test_results eingefügt, wie unten gezeigt. Der erste Test zeigt, dass util.dedup(‚a‘, ‚b‘, ‚c‘, ‚a‘, ‚b‘), aber die Ergebnisse keine Duplikate enthalten. Andere allgemeine Tests werden ebenfalls durchgeführt. Alle Einzelheiten finden Sie in der Funktion index.runTests() in utilLib.js.
Zusammenfassung
Dieser Artikel zeigt Ihnen, wie Sie gemeinsam nutzbare JavaScript-Funktionen in die Pipeline-Stages von Fusion laden können, so dass gemeinsame Funktionen in allen Pipelines genutzt werden können. Er enthält auch mehrere praktische Hilfsfunktionen, die als solche oder als Bausteine für komplexere Datenmanipulationen verwendet werden können. Außerdem wurde gezeigt, wie Sie häufige Fallstricke wie JavaScript-Syntaxfehler und unbeabsichtigte globale Variablen vermeiden können. Abschließend wurde eine Pipeline-Simulation durchgeführt und die Ergebnisse des Unit-Tests gezeigt.
Danksagung
Besonderen Dank an Carlos Valcarcel und Robert Lucarini von Lucidwoks sowie Patrick Hoeffel und Matt Kuiper von Polaris Alpha für ihre Hilfe und Beispielskripte.