Einen externen Präprozessor einbinden

Allgemeines

Mit einem externen Präprozessor können Dokumente geändert werden, bevor sie indiziert werden. Dies ermöglicht es beispielsweise, Binärdaten in Text umzuwandeln oder Metadaten (etwa von Bildern) zu extrahieren oder zu erzeugen und anschließend zu indizieren. Dadurch können die betreffenden Dokumente auch oder besser über die Suche gefunden werden.

Dokumente beliebiger MIME-Typen können den jeweils zu verwendenden externen Präprozessoren über den Abschnitt indexing in der Systemkonfiguration zugeordnet werden. Als ein externer Präprozessor kann jedes geeignete Programm angegeben werden. Optional können einem solchen Programm Argumente übergeben werden.

Funktionsweise

Das Präprozessor-Programm erhält vom Search Engine Server das zu indizierende Dokument in Form eines serialisierten XML-Dokuments über stdin. Der Präprozessor modifiziert dieses XML-Dokument in der gewünschten Weise und gibt es anschließend an den Search Engine Server auf stdout zurück. Dieser indiziert nun das modifizierte Dokument. Beispiel:

Ursprüngliche Daten:

<ses-indexDoc docId="2148" collection="cm-contents"
    mimeType="application/vnd.ms-excel">
<title encoding="plain">Ein Beispiel mit Excel-Daten</title>
<keyword encoding="plain">Beispiel</keyword>
<blob encoding="stream" mimeType="application/vnd.ms-excel">
  /Fiona_671/instance/default/tmp/externalPreprocessor/1.dat
</blob>
</ses-indexDoc>

Geänderte Daten:

<ses-indexDoc docId="2148" collection="cm-contents"
    mimeType="application/vnd.ms-excel">
<title encoding="plain">Excel-Daten als Text</title>
<keyword encoding="plain">Beispiel</keyword>
<blob encoding="stream" mimeType="text/plain">
  /Fiona_671/instance/default/tmp/text_data.dat
</blob>
</ses-indexDoc>

Das XML-Dokument enthält die zu indizierenden Felder (die Namen der XML-Elemente) und deren Werte (die Inhalte der XML-Elemente). Ein Feldwert kann direkt (encoding: plain) oder kodiert angegeben sein. Das Encoding wird über das Tag-Attribut encoding des Feld-Elements bestimmt, das folgende Werte haben kann:

  • plain: Der Feldwert entspricht dem Inhalt des XML-Elements.
  • base64: Der Feldwert ergibt sich aus dem base64-dekodierten Inhalt des XML-Elements.
  • stream: Der Feldwert ist in der Datei enthalten, deren Pfad im Inhalt des XML-Elements angegeben ist.

Bei allen Kodierungen außer plain wird zusätzlich der MIME-Typ des Dokuments im Feld-Element-Attribut mimeType übermittelt. Wenn der MIME-Typ während der Vorverarbeitung geändert wird, muss auch das mimeType-Attribut auf den resultierenden MIME-Typ gesetzt werden. Ist die Kodierung nicht plain, wird ein Feldwert nur dann indiziert, wenn der angegebene MIME-Typ dem Muster text/* genügt. Mit anderen Worten: wenn ein Präprozessor base64-kodierte oder per Streaming inkludierte Feldwerte liefert, muss er deren MIME-Typ auf einen Text-Typ setzen.

Konfiguration

Der zu verwendende Präprozessor kann zusammen mit den MIME-Typen, für die er zuständig ist, sowie den ihm zu übergebenden Argumenten in der Konfigurationsdatei indexing.xml eingetragen werden. Der betreffende Abschnitt sieht beispielsweise so aus:

  ...
  <contentPreprocessors type="list">
    <preprocessor>
      <mimeTypes type="list">
        <mimeType>application/pdf</mimeType>
      </mimeTypes>
      <processor type="external">
        bin/tclsh
      </processor>
      <processorArguments type="list">
        <argument>/Fiona_671/instance/default/script/custom/pdf2TxtWrapper.tcl</argument>
      </processorArguments>
    </preprocessor>
    ...
  </contentPreprocessors>
  ...

Hier sind als auszuführendes Programm der Tcl-Interpreter und als ein argument in processorArguments der Name des von ihm auszuführenden Skripts, pdf2TxtWrapper.tcl, angegeben. Das Skript kann nicht beim Start des Search Engine Servers geladen werden, sollte also nicht im serverCmds- oder clientCmds-Verzeichnis liegen.

Das folgende als Beispiel aufgeführte Skript pdf2TxtWrapper.tcl zeigt, wie ein im Feld blob enthaltenes PDF-Dokument eingelesen und zu Text konvertiert werden kann. Beachten Sie bitte, dass die Search Cartridge PDF-Dateien auch ohne Zuhilfenahme eines Präprozessors indizieren kann.

# Libraries
package require dom
package require base64
proc safeInterp {args} {}
source [file join [file dirname [info script]]\
    ../../../share/script/common/clientCmds/util.tcl]

# Read Data
set xmlRequest [read stdin]

# Parse XML
set docNode [::dom::DOMImplementation parse $xmlRequest]
set rootNode [::dom::document cget $docNode -documentElement]

# Select and handle element "blob"
set blobElement [lindex [::dom::selectNode $rootNode descendant::blob] 0]
array set attributes [array get [$blobElement cget -attributes]]
set blobTextNode [$blobElement cget -firstChild]
if {$blobTextNode ne ""} {
  set value [$blobTextNode cget -nodeValue]
  if {$value ne ""} {
    switch $attributes(encoding) {
      plain {
        # shouldn't happen with pdf
        set blob $value
      }
      base64 {
        set blob [::base64::decode $value]
      }
      stream {
        set blobFile $value
      }
    }
    set deletePdfFile 0
    if {![info exists blobFile]} {
      set blobFile "/tmp/convert_me_[pid].pdf"
      writeFile $blobFile $blob
      set deletePdfFile 1
    }
    set textFile "/tmp/converted_[pid].txt"
    # convert using ps2ascii
    if {![catch {
      exec ps2ascii $blobFile $textFile
    }]} {
      # modify the dom tree
      $blobTextNode configure -nodeValue $textFile
      ::dom::element setAttribute $blobElement mimeType "text/plain"
      ::dom::element setAttribute $blobElement encoding stream
    }
    if {$deletePdfFile} {
      file delete -force $blobFile
    }
  }
}
set xmlToReturn [string trimright [::dom::DOMImplementation serialize $docNode] "\n"]
set lines [split $xmlToReturn "\n"]
if {[string match "<!D*" [lindex $lines 1]]} {
  set xmlToReturn [join [lreplace $lines 1 1] "\n"]
}
# return the (modified) xml data
puts -nonewline $xmlToReturn