Posts mit dem Label CTX_OUTPUT werden angezeigt. Alle Posts anzeigen
Posts mit dem Label CTX_OUTPUT werden angezeigt. Alle Posts anzeigen

Montag, 24. November 2008

Suchverhalten der Anwender monitoren: Abfrage-Analyse mit CTX_REPORT

Was sind die häufigsten Begriffe, nach denen die Anwender suchen? Welche Abfragen laufen ständig ins Leere und liefern kein Resultat? Diese Fragen sind häufig wichtig, um "anwenderfreundliche" Applikationen gestalten zu können oder um die Suchanfragen optimal zur Verfügung zu stellen.
Ab Oracle 10g ist es möglich mit CTX_OUTPUT ein spezielles Logging für Suchanfragen anzustossen und mit CTX_REPORT eine Analyse dieser Loginformationen durchzuführen.
Im Folgenden demonstriert ein Beispiel die Anwendung.

Wie in einem unserer vorangegangenen
Blogs schon demonstriert, wird das Logging in den Sessions, in denen die Abfragen laufen, aktiviert. Dazu legen wir zuerst das Log Verzeichnis fest.

execute CTXSYS.CTX_ADM.SET_PARAMETER ('LOG_DIRECTORY','/tmp'); 

Danach starten wir das Query-Logging mit folgendem Aufruf:

exec CTX_OUTPUT.START_QUERY_LOG('querylog');

Die folgenden SELECT Statements werden nun in einer Logdatei aufgezeichnet. Dabei nehmen als Grundlage, die in Blog generierte Tabelle TEXTTABELLE und den dazugehörenden Textindex.

SELECT * FROM texttabelle WHERE contains(dokument, 'USA')>0;
SELECT * FROM texttabelle WHERE contains(dokument, 'USA')>0;
SELECT * FROM texttabelle WHERE contains(dokument, 'USA')>0;
SELECT * FROM texttabelle WHERE contains(dokument, 'USA')>0;
SELECT * FROM texttabelle WHERE contains(dokument, 'USA and Messe')>0; 
SELECT * FROM texttabelle WHERE contains(dokument, 'Software')>0;
SELECT * FROM texttabelle WHERE contains(dokument, 'Hamburg')>0;

Das Logging wird dann mit folgendem Aufruf beendet:

execute CTX_OUTPUT.END_QUERY_LOG;

Wie schon erwähnt, ist diese Art von Logging vergleichbar mit dem Logging mit CTX_OUTPUT.START_LOG (siehe Blog). Es wird eine Datei mit Namen QUERYLOG im Logverzeichnis /tmp erzeugt. Allerdings liegt diese Logdatei in einem speziellen XML Format vor, wie in unserem Beispiel zu sehen ist:


<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>USA</Query><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>USA</Query><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>USA</Query><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>USA</Query><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>USA and Messe</Query><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>Software</Query>><ReturnHit>Yes</ReturnHit><QueryTag></QueryTag></QuerySet>
<QuerySet><TimeStamp>10:30:42 11/20/08 </TimeStamp><IndexName>IDX_TEXT</IndexName><Query>Oracle</Query>><ReturnHit>No</ReturnHit><QueryTag></QueryTag></QuerySet>

Wie lässt sich nun diese Datei, besonders wenn sie grösser als in unserem Minibeispiel ist, bequem auslesen?
Das Package CTX_REPORT mit der Prozedur QUERY_LOG_SUMMARY liefert eine mögliche Vorgehensweise. Diese Prozedur, als CTXSYS User ausgeführt, liest die TOP N Abfragen und liefert die Resultate in einer PL/SQL Table vom Typ CTX_REPORT.QUERY_TABLE. Die Zahl N ist dabei definierbar über den Parameter ROW_NUM. Folgender Beispiel-Code liest unsere Log-Datei QUERYLOG aus und liefert das Ergebnis der TOP 10 Abfragen:

SQL> connect ctxsys
Enter password:
Connected.
SQL> set serveroutput on

SQL> declare
  2  logentry ctx_report.query_table;
  3  begin
  4  ctx_report.query_log_summary('querylog','idx_text', logentry, row_num=>10);
  5  for i in 1..logentry.count 
  6  loop
  7  dbms_output.put_line(logentry(i).query || ' kommt '||logentry(i).times||' Mal vor');
  8  end loop;
  9  end;
  10  /
USA kommt 4 Mal vor
USA and Messe kommt 1 Mal vor
Software kommt 1 Mal vor

PL/SQL procedure successfully completed.

