Zum Hauptinhalt springen

Indexing-Services

Einleitung

Ein Indexing-Service ist eine spezielle SmartIndexing-Regel, die die Verarbeitung des Textes an ein eigenes, in Python 3.6 programmiertes Plugin weiterleitet.

Die Python-Module müssen im Unterverzeichnis customisation\indexingservices des Installations-Verzeichnisses abgelegt werden und die Endung .py haben.

Wenn Documents z.B. in C:\Programme\PHOENIX_Documents installiert ist, befindet sich der Indexing-Service mymodule in der Datei C:\Programme\PHOENIX_Documents\customisation\indexingservices\mymodule.py.

Jeder Indexing-Service kann durch eine Konfigurationsdatei weiter angepasst werden.

Wenn sich neben der Datei mymodule.py noch eine INI-Datei mymodule.ini befindet, wird diese automatisch eingelesen und im Python-Modul bereitgestellt.

Damit ein Indexing-Service in der Applikation ausgewählt und verwendet werden kann, muss er über eine eigene Regel in der smartindexing.xml registriert werden:

xml

<option id="mymodule" name="Mein Indexing-Service">
<rule>service: "mymodule", group=1</rule>
</option>

Das Attribut id muss in der smartindexing.xml eindeutig sein und sollte nicht mehr verändert werden, sobald diese Regel in mindestens einem Archiv ausgewählt ist.

name ist der Name, der im SmartIndexing-Auswahldialog angezeigt wird.

Die Regel muss vom Typ service sein und benötigt als ersten Parameter den Namen des Moduls (d.h. den Namen der Python-Datei ohne die Erweiterung .py). String-Parameter müssen in doppelten Anführungszeichen stehen.

Optional und durch Kommas getrennt folgen Parameter, die an den Indexing-Service durchgereicht werden.


Aufbau eines Indexing-Services

Das folgende Beispiel ist ein minimaler Indexing-Service.

Das Python-Modul muss eine Klasse mit dem Namen IndexingService enthalten, die eine Methode process enthält:

python

import regex

class IndexingService:
"""
IndexingService, der die erste im Text vorkommende Zahl zurückgibt.
"""
def process(self, **kwargs):
text = self.get_text()
match = regex.search(r'(\d+)', text)
if match:
return [match.group(1)]

Die Methode process muss eine Liste von Ergebnissen zurückgeben, wobei einzelne Ergebnisse als umso wichtiger angesehen werden, je weiter vorne sie in der Liste stehen. Wenn es keine Ergebnisse gibt, kann die Methode anstelle eine leeren Liste auch None zurückgeben.

In **kwargs sind die zusätzlichen Parameter der smartindexing.xml enthalten, in der obigen Beispielkonfiguration also der Parameter group mit dem Wert 1.

Die Klasse stellt mehrere Methoden bereit, um an die zu verarbeitenden Daten zu gelangen:

self.get_file()

Der absolute Pfad der zu verarbeitenden Datei, die sich normalerweise in einem temporären Verzeichnis befindet. Der Indexing-Service muss damit umgehen können, dass der Rückgabewert auch None sein kann, da es für Clients grundsätzlich möglich (und bei älteren Clients auch üblich) ist, direkt Text und keine Datei zu übergeben.

self.get_filename()

Der der Name der zu verarbeitenden Datei. Normalerweise ist das der basename() von get_file(), d.h. der Dateiname ohne den absoluten Pfad. Jedoch kann der Dateiname auch bei einer reinen Textübergabe vom Client mit angegeben werden. Genau wie bei get_file() muss damit gerechnet werden, dass der zurückgegebene Wert None ist.

self.get_text()

Der in der Datei enthaltene Text, sofern der Server die Möglichkeit hat, diesen zu extrahieren (z.B. bei PDF- oder DOCX-Dateien) oder der Client den Text direkt übergeben hat. Wenn kein Text existiert, wird None oder ein leerer String zurückgegeben.

Im Indexing-Service können beliebige Module aus der Python-Standardbibliothek importiert werden. Für reguläre Ausdrücke steht nebem den Stand-Modul re auch noch das mächtigere regex-Modul (https://pypi.org/project/regex/) zur Verfügung, das im obigen Beispiel verwendet wird.


Konfiguration

Die zu mymodule.py gehörende Konfigurationsdatei mymodule.ini kann in der Klasse IndexingService über self.config benutzt werden. self.config ist ein configparser.ConfigParser-Objekt (aus der Python-Standard-Library) und ist leer, falls keine INI-Datei vorhanden ist.


Datenbankzugang

ODBC

Es ist möglich, innerhalb der process-Methode über ODBC auf externe Datenbanken zuzugreifen.

Eine ODBC-Datenquelle kann über die Sektion Database in der zum Modul gehörenden INI-Datei einfach konfiguriert werden:

ini

[Database]
DSN = MY_DSN
UID = user
PWD = password

Anschließend kann über self.database mithilfe des with-Statements eine Verbindung aufgebaut werden:

python

with self.database() as conn:
sql = 'SELECT data FROM mydata WHERE ID = {}'.format(documentId)
cursor = conn.cursor()
cursor.execute(sql)
value = cursor.fetchone()[0]
# ...

Sollten Daten verändert werden, muss die Transaktion mit conn.commit() abgeschlossen werden. Beim Verlassen des with-Blocks wird die Datenbankverbindung automatisch geschlossen.

Intern wird für die Datenbankverbindungen PyODBC benutzt. Sollte innerhalb eines Archivierungsvorgangs Zugriff auf mehr als eine externe Datenbank benötigt werden, muss PyODBC direkt verwendet werden.


Documents-Datenbank

Unter self.engine wird ein Objekt bereitgestellt, mit dem man ohne weitere Konfiguration eine direkte Verbindung zur PostgreSQL-Datenbank von PHOENIX Documents aufbauen kann. Es handelt sich dabei um ein Engine-Objekt von SQLAlchemy.

Mit self.engine.connect() kann eine Verbindung aufgebaut werden, es wird jedoch empfohlen, ein with-Statement mit einer impliziten Transaktion zu verwenden:

python

# Verbindung aufbauen
with self.engine.begin() as conn:
conn.execute(...)

Wenn innerhalb des with-Blocks eine Exception ausgelöst wird, gibt es automatisch einen Rollback. Wenn es keine Fehler gibt, wird automatisch ein Commit durchgeführt.

Mit der execute-Methode des Connection-Objekts können Statements ausgeführt werden.

Für Prepared Statements muss die Funktion sqlalchemy.sql.text werden, in der die dynamischen Parameter mit einem vorangestellten Doppelpunkt bezeichnet und anschließend beim Aufruf der execute als Dictionary übergeben werden:

python

from sqlalchemy.sql import text

with self.engine.begin() as conn:
stmt = text('SELECT id FROM _exported_records WHERE id = :id')
result = conn.execute(stmt, {"id": record_id}).fetchone()
Hat dies deine Frage beantwortet?