Donnerstag, 19. Juli 2012

Filter Preferences - Grundsätzliches

Wir haben in unseren Textblogs schon mehrfach über einige Texteinstellungen - die sogenannten Preferences - gesprochen.  Nun ist es an der Zeit, Grundlagen zu den Filter Preferencen zu legen. Filter Preferences sind, wie der Name schon verrät, dazu da den Text zum Indizieren zu filtern. Formatierte Dokumente werden zwar in nativer Format gespeichert; der Filter sorgt allerdings dafür, dass eine vorläufige Version in reinem (plain) Text oder HTML Version des Dokuments zur Verfügung steht, um dann die Wörter zum Indizieren zu erhalten.

Filter-Preferences werden mit dem CREATE INDEX oder ALTER INDEX Statement erzeugt. Man sollte sich dabei nicht auf System Preferencen verlassen, sondern den Filter immer beim Anlegen des Index mitangeben. Folgende Filter Typen existieren:

  • CHARSET_FILTER: Character Set Konvertierung
  • AUTO_FILTER: Für formatierte Dokumente
  • NULL_FILTER: Kein Filter ist erforderlich, nützlich für Plain Text, HTML und XML
  • MAIL_FILTER: Transformiert RFC-822 und RFC-2045 Nachrichten in indizierbaren Text
  • USER_FILTER: Externer Filter für benutzerdefinertes Filtern
  • PROCEDURE_FILTER: Benutzerdefiniertes Filtern definiert über eine Prozedur

Hier im Blog gebe ich Beispiele für NULL_FILTER, AUTO_FILTER und den USER_FILTER. Weitere Beispiele dazu finden sich im Handbuch.
Zuerst wird eine Tabelle erzeugt, die Dokumente im Format Powerpoint, PDF, HTML und ASCII enthält.

drop table filter_test; 
create table filter_test(id number primary key, docs blob);

Zum Laden verwende ich den SQL *Loader. Die CTL Datei sieht folgendermassen aus:
LOAD DATA
INFILE 'filter_load.dat'
INTO TABLE null_filter
FIELDS TERMINATED BY ','
(id SEQUENCE (MAX,1) ,
ext_fname FILLER CHAR(50),
docs LOBFILE(ext_fname) TERMINATED BY EOF)

Die filter_load.dat Datei hat folgende Inhalte.
snaps.sql
powerp.pptx
plain.txt
replay.html
one_page.pdf

Im ersten Beispiel wird ein Index mit Filter Preference NULL_FILTER erzeugt. Um zu überprüfen, ob im Index Create Prozeß keine Fehler passiert sind, schalte ich Logging ein und überprüfe den Index nach dem Anlegen mit CTX_USER_INDEX_ERRORS.
drop index filter_test_idx force;
execute CTXSYS.CTX_ADM.SET_PARAMETER ('LOG_DIRECTORY','/tmp'); 
exec CTX_OUTPUT.START_QUERY_LOG('filterlog');

create index filter_test_idx on filter_test ( docs )
indextype is ctxsys.context
parameters ('FILTER ctxsys.NULL_FILTER');

execute CTX_OUTPUT.END_QUERY_LOG;
SQL> select * from ctx_user_index_errors;
no rows selected

Nun wird das Ergebnis überprüft. Um einen Einruck von dem Inhalt der Ergebnismenge zu bekommen, verwende ich CTX_DOC.SNIPPED. Die REGEXP_REPLACE Funktion macht das Ergebnis lesbarer und eliminiert die überflüssigen Leerzeilen.