Standardmässig werden dabei nur die häufigsten Treffer der erfolgreichen Abfragen ausgewertet, da der Parameter MOST_FREQ auf TRUE steht. Manchmal ist es allerdings interessanter, die fehlgeschlagenen Abfragen zu dokumentieren. Der Parameter HAS_HIT (Defaultwert: TRUE) kontrolliert das Verhalten der Auswertung bzgl. der erfolgreichen Treffer. Setzen wir diesen Wert auf FALSE, werden nur die Resultate angezeigt, die von fehlgeschlagenen Suchabfragen stammen.
Folgendes Beispiel demonstriert das Verhalten:

SQL> set serveroutput on
SQL> declare
  2  logentry ctx_report.query_table;
  3  begin
  4  ctx_report.query_log_summary('querylog','idx_text', logentry, row_num=>10, has_hit=>false);
  5  for i in 1..logentry.count 
  6  loop
  7  dbms_output.put_line(logentry(i).query || ' kommt '||logentry(i).times||' Mal vor');
  8  end loop;
  9  end;
 10  /
Hamburg kommt 1 Mal vor

PL/SQL procedure successfully completed.

Um solches Fehlschlagen von Suchabfragen zu verhindern, könnte man z.B. in den Applikationen bessere Hilfestellung für den User anbieten oder über Synonyme (Thesaurus) alternative Schreibweisen ermöglichen.
Mehr dazu in einem unserer nächsten Blog-Veröffentlichungen. Viel Spass beim Ausporbieren ...

Freitag, 24. Oktober 2008

Monitoren von Oracle Text Indizes: Grundsätzliche Funktionen

Wie kann man den Textindex monitoren? Welche Möglichkeiten gibt es? Dazu stehen spezielle Data Dictionary Views, Packages oder ab Oracle Database 11g die Enterprise Manager Funktionalität zur Verfügung. Im folgenden Beispiel nutzen wir eine Tabelle die ca. 600 000 Zeilen besitzt und die mit einer TEXT-Spalte mit Kurztexten ausgestattet ist.
Zuerst erzeugen wir den Textindex TEXT_COMP und monitoren gleichzeitig den Indexvorgang. Mit dem Aufruf CTX_ADM.SET_PARAMETER läßt sich dabei das Logverzeichnis festlegen - in unserem Fall /tmp. Mit CTX_OUTPUT.START_LOG starten wir den Logvorgang. Folgender Aussschnitt zeigt die Verwendung:

SQL> execute CTXSYS.CTX_ADM.SET_PARAMETER ('LOG_DIRECTORY','/tmp'); 
PL/SQL procedure successfully completed.

SQL> execute CTX_OUTPUT.START_LOG('textlog');
PL/SQL procedure successfully completed.

SQL> CREATE INDEX text_comp ON comp_test(text)
  2  INDEXTYPE IS ctxsys.context PARAMETERS('memory 100M');
Index created.

SQL> execute CTX_OUTPUT.END_LOG;
PL/SQL procedure successfully completed.

Bevor wir uns die Logtabelle ansehen, sollten wir zuerst überprüfen, ob der Index ohne Fehler erzeugt worden ist. Folgendes Kommando gibt Aufschluss darüber. Diese Überprüfung sollte nach jeder Indexerzeugung durchgeführt werden.

SQL> SELECT err_index_name, err_timestamp, err_textkey, err_text
   2 FROM ctx_user_index_errors ORDER BY err_index_name, err_timestamp;
no rows selected

In unserem Fall liegt kein Fehler vor. Falls diese Tabelle Zeilen enthält, gibt die Spalte ERR_TEXTKEY Aufschluss über die ROWID des entsprechenden Dokuments, das den Fehler hervorgerufen hat. Damit hat man einen Startpunkt, um den Fehler zu beheben.

Die Datei "textlog" im Verzeichnis /tmp gibt nun Auskunft über den Vorgang der Indizierung. Sehr wichtig dabei ist, dass die Angabe von "PARAMETERS ('MEMORY 100M')" zu einer Beschleunigung des Indizierungsvorgangs führt. Der Wert 100M bestimmt die Größe der Token und Mapping Tabelle im Memory, bevor die Informationen in die entsprechenden Tabellen geschrieben werden. Der Vorgang wird so lange wiederholt bis der Index erzeugt worden. Daher ist es sehr sinnvoll den Parameter Memory zu setzen und den Wert so gross wie möglich zu wählen. Folgender Ausschnitt zeigt ein Beispiel einer Logtabelle und gibt Aufschluss über die Nutzung des Memory Parameters.

