# 7.9 Automatisierung Die Systemarchitektur von OpenRefine macht es möglich, die Anwendung nicht nur über die grafische Oberfläche, sondern auch über eine API "fernzusteuern". Im Punkt zur Systemarchitektur in der [Dokumentation für Entwickler](https://github.com/OpenRefine/OpenRefine/wiki/Documentation-For-Developers) heißt es: >"And it's possible to make the server-side scriptable from the command line." Das machen wir uns zunutze. Die [HTTP-API von OpenRefine](https://github.com/OpenRefine/OpenRefine/wiki/OpenRefine-API) kann theoretisch auch direkt angesprochen werden, aber da sie nur rudimentär dokumentiert ist, nutzen wir einen der verschiedenen Clients, die andere schon gegen die HTTP-API von OpenRefine entwickelt haben. Es gibt Clients in Python, Ruby, node.js, PHP und für R. Am ausgereiftesten ist der [Python-Client von Paul Makepeace](https://github.com/PaulMakepeace/refine-client-py/). Der Client kann ebenso wie OpenRefine lokal installiert werden. Um die Installation und Bedienung zu vereinfachen, habe ich einen Docker-Container gebaut (vgl. [Repository felixlohmeier/openrefine in Docker Hub](https://hub.docker.com/r/felixlohmeier/openrefine/)). ## Aufgabe 1: Starten Sie den Python-Client und geben Sie eine Liste der Projekte aus Hinweise: * Die Bedienung ist im Abschnitt "**batch processing with python-client**" im [Repository in Docker Hub](https://hub.docker.com/r/felixlohmeier/openrefine/)) beschrieben. Schauen Sie sich die unter der Überschrift "example for customized run command in interactive mode (e.g. for usage in terminals)" gelisteten Docker-Startbefehle an und wandeln Sie diese so ab, dass sie mit den Parametern im [Kapitel 6.3](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/06_3_openrefine_starten_und_daten_laden.html) beschriebenen Docker-Startbefehl zusammen passen. * Starten Sie Putty zweimal und bauen Sie jeweils eine SSH-Verbindung auf. Dann können Sie den Server im ersten Putty-Fenster (nennen wir dies im Folgenden Terminal 1) starten und den Client im Zweiten (nennen wir dies im Folgenden Terminal 2). ## Lösung * Terminal 1: Server starten: {%s%}sudo docker run --name=refine-server --rm -p 8888:3333 -v /home/stud/refine:/data felixlohmeier/openrefine:2.6rc1 -i 0.0.0.0 -m 3G -d /data{%ends%} * Terminal 2: Python-Client: {%s%}sudo docker run --link refine-server --rm -v /home/stud/refine:/data felixlohmeier/openrefine:client-py{%ends%} ## Aufgabe 2: Wenden Sie die in Kap. 7.3 gespeicherten Transformationsregeln auf ein neues Projekt an Hinweise: * Erstellen Sie ein neues Projekt auf gewohnte Weise (vgl. [Kapitel 6.3](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/06_3_openrefine_starten_und_daten_laden.html), Aufgabe 2) * Nutzen Sie entweder Ihre selbst erstellten Transformationsregeln aus [Kapitel 7.3](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/07_3_fuer_jedes_marc-feld_eine_spalte.html) oder die aus der folgenden Datei: [07_3.json](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/openrefine/07_3.json). Speichern Sie diese Transformationsregeln in einer Datei auf dem Webserver, z.B. **a)** über die Zwischenablage mit ```nano``` (vgl. [Kapitel 3.5](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/03_5_uebung_text_ueber_die_konsole_erstellen.html)) ** oder **b)** laden Sie die Datei mit ```curl``` (vgl. [Kapitel 4.2](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/04_2_uebung_unapi-schnittstelle_des_gbv.html). Die Datei muss im Arbeitsverzeichnis liegen (in unserem Beispiel also in ```/home/stud/refine/```). ## Lösung * Terminal 1 - Server starten: {%s%}sudo docker run --name=refine-server --rm -p 8888:3333 -v /home/stud/refine:/data felixlohmeier/openrefine:2.6rc1 -i 0.0.0.0 -m 3G -d /data{%ends%} * Browser: {%s%}OpenRefine aufrufen und ein neues Projekt erstellen (vgl. Kapitel 6.3, Aufgabe 2){%ends%} * Terminal 2 - Projekte auslesen: {%s%}sudo docker run --link refine-server --rm -v /home/stud/refine:/data felixlohmeier/openrefine:client-py{%ends%} * Terminal 2 - Projekt-ID notieren: {%s%}Notieren Sie die Nummer des gerade erstellten Projekts{%ends%} * Terminal 2 - Transformationsdatei erstellen (hier Variante b mit curl): {%s%}curl https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/openrefine/07_3.json > /home/stud/refine/07_3.json {%ends%} * Terminal 2 - Transformationen anwenden (1234567890123 durch Projekt-ID ersetzen): {%s%}sudo docker run --link refine-server --rm -v /home/stud/refine:/data felixlohmeier/openrefine:client-py -f 07_3.json 1234567890123{%ends%} ## Aufgabe 3: Exportieren Sie mit dem Python-Client die Daten aus einem Projekt als TSV Hinweise: * Auch der dafür notwendige Befehl ist im [Repository in Docker Hub](https://hub.docker.com/r/felixlohmeier/openrefine/)) beschrieben. ## Lösung * Terminal 1 - Server starten: {%s%}sudo docker run --name=refine-server --rm -p 8888:3333 -v /home/stud/refine:/data felixlohmeier/openrefine:2.6rc1 -i 0.0.0.0 -m 3G -d /data{%ends%} * Terminal 2 - Daten exportieren (1234567890123 durch Projekt-ID aus Aufgabe 2 ersetzen): {%s%}sudo docker run --link refine-server --rm -v /home/stud/refine:/data felixlohmeier/openrefine:client-py 1234567890123 -E --output=test.tsv 1234567890123{%ends%} * Terminal 2 - Daten anzeigen: {%s%}cat test.tsv | more{%ends%} ## Aufgabe 4: Schreiben Sie ein Shell-Script, dass Server und Client startet, die Transformation durchführt und dann die Daten als TSV exportiert Hinweise: * Schauen Sie sich die Grundlagen für Shell-Scripte in [Kapitel 4.4](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/04_4_download_der_metadaten.html), Aufgabe 3 nochmal an. * Shell-Scripte führen die im Script enthaltenen Befehle Zeile für Zeile einen nach dem anderen aus, sobald der vorige Befehle abgeschlossen ist. Bislang haben wir den OpenRefine-Server im interaktiven Modus gestartet, d.h. der Startbefehl kommt nie von alleine zu Ende und würde die Bearbeitung des restlichen Teils vom Script blockieren. Verwenden Sie daher im Startbefehl des Servers den Parameter ```-d``` anstelle von ```--rm```. Der Server läuft dann endlos im Hintergrund. Sie müssen ihn abschließend manuell beenden mit dem Befehl ```sudo docker stop refine-server```` und löschen mit ```sudo docker rm refine-server``` * Der Docker-Container mit dem Server muss vollständig gestartet sein, bevor Sie den Client starten können, denn sonst liefe der ins Leere. Daher sollten Sie eine gewisse Wartezeit einbauen, z.B. mit dem Befehl ```sleep 15```. * Verwenden Sie ein neues Projekt für Ihre Tests. Wenn Sie Transformationsregeln ein zweites Mal auf ein Projekt anwenden, dann laufen die Transformationen auf den bereits transformierten Daten ab. Das führt mit Sicherheit zu unerwünschten Ergebnissen. ## Lösung Erläuterungen folgen direkt in den Skripten mit ```#```. Die erste Variante ist der einfachere Lösungsweg, aber nicht so komfortabel. Verwenden Sie Variante 2, wenn Sie damit arbeiten wollen. ### Variante 1: Transformations+Export-Script "minimal" ``` #!/bin/bash # Script zur Transformation und zum Export von Projekten mit OpenRefine # Variante "minimal", Stand: 18.11.2016 # Voraussetzungen: # 1. Docker # 2. OpenRefine-Projekte im Arbeitsverzeichnis /home/stud/refine # 3. Transformationsdatei 07_3.json im Ordner /home/stud/refine # 4. IDs der zu verarbeitenden Projekte im Script definiert # Definieren Sie hier die Projekte, die verarbeitet werden sollen! # Geben Sie dazu die vierzehnstelligen Projektnummern von OpenRefine in die Klammern ein. # Mehrere Projekte werden mit Leerzeichen getrennt. projects=(01234567890123 12345678901234) # Server starten und 15 Sekunden warten sudo docker run -d --name=refine-server -p 8888:3333 -v /home/stud/refine:/data felixlohmeier/openrefine:2.6rc1 -i 0.0.0.0 -m 3G -d /data sleep 15 # Anfang der Schleife für die definierten Projekte for projectid in "${projects[@]}" ; do # Transformationen durchführen sudo docker run --rm --link refine-server -v /home/stud/refine:/data felixlohmeier/openrefine:client-py -f 07_3.json ${projectid} # Daten exportieren sudo docker run --rm --link refine-server -v /home/stud/refine:/data felixlohmeier/openrefine:client-py -E --output=${projectid}.tsv ${projectid} # Ende der Schleife für die definierten Projekte done # Server beenden und Container löschen sudo docker stop refine-server sudo docker rm refine-server exit ``` **Ausführen:** * Diesen Textinhalt in einer Datei abspeichern, z.B. mit ```nano transform+export-minimal.sh``` * IDs der zu verarbeitenden Projekte in der sechsten Zeile des Scripts eingeben: ```nano transform+export-minimal.sh``` * Script ausführbar machen: ```chmod +x transform+export-minimal.sh``` * Transformationsdatei 07_3.json in das Arbeitsverzeichnis laden, falls noch nicht vorhanden: ```curl https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/openrefine/07_3.json > /home/stud/refine/07_3.json``` * Script starten mit ```./transform+export-minimal.sh``` ### Variante 2: Transformations+Export-Script "Komfort" Wie Variante 1 mit folgenden Verbesserungen: * Die IDs der zu verarbeitenden Projekte können nun an den Befehl zum Aufruf des Scripts angehängt werden. Wenn keine Projekt-IDs angegeben werden, dann werden diejenigen Projekte verarbeitet, deren Name mit ```TRANSFORM``` beginnt. Dazu werden die vorhandenen Projekte ausgelesen und daraus die Projektnummern mit einem grep-Befehl ausgefiltert und in eine Variable geschrieben. * Die anzuwendenden Transformationsdateien werden zu Beginn in einer Variable ```jsonfiles``` definiert (und können direkt im Script geändert werden). Das Script wendet diese Transformationsdateien in der genannten Reihenfolge auf alle zu verarbeitenden Projekte an. * Das Script lädt selbsttätig die aktuellen Transformationsdateien aus dem Script in Gitbook, d.h. aus dem Verzeichnis https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/openrefine/ in das Arbeitsverzeichnis von OpenRefine und überschreibt ggf. gleichlautende Dateien. * Statt der festen Wartezeit (sleep 15) erfolgt eine Abfrage, ob der Server erreichbar ist, bevor das Script fortschreitet. Das beschleunigt die Verarbeitung, wenn der Server schneller als in 15 Sekunden startet und beugt Fehlern vor, falls der Server ausgelastet ist und mal länger als 15 Sekunden braucht. * Am Ende werden zur Erfolgskontrolle die exportierten TSV-Dateien ausgegeben. * Das Script gibt die Konfigurationswerte sowie regelmäßig Start- und Endzeitpunkte aus. * Arbeitsverzeichnis, Port und maximaler Arbeitsspeicher für den OpenRefine-Server werden zu Beginn als Variable definiert (Standard: ```/home/stud/refine/```, ```8888```, ```3G```), was eine Anpassung später leichter macht. ``` #!/bin/bash # Script zur Transformation und zum Export von Projekten mit OpenRefine # Variante "Komfort", Stand: 18.11.2016 # # Voraussetzungen: # 1. Docker # 2. OpenRefine-Projekte im Arbeitsverzeichnis # # Nutzung Variante A) # IDs der zu verarbeitenden Projekte an den Startbefehl anhängen. # Beispiel: ./transform+export.sh 01234567890123 1234567890123 # # Nutzung Variante B) # Codewort TRANSFORM manuell in OpenRefine in den Namen der zu verarbeitenden Projekten aufnehmen # und Script ohne weitere Parameter starten. # Beispiel: ./transform+export.sh # # Transformationen aus den folgenden Dateien werden (in dieser Reihenfolge) durchgeführt # (bei Bedarf direkt hier im Script ändern) jsonfiles=(07_3.json test.json) # Weitere Programmvariablen workdir="/home/stud/refine" port=8888 ram=3G # Variablen ausgeben echo "Transformationsdateien: " ${jsonfiles} echo "Arbeitsverzeichnis: " ${workdir} echo "OpenRefine auf Port: " ${port} echo "OpenRefine max. RAM: " ${ram} echo "" # Startzeitpunkt ausgeben echo "Startzeitpunkt: $(date)" echo "" # Transformationsdateien ins Arbeitsverzeichnis laden echo "Transformationsdateien herunterladen..." cd ${workdir} for jsonfile in "${jsonfiles[@]}" ; do curl -O https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/openrefine/${jsonfile} done cd - > /dev/null echo "" # Server starten echo "Server starten..." sudo docker run -d --name=refine-server -p ${port}:3333 -v ${workdir}:/data felixlohmeier/openrefine:2.6rc1 -i 0.0.0.0 -m ${ram} -d /data echo "" # Warten bis Server vollständig gestartet ist until curl --silent http://localhost:${port} | grep -q -o "OpenRefine" >/dev/null ; do sleep 1; done # Abfrage der Projekt-IDs, wenn mit dem Startbefehl keine benannt wurden if [ -z "$1" ] then echo "Es wurden beim Aufruf des Scripts keine Projekt-IDs benannt." echo "" echo "Projekt-IDs auslesen..." projects=($(sudo docker run --rm --link refine-server -v ${workdir}:/data felixlohmeier/openrefine:client-py | grep "TRANSFORM" | cut -c 2-14)) if [ -z "$projects" ] then echo "*** Es konnten keine Projekte gefunden werden! ***" echo "" echo "Sie haben zwei Möglichkeiten Projekte zur Verarbeitung zu benennen:" echo "1. an den Startbefehl des Scripts die IDs der zu verarbeitenden Projekte anhängen" echo "Beispiel: ./transform+export.sh 01234567890123 1234567890123" echo "" echo "2. Das Codewort TRANSFORM manuell in OpenRefine in den Namen der zu verarbeitenden Projekten aufnehmen und das Script erneut starten." echo "" echo "Server beenden und Container löschen..." sudo docker stop refine-server sudo docker rm refine-server exit else echo "Folgende Projekte im Arbeitsverzeichnis tragen das Codewort TRANSFORM im Namen:" echo ${projects[@]} echo "" fi else echo "Folgende Projekt-IDs wurden beim Aufruf des Script benannt:" projects=($*) echo ${projects[@]} echo "" fi # Schleife für Transformation und Export der Projekte for projectid in "${projects[@]}" ; do echo "Start Projekt $projectid @ $(date)" # Transformationen durchführen for jsonfile in "${jsonfiles[@]}" ; do echo "Transformiere mit ${jsonfile}..." sudo docker run --rm --link refine-server -v ${workdir}:/data felixlohmeier/openrefine:client-py -f ${jsonfile} ${projectid} done # Daten exportieren echo "Exportiere in ${projectid}.tsv" sudo docker run --rm --link refine-server -v ${workdir}:/data felixlohmeier/openrefine:client-py -E --output=${projectid}.tsv ${projectid} echo "Ende Projekt $projectid @ $(date)" echo "" done # Server beenden und Container löschen echo "Server beenden und Container löschen..." sudo docker stop refine-server sudo docker rm refine-server # Endzeitpunkt ausgeben echo "Endzeitpunkt: $(date)" echo "" # Liste der exportierten Dateien echo "Folgende Dateien wurden erfolgreich exportiert:" echo "(Anzahl der Zeilen und Dateigröße in Bytes)" wc -l -c ${workdir}/*.tsv exit ``` Script als Datei: [transform+export.sh](https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/scripte/transform+export.sh) **Ausführen:** * Script mit ```curl``` auf den Server laden: ```curl -O https://felixlohmeier.gitbooks.io/seminar-wir-bauen-uns-einen-bibliothekskatalog/content/scripte/transform+export.sh``` * Script ausführbar machen: ```chmod +x transform+export.sh``` * Script starten mit ```./transform+export.sh``` ## Literatur * Die [FAQ aus der OpenRefine Dokumentation](https://github.com/OpenRefine/OpenRefine/wiki/FAQ) behandeln auch, wie OpenRefine programmatisch als Server genutzt werden kann.