Montag, 26. August 2013

Alle 12c Oracle Text Features auf einen Blick!

Mit der neuen Oracle Database 12c Version sind einige interessante neue Features im Oracle Text Umfeld implementiert worden. Nach und nach wollen wir diese in unseren deutschsprachigen Postings thematisieren.

Wer jetzt allerdings schon einen Überblick über alle neuen Text Features erhalten möchte, kann entweder im
Oracle Text Application Developer's Guide 12c Release 1 (12.1) im Abschnitt New Features recherchieren oder sich über das neue Whitepaper New Features in Oracle Text with Oracle Database12c informieren.

Viel Spaß dabei!

Montag, 15. Juli 2013

Oracle TEXT in Oracle12c: Neues Feature 'Pattern Stopclass'

Heute festgestellt, dass das letzte Blog Posting schon fast 3 Monate zurückliegt. Nun wird es aber Zeit: Das neue Datenbankrelease Oracle12c bringt auch im Bereich Oracle TEXT einige neue Features mit sich - diese werden wir nach und nach in diesem Blog besprechen. Heute geht es um die neue Möglichkeit, eine Stopwortliste nicht nur mit einzelnen Wörtern, sondern mit Stop-Patterns zu versehen. Hierauf haben viele sicherlich schon lange gewartet. Ein Beispiel: Wir erzeugen eine Tabelle und füllen diese mit ein paar "Wörtern" ...
create table tab_stopclasstest (
  textcol  varchar2(200)
)
/

insert into tab_stopclasstest values ('200');
insert into tab_stopclasstest values ('100');
insert into tab_stopclasstest values ('99');
insert into tab_stopclasstest values ('Oracle TEXT');
insert into tab_stopclasstest values ('A100');
insert into tab_stopclasstest values ('01.09.2012');
Wenn es nun an die Definition der Stopwörter geht, so konnte man bislang mit CTX_DDL.CREATE_STOPLIST eine Stopliste erzeugen und mit CTX_DDL.ADD_STOPWORD die Wörter ("Oracle") hinzufügen.

begin
  ctx_ddl.create_stoplist(
    stoplist_name => 'NEUE_STOPLISTE'
  );
  ctx_ddl.add_stopword ('NEUE_STOPLISTE', 'Oracle');
  ctx_ddl.add_stopclass('NEUE_STOPLISTE', 'NUMBERS');
end;
/
Aber genau dabei beginnt in vielen Fällen das Problem: Denn wenn Zahlen nicht indiziert werden sollen, ist es nahezu unmöglich, im Vorfeld alle möglichen Varianten als Stopwörter zu bestimmen. Die Stopclasses machen nun genau das möglich (übrigens kann man die Stopklasse NUMBERS schon in Oracle 11.2 verwenden) - aber dort eben nicht mehr. Anders in Oracle12c ...
begin
  ctx_ddl.create_stoplist(
    stoplist_name => 'NEUE_STOPLISTE'
  );
  ctx_ddl.add_stopword ('NEUE_STOPLISTE', 'Oracle');
  ctx_ddl.add_stopclass('NEUE_STOPLISTE', 'NUMBERS');
  ctx_ddl.add_stopclass('NEUE_STOPLISTE', 'KLASSE_1','[A-Z]\d+');
end;
/
CTX_DDL.ADD_STOPCLASS nimmt drei Parameter entgegen. Der erste ist, wie schon bei ADD_STOPWORD, der Name der Stopliste. Danach kommt die "Stopklasse" - Oracle bringt eine vordefinierte Klasse mit: NUMBERS, die, wie gesagt, schon in 11.2 vorhanden ist. Ab Oracle 12.1 kann man aber auch einen anderen Namen eintragen - und dann braucht es noch den dritten Parameter: Dort wird ein regulärer Ausdruck hinterlegt, der die zu ignorierenden Wörter erfasst. In obigem Beispiel wäre das genau ein Buchstabe, gefolgt von mindestens einer Zahl. Legt man, basierend auf dieser Stopliste einen Index auf die obige Tabelle an, so wird dieser nur ein einziges Token enthalten: TEXT.
create index ft_stopclasstest on tab_stopclasstest (textcol)
indextype is ctxsys.context 
parameters ('stoplist neue_stopliste')
/

select token_text from dr$ft_stopclasstest$i
/

TOKEN_TEXT
-----------------------------------------
TEXT
Viel Spaß beim Ausprobieren.

Donnerstag, 18. April 2013