Oracle Text, 11.1.0.6.0
14:00:28 10/24/08 begin logging
14:00:49 10/24/08 populate index: COMP.TEXT_COMP
14:00:49 10/24/08 Begin document indexing
14:00:49 10/24/08 100 documents indexed
14:00:49 10/24/08 200 documents indexed
14:00:49 10/24/08 300 documents indexed
14:00:49 10/24/08 400 documents indexed
14:00:49 10/24/08 500 documents indexed
...
14:01:58 10/24/08 118200 documents indexed
14:01:58 10/24/08 Errors reading documents: 0
14:01:58 10/24/08 Index data for 118236 documents to be written to database
14:01:58 10/24/08    memory use: 98846623
14:01:58 10/24/08 Begin sorting the inverted list.
14:01:58 10/24/08 End sorting the inverted list.
14:01:58 10/24/08 Writing index data ($I) to database.
14:02:06 10/24/08 Wrote 313223 rows (12067 big rows) to $I.
14:02:06 10/24/08 Writing index data ($R) to database.
14:02:06 10/24/08    index data written to database.
... 

Zusätzlich bietet die Verwendung des Package CTX_REPORT weitere Möglichkeiten, Informationen zum Textindex zu erhalten. Im folgenden sollen 2 Beipiele dies illustrieren.
Möchte man z.B. die Größe des Textindex herausfinden, kann der Aufruf von CTX_REPORT.INDEX_SIZE einen detaillierten Bericht dazu liefern. Abgesehen von der Gesamtgröße des Index erhält man eine detaillierte Auflistung über die Größe der zugehörigen $I, $K, $R Tabellen usw. und der Zuordnung zu den Tablespaces.
Folgender Abschnitt zeigt einen Auszug aus dem Report:

SQL> col ausgabe format a150
SQL> set long 2000000000 head off pagesize 10000
SQL> select ctx_report.index_size('TEXT_COMP') as ausgabe from dual;

===========================================================================
                       INDEX SIZE FOR COMP.TEXT_COMP
===========================================================================
TABLE:                               COMP.DR$TEXT_COMP$I
TABLESPACE NAME:                     USERS
BLOCKS ALLOCATED:                                                    13056
BLOCKS USED:                                                         12752
BYTES ALLOCATED:                                   106,954,752 (102.00 MB)
BYTES USED:                                         104,464,384 (99.63 MB)
LOB SEGMENT:                         COMP.SYS_LOB0000094903C00006$$
TABLE NAME:                          COMP.DR$TEXT_COMP$I
LOB COLUMN:                          TOKEN_INFO
TABLESPACE NAME:                     USERS
BLOCKS ALLOCATED:                                                        8

...

TOTALS FOR INDEX COMP.TEXT_COMP
---------------------------------------------------------------------------
TOTAL BLOCKS ALLOCATED:                                              16040
TOTAL BLOCKS USED:                                                   15487
TOTAL BYTES ALLOCATED:                             131,399,680 (125.31 MB)
TOTAL BYTES USED:                                  126,869,504 (120.99 MB)

Benötigt man ein zugehöriges CREATE INDEX Skript, ist es nicht notwendig, im Data Dictionary nach den Eigenschaften des Index zu suchen. Das einfache Ausführen der Funktion CREATE_INDEX_SCRIPT, liefert eine Liste von DDL Kommandos, die einen vergleichbaren Index erzeugen:

select ctx_report.create_index_script('TEXT_COMP') from dual
begin
  ctx_ddl.create_preference('"TEXT_COMP_DST"','DIRECT_DATASTORE');
end;
/

...
begin
  ctx_output.start_log('TEXT_COMP_LOG');
end;
/

create index "COMP"."TEXT_COMP"
  on "COMP"."COMP_TEST"
      ("TEXT")
  indextype is ctxsys.context
  parameters('
    datastore       "TEXT_COMP_DST"
    filter          "TEXT_COMP_FIL"
    section group   "TEXT_COMP_SGP"
    lexer           "TEXT_COMP_LEX"
    wordlist        "TEXT_COMP_WDL"
    stoplist        "TEXT_COMP_SPL"
    storage         "TEXT_COMP_STO"
  ')
/

begin
  ctx_output.end_log;
end;
/

Wer allerdings schon Oracle Database 11g einsetzt und die Möglichkeit besitzt auf Enterprise Manager Database Control zuzugreifen, kann sich das Skripting sparen. Alle hier aufgelisteten Funktionalitäten sind durch einfaches Navigieren im Text Manager unter "Schema => Text Indexes" zu finden.

Beliebte Postings