SQL> execute ctx_doc.set_key_type('ROWID');
SQL> select id, regexp_replace(ctx_doc.snippet 
('FILTER_TEST_IDX', rowid, 'plain or OLTP or replay or snapshot or SPA or
 REPLAY',starttag=>'###',endtag =>'###'),'\s+',' ') snippet
 from filter_test
 where contains ( docs, 'plain or OLTP or replay or snapshot or SPA or REPLAY') > 0; 
ID
----------
SNIPPET
--------------------------------------------------------------------------------
1
hh24:mi') from dba_hist_###snapshot### order by BEGIN_INTERVAL_TIME
3
dies ist ein ###plain### text
4
performance of a workload ###replay### against the performance of...The f
irst ###replay### would try to mimic the captured

Wie zu erwarten, enthält das Ergebnis die Dokumente snaps.sql (mit 1), plain.txt (mit 2) und replay.html (mit 3).
Nun verwenden wir den AUTO_FILTER. Das Vorgehen ist ähnlich wie oben, nur die FILTER Preference lautet nun AUTO_FILTER.
drop index filter_test_idx force; 
execute CTXSYS.CTX_ADM.SET_PARAMETER ('LOG_DIRECTORY','/tmp'); 
execute CTX_OUTPUT.START_QUERY_LOG('filterlog');

create index filter_test_idx on filter_test (docs)
indextype is ctxsys.context
parameters ('FILTER ctxsys.AUTO_FILTER');

execute CTX_OUTPUT.END_QUERY_LOG;
SQL> select * from ctx_user_index_errors;
no rows selected
Nun wird wieder das Ergebnis selektiert.
SQL> execute ctx_doc.set_key_type('ROWID');

SQL>select id, regexp_replace(ctx_doc.snippet
('FILTER_TEST_IDX', rowid, 'plain or OLTP or replay or snapshot or SPA or
 REPLAY',starttag=>'###',endtag =>'###'),'\s+',' ') snippet
 from filter_test
 where contains ( docs, 'plain or OLTP or replay or snapshot or SPA or REPLAY') > 0; 
ID
----------
SNIPPET
--------------------------------------------------------------------------------
1
hh24:mi') from dba_hist_###snapshot### order by BEGIN_INTERVAL_TIME
2
Sesssions und Calls ###OLTP###-Datenbanken mit ca.12.000...Siehe Enhancem
ent Request ?7523016: ###REPLAY### REPORTS ORA-933 ON SET ROLE
3
dies ist ein ###plain### text
4
performance of a workload ###replay### against the performance of...The f
irst ###replay### would try to mimic the captured
5
2) Before using the ###SPA### or Database Replay, understand...3) Perform
STS Capture for ###SPA### & workload capture for Database

Es werden nun alle Dokumente gefiltert, indiziert und gefunden. Möchte man einen Überblick über alle unterstützten Formate erhalten, kann man dies im Handbuch nachschlagen.

Nun kommen wir zum letzten Beispiel - einem USER_FILTER. Hierzu ist ein Programm notwendig, das beim Filtern für jede Zeile ausgeführt wird. Explizit wird nun eine Preference MY_FILTER mit einem speziellen Attribut erzeugt, das den Programmnamen festlegt - hier upper.pl
execute ctx_ddl.drop_preference('my_filter');
BEGIN
ctx_ddl.create_preference ('my_filter', 'user_filter');
ctx_ddl.set_attribute ('my_filter', 'command', 'upper.pl');
END;
/
PL/SQL procedure successfully completed.
Das Programm ist ein Perl-Programm, das den Text in Großbuchstaben konvertiert. Es muß unbedingt im Verzeichnis $ORACLE_HOME/ctx/bin zu finden sein.

#!/usr/bin/perl
open(IN, $ARGV[0]);
open(OUT, ">".$ARGV[1]);
while ()
{
tr/a-z/A-Z/;
print OUT;
}
close (IN);
close (OUT);

Nun wird der Index erzeugt.

drop index filter_test_idx force;

create index filter_test_idx on filter_test (docs) 
indextype is ctxsys.context
parameters ('filter my_filter');

SQL> select * from ctx_user_index_errors;
no rows selected

Das Ergebnis sieht dann folgendermassen aus.

SQL> select id, regexp_replace(ctx_doc.snippet
('FILTER_TEST_IDX', rowid, 'plain or OLTP or replay or snapshot or SPA or
REPLAY',starttag=>'###',endtag =>'###'),'\s+',' ') snippet
from filter_test
where contains ( docs, 'plain or OLTP or replay or snapshot or SPA or REPLAY') > 0;
ID
----------
SNIPPET
--------------------------------------------------------------------------------
4
CAPTURE VS. ###REPLAY###
...PERFORMANCE OF A WORKLOAD ###REPLAY### AGAINST THE PERFORMANCE
OF...CAPTURED SYSTEM, WHILE "###REPLAY###" REFERS TO THE
REPLAYED WORKLOAD.

Keine Kommentare:

Beliebte Postings