Indexstatistiken (INDEX_STATS) im XML-Format: Oracle TEXT Management einfach automatisieren!

Heute geht es um Statistiken für einen Oracle TEXT Index - vor einiger Zeit gab es dazu schon mal ein Posting - heute soll es darum gehen, wie man diese Statistiken so zur Verfügung stellt, dass man mit Reporting- oder Management-Tools einfach darauf zugreifen oder diese zur Automatisierung von Aufgaben verwenden kann. Indexstatistiken kann man mit CTX_REPORT.INDEX_STATS abrufen. In nahezu allen Beispielen (so auch im erwähnten Blog-Posting) werden die Statistiken als Textausgabe erzeugt - in etwa wie folgt ...
===========================================================================
                    STATISTICS FOR "TESTIT"."IDX_TEXT"
===========================================================================

indexed documents:                                                     10
allocated docids:                                                      10
$I rows:                                                               56

---------------------------------------------------------------------------
                             TOKEN STATISTICS
---------------------------------------------------------------------------
:
Dieses Format ist zwar gut lesbar, zur Automatisierung jedoch völlig ungeeignet. Allerdings bietet Oracle TEXT noch eine andere Variante zur Ausgabe der Statistiken an: XML - und das geht wie folgt.
DROP TABLE ausgabe
/

CREATE TABLE ausgabe (
  index_name  varchar2(200),
  zeitstempel date,
  resultat    xmltype
)
xmltype column resultat store as binary xml
/

 
declare
  ergebnis clob := null;
begin
  ctx_report.index_stats(
    index_name     => 'IDX_TEXT',
    report         => ergebnis,
    report_format  => ctx_report.fmt_xml,
    stat_type      => null
  );
  insert into ausgabe values ('IDX_TEXT', sysdate, xmltype(ergebnis));
  dbms_lob.freetemporary(ergebnis);
end;
/

 
set long 32000
set head off
set pagesize 10000

SELECT * FROM ausgabe
/
Das generierte Format sieht nun wie folgt aus ...
<CTXREPORT>
  <INDEX_STATS>
    <STAT_INDEX_NAME>"TESTIT"."IDX_TEXT"</STAT_INDEX_NAME>
    <STAT_INDEX_STATS>
      <STAT_STATISTIC NAME="indexed documents">10</STAT_STATISTIC>
      <STAT_STATISTIC NAME="allocated docids">10</STAT_STATISTIC>
      <STAT_STATISTIC NAME="$I rows">56</STAT_STATISTIC>
      :
Bei großen Indizes braucht der Aufruf von INDEX_STATS sehr lange - hier ist es sicher sinnvoll, mit Hilfe von DBMS_SCHEDULER einen Job zu erzeugen, welcher die Statistiken regelmäßig (bspw. über Nacht) aktualisiert. Das Interessante am XML-Format ist nun, dass es sich maschinell auswerten lässt. Dazu nutzen wir die XML-Funktionen in der Oracle-Datenbank und erstellen eine (relationale) View auf die XML-Ausgabe von CTX_REPORT.INDEX_STATS.
create or replace view view_index_stats as
select
  a.index_name,
  a.zeitstempel,
  x.indexed_documents,
  x.allocated_docids,
  x.dollar_i_rows,
  x.dollar_i_dsize,
  x.index_frag,
  x.garbage_docids,
  x.garbage_size
from 
  ausgabe a,
  xmltable(
    '/CTXREPORT/INDEX_STATS'
    passing a.resultat
    columns 
      indexed_documents number path '/INDEX_STATS/STAT_INDEX_STATS/STAT_STATISTIC[@NAME="indexed documents"]',
      allocated_docids  number path '/INDEX_STATS/STAT_INDEX_STATS/STAT_STATISTIC[@NAME="allocated docids"]',
      dollar_i_rows     number path '/INDEX_STATS/STAT_INDEX_STATS/STAT_STATISTIC[@NAME="$I rows"]',
      dollar_i_dsize    number path '/INDEX_STATS/STAT_FRAG_STATS/STAT_STATISTIC[@NAME="total size of $I data"]',
      index_frag        varchar2(10) path '/INDEX_STATS/STAT_FRAG_STATS/STAT_STATISTIC[@NAME="estimated row fragmentation"]',
      garbage_docids    number path '/INDEX_STATS/STAT_FRAG_STATS/STAT_STATISTIC[@NAME="garbage docids"]',
      garbage_size      number path '/INDEX_STATS/STAT_FRAG_STATS/STAT_STATISTIC[@NAME="estimated garbage size"]'
  ) x
