Montag, 10. Oktober 2011

Einzelne Zeilen vom Index ausnehmen - Parameter "FORMAT COLUMN"

Heute geht es um einen eher unscheinbaren Parameter beim Erstellen eines Oracle TEXT Index:
Mit FORMAT COLUMN kann zum einen der Filter für Binärdokumente gesteuert werden - darüber hinaus
kann man damit aber auch festlegen, ob das Dokument überhaupt indiziert werden soll. Und das geht so - wir fangen mit einer einfachen Tabelle an:
create table test(
  id     number(10) not null,
  text   varchar2(4000) not null,
  format varchar2(10) not null,
  constraint pk_test primary key (id),
  constraint ck_format check (format in ('TEXT','BINARY','IGNORE'))
)
/

insert into test values (1, 'Dieses Dokument wird indiziert.', 'TEXT')
/
insert into test values (2, 'Hierfür stehen keine Einträge im Textindex', 'IGNORE')
/
Die Indexerstellung funktioniert wie immer - nur, dass der Parameter FORMAT_COLUMN mitgegeben wird.
create index ft_test on test (text)
indextype is ctxsys.context
parameters ('format column format')
/
Danach schauen wir in die $I-Tabelle - dort stehen in der Tat nur Tokens für das erste
Dokument - die Spalte FORMAT enthält hier "TEXT".
SQL> select token_text from dr$ft_test$i;

TOKEN_TEXT
------------------------------------------
DIESES
DOKUMENT
INDIZIERT
WIRD

4 Zeilen ausgewählt.
Aber was passiert, wenn man die Spalte FORMAT ändert - angenommen, wir ändern den Inhalt
für das zweite Dokument von IGNORE in TEXT ...
SQL> update test set format = 'TEXT' where id = 2
/

1 Zeile aktualisiert.
Wenn man nun in der Dictionary View CTX_USER_PENDING nachsieht, ändert sich diese
(obwohl mit der Spalte FORMAT eine "index-relevante" Spalte geändert wurde, nicht. Ein CTX_DDL.SYNC_INDEX
bewirkt also ebenfalls nichts. Man muss
also entweder im Update-Kommando selbst oder mit einem Trigger sicherstellen, dass bei einer
Änderung der Spalte FORMAT auch die Indexspalte selbst "angefasst" wird - das könnte so
aussehen ...
create or replace trigger tr_upd_format
before update of format on test
for each row
begin
  if :old.format != :new.format then 
    :new.text := :old.text;
  end if;
end;
/
Von nun an wirkt eine Änderung an der Spalte FORMAT wie eine Änderung am Dokument - nach der
Index-Synchronisierung ist das Dokument indiziert bzw. aus dem Index entfernt (je nachdem, wie
die Spalte FORMAT gesetzt wurde).
SQL> update test set format = 'IGNORE' where id = 1; 

1 Zeile wurde aktualisiert.

SQL> update test set format = 'TEXT' where id = 2; 

1 Zeile wurde aktualisiert.

SQL> select pnd_rowid from ctx_user_pending; 

PND_ROWID
------------------------------ 
AAAmVGAAFAAAMWTAAA
AAAmVGAAFAAAMWTAAB

2 Zeilen ausgewählt.

SQL> exec ctx_ddl.sync_index('FT_TEST'); 

PL/SQL-Prozedur erfolgreich abgeschlossen.

SQL> exec ctx_ddl.optimize_index('FT_TEST', ctx_ddl.optlevel_full); 

PL/SQL-Prozedur erfolgreich abgeschlossen.

SQL> select token_text from dr$ft_test$i; 

TOKEN_TEXT
----------------------------------------------------------------
EINTRÄGE
HIERFÜR
IM
KEINE
STEHEN
TEXTINDEX

6 Zeilen ausgewählt.

Beliebte Postings