/
Diese View lässt sich nun wie eine Tabelle verwenden ...
SQL> select * from view_index_stats

INDEX_NAME ZEITSTEMPEL          INDEXED_DOCUMENTS ALLOCATED_DOCIDS
---------- -------------------- ----------------- ----------------
DOLLAR_I_ROWS DOLLAR_I_DSIZE INDEX_FRAG GARBAGE_DOCIDS GARBAGE_SIZE
------------- -------------- ---------- -------------- ------------
IDX_TEXT   18.04.2013 14:43:49                 10               10
           56            198  0 %                    0            0


1 Zeile wurde ausgewählt.
Nicht so schön ist die Spalte INDEX_FRAG - denn das XML, welches von INDEX_STATS generiert wurde, enthält hier tatsächlich das Prozentzeichen - weshalb es nicht als NUMBER aufgefasst werden kann - hierfür müssen wir in der View-Definition noch ein wenig was tun ...
create or replace view view_index_stats as
select
  a.index_name,
  a.zeitstempel,
  x.indexed_documents,
  x.allocated_docids,
  x.dollar_i_rows,
  x.dollar_i_dsize,
  to_number(replace(x.index_frag, ' %', '')) as index_frag,
  x.garbage_docids,
 :
Danach ist auch die Spalte INDEX_FRAG vom Typ NUMBER und man kann nun numerische Vergleiche durchführen. Analog dazu lassen sich auch die Token-Statistiken entsprechend aufbereiten ... Dazu bauen wir eine zweite View ...
create or replace view index_stats_frag_tokens as
select
  a.index_name,
  a.zeitstempel,
  x.token_text,
  x.token_type,
  to_number(replace(x.token_frag, ' %', '')) as token_frag
from 
  ausgabe a,
  xmltable(
    '/CTXREPORT/INDEX_STATS/STAT_FRAG_STATS/STAT_TOKEN_LIST/STAT_TOKEN'
    passing a.resultat
    columns 
      token_text   varchar2(64) path '/STAT_TOKEN/STAT_TOKEN_TEXT',
      token_type   varchar2(50) path '/STAT_TOKEN/STAT_TOKEN_TYPE',
      token_frag   varchar2(20) path '/STAT_TOKEN/STAT_TOKEN_STATISTIC'
  ) x
/
  
select * from index_stats_frag_tokens
/
... deren Inhalt nun wie folgt aussieht ...
SQL> select * from index_stats_frag_tokens

INDEX_NAME ZEITSTEMPEL          TOKEN_TEXT           TOKEN_TYPE           TOKEN_FRAG
---------- -------------------- -------------------- -------------------- ----------
IDX_TEXT   18.04.2013 14:55:28  ZU                   0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WOLLEN               0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WIRTSCHAFT           0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WIRD                 0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WICHTIGER            0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WERDEN               0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WER                  0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WEITER               0:TEXT                        0
IDX_TEXT   18.04.2013 14:55:28  WAHLKAMPF            0:TEXT                        0
:
Lässt man das XML nun, wie schon erwähnt, per DBMS_SCHEDULER regelmäßig aktualisieren, so hat man (wie im Data Dictionary) bequem nutzbare Views mit Statistiken zum Index. Diese können nun natürlich auch für eine automatisierte Verarbeitung genutzt werden. So könnte ein Job regelmäßig alle Tokens optimieren (CTX_DDL.OPTIMIZE mit OPTLEVEL_TOKEN), die eine bestimmte Fragmentierung überschreiten. Gleiches gilt natürlich auf Indexebene.
Auch die Integration mit Management-Werkzeugen wie dem Oracle Enterprise Manager ist kein Problem. In der deutschsprachigen DBA Community ist beschrieben, wie man eine eigene "Metrik", basierend auf einer SQL-Abfrage einrichtet. Nimmt man hierfür die erstellten Views, so kann der Enterprise Manager einen Alert senden, sobald die Indexfragmentierung einen bestimmten Schwellenwert übersteigt. Die professionelle Wartung einer Oracle TEXT-Installation ist damit kein Problem mehr ...

Dienstag, 5. März 2013

Alle Posts auf einen Blick

Um einen besseren Überblick über die schon veröffentlichten Posts in diesem Blog zu bekommen, an dieser Stelle eine aktuelle Linksammlung ...

Grundsätzliche Themen: Administration, Index anlegen ...
Performance, Monitoring ...
Spezielle Suchabfragen unterstützen
Mixed Queries, Datastores ...

Beliebte Postings