prog:oracle_apex_oracle_text_document_archive
Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
Beide Seiten der vorigen RevisionVorhergehende Überarbeitung | |||
prog:oracle_apex_oracle_text_document_archive [2016/04/25 22:20] – [Tree Ansicht über die Einträge im Thesaurus] gpipperr | prog:oracle_apex_oracle_text_document_archive [2016/04/26 14:28] (aktuell) – [Mit Oracle APEX 5 und Oracle Text ein Dokumentenarchive für technische Dokumentation aufbauen] gpipperr | ||
---|---|---|---|
Zeile 1: | Zeile 1: | ||
+ | =====Mit Oracle APEX 5 und Oracle Text ein Dokumentenarchive für technische Dokumentation aufbauen===== | ||
+ | **Oracle 12c, APEX 5.0** | ||
+ | **Erstellt März 2016** | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | Aufgabe: | ||
+ | |||
+ | In Oracle APEX 5 soll ein einfaches Dokumentenarchive für die Volltext Suche über technischer Dokumentation erstellt werden. | ||
+ | |||
+ | Details: | ||
+ | |||
+ | * Die Dokumente verbleiben auf dem Fileserver im Dateisystem | ||
+ | * Der Text der binären Dokumente wie PDF, PowerPoint, Word etc. kann frei durchsucht werden | ||
+ | * Für das Wandeln in Text werden die Oracle Filter und eigene PDF Filter eingesetzt | ||
+ | * Die Dokumente werden über den Inhalt in in Kategorien, wie Java, Datenbank Entwicklung, | ||
+ | * Die Suche findet über eine APEX Suchmaske statt | ||
+ | |||
+ | |||
+ | Als Datenbank kommt eine Oracle 12c R1 als Standard Edition zum Einsatz, prinzipiell reicht aber auch eine Oracle XE. | ||
+ | |||
+ | Für den Volltext Index wird Oracle Text eingesetzt, mehr dazu im Detail siehe hier => [[dba: | ||
+ | |||
+ | |||
+ | |||
+ | === Vortrag === | ||
+ | |||
+ | |||
+ | Die Ergebnisse aus diesen kleinen Projekt werden auf der APEX Connect 2016 vorgestellt. | ||
+ | |||
+ | **<fc # | ||
+ | 26. bis 28. April.2016 in Berlin - Die größte Entwicklerkonferenz rund um Oracle PL/SQL und Oracle APEX in Deutschland | ||
+ | |||
+ | Mein Thema: <fc # | ||
+ | |||
+ | |||
+ | === Ablauf === | ||
+ | |||
+ | * Datenmodell für die Dokumenttabelle und die Pflege eines eigenen Thesaurus | ||
+ | * Ladeskript für die Dokumente in Python erstellen und Daten laden | ||
+ | * Filter Script für eigenen PDF Filter erstellen | ||
+ | * APEX Pflege Oberfläche für den Thesaurus | ||
+ | * Thesaurus pflegen und für Oracle Text erstellen | ||
+ | * Theme Index Information in der Datenbank hinterlegen | ||
+ | * Oracle Text Index konfigurieren | ||
+ | * Oracle Text Index auf den Dokumenten anlegen | ||
+ | * APEX Suchmaske für die Dokumente erstellen | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | ==== Datenmodell ==== | ||
+ | |||
+ | Die Dokumente werden als BFILE Referenz gespeichert. | ||
+ | |||
+ | |||
+ | Beim Laden werde soviel Metadaten wie möglich gleich mitgespeichert. | ||
+ | |||
+ | |||
+ | Dokumente - Tabelle DOCUMENTS | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | <code sql Documents.sql> | ||
+ | --------------------------------------------------------- | ||
+ | -- Document table | ||
+ | --------------------------------------------------------- | ||
+ | |||
+ | CREATE TABLE Documents | ||
+ | ( | ||
+ | ID NUMBER (30) NOT NULL , | ||
+ | Filename | ||
+ | FileTyp | ||
+ | FileDirectory | ||
+ | FilePointer | ||
+ | MD5Hash | ||
+ | FileCreateDate | ||
+ | FileLastModify | ||
+ | Language | ||
+ | CreateDate | ||
+ | CreateUser | ||
+ | ChangeDate | ||
+ | ChangeUser | ||
+ | Theme_data_avaiable VARCHAR2 (1 CHAR) DEFAULT ' | ||
+ | ) ; | ||
+ | |||
+ | CREATE UNIQUE INDEX IDX_Documents_ID_PK ON Documents ( ID ASC ); | ||
+ | |||
+ | ALTER TABLE Documents ADD CONSTRAINT Document_PK PRIMARY KEY ( ID ) ; | ||
+ | |||
+ | COMMENT ON TABLE Documents IS ' | ||
+ | COMMENT ON COLUMN Documents.ID IS ' | ||
+ | COMMENT ON COLUMN Documents.Filename IS 'Name of the file on disk' ; | ||
+ | COMMENT ON COLUMN Documents.FileTyp IS 'Typ of the file' ; | ||
+ | COMMENT ON COLUMN Documents.FileDirectory IS ' | ||
+ | COMMENT ON COLUMN Documents.FilePointer IS 'Bfile Pointer to the File' ; | ||
+ | COMMENT ON COLUMN Documents.MD5Hash IS 'Hash of the files to indentify dublicate files' ; | ||
+ | COMMENT ON COLUMN Documents.FileCreateDate IS 'File Create Time from the file' ; | ||
+ | COMMENT ON COLUMN Documents.FileLastModify IS 'Last modificatoin date from the file' ; | ||
+ | COMMENT ON COLUMN Documents.Language IS ' | ||
+ | COMMENT ON COLUMN Documents.CreateDate IS 'Date when the record was created' | ||
+ | COMMENT ON COLUMN Documents.CreateUser IS 'User create the record' | ||
+ | COMMENT ON COLUMN Documents.ChangeDate IS 'Last Change on the record' | ||
+ | COMMENT ON COLUMN Documents.ChangeUser IS 'User change the record' | ||
+ | COMMENT ON COLUMN Documents.Theme_data_avaiable IS 'If Themdata is there => Y, if not N' ; | ||
+ | |||
+ | --------------------------------------------------------- | ||
+ | |||
+ | create sequence documents_seq; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Thesaurus - Tabelle THESAURUS | ||
+ | |||
+ | <code sql thesaurus.sql> | ||
+ | |||
+ | --------------------------------------------------------- | ||
+ | -- thesaurus tables | ||
+ | --------------------------------------------------------- | ||
+ | drop table thesaurus cascade constraint | ||
+ | / | ||
+ | create table thesaurus( | ||
+ | | ||
+ | , | ||
+ | , | ||
+ | ) | ||
+ | / | ||
+ | --pk | ||
+ | create unique index idx_thesaurus_id_pk on thesaurus ( id asc ); | ||
+ | alter table thesaurus add constraint thesaurus_pk primary key ( id ) ; | ||
+ | --uk | ||
+ | create unique index idx_thesaurus_name_uk on thesaurus (name); | ||
+ | --comment | ||
+ | comment on table thesaurus is 'the name and the meaning of the thesaurus' | ||
+ | comment on column thesaurus.id is ' | ||
+ | comment on column thesaurus.name is 'name of the thesaurus' | ||
+ | comment on column thesaurus.description is ' | ||
+ | |||
+ | --------------------- | ||
+ | drop table thesaurus_phrases | ||
+ | / | ||
+ | |||
+ | create table thesaurus_phrases( | ||
+ | | ||
+ | ,ths_id number(11) not null | ||
+ | ,phrase varchar2(255) not null | ||
+ | ) | ||
+ | / | ||
+ | --pk | ||
+ | create unique index idx_thesaurus_phrases_id_pk on thesaurus_phrases ( id asc ); | ||
+ | alter table thesaurus_phrases add constraint thesaurus_phrases_pk primary key ( id ) ; | ||
+ | --uk | ||
+ | create unique index idx_thesaurus_phrases_uk on thesaurus_phrases (phrase); | ||
+ | --comment | ||
+ | comment on table thesaurus_phrases is 'all phrases of this thesaurus'; | ||
+ | comment on column thesaurus_phrases.id is ' | ||
+ | comment on column thesaurus_phrases.ths_id is 'fk to the thesaurus name' ; | ||
+ | comment on column thesaurus_phrases.phrase is 'the phrase' | ||
+ | --------------------- | ||
+ | drop table thesaurus_relations cascade constraint | ||
+ | / | ||
+ | |||
+ | create table thesaurus_relations( | ||
+ | id number(11) not null | ||
+ | ,ths_id number(11) | ||
+ | ,thp_phrase number(11) not null | ||
+ | ,relation varchar2(3) not null | ||
+ | , | ||
+ | ) | ||
+ | / | ||
+ | create unique index idx_thesaurus_relations_pk on thesaurus_relations ( id asc ); | ||
+ | alter table thesaurus_relations add constraint thesaurus_relations_pk primary key ( id ) ; | ||
+ | |||
+ | --uk | ||
+ | create unique index idx_thesaurus_relations_uk on thesaurus_relations (ths_id, | ||
+ | |||
+ | --comment | ||
+ | comment on table thesaurus_relations is 'all relations of this thesaurus'; | ||
+ | comment on column thesaurus_relations.id is ' | ||
+ | comment on column thesaurus_relations.ths_id is 'fk to the thesaurus name' ; | ||
+ | comment on column thesaurus_relations.relation is 'the relation between the phrases' | ||
+ | comment on column thesaurus_relations.thp_phrase is 'from this phrase' | ||
+ | comment on column thesaurus_relations.thp_rel_phrase is 'to this phrase' | ||
+ | --------------------- | ||
+ | -- fk | ||
+ | --------------------- | ||
+ | alter table thesaurus_relations add constraint thesaurus_relations_t_fk foreign key (ths_id) references thesaurus (id); | ||
+ | alter table thesaurus_relations add constraint thesaurus_relations_p1_fk foreign key (thp_phrase) references thesaurus_phrases (id); | ||
+ | alter table thesaurus_relations add constraint thesaurus_relations_p2_fk foreign key (thp_rel_phrase) references thesaurus_phrases (id); | ||
+ | ------- | ||
+ | alter table thesaurus_phrases add constraint thesaurus_phrases_t_fk foreign key (ths_id) references thesaurus (id); | ||
+ | |||
+ | --------------------- | ||
+ | -- Sequence | ||
+ | --------------------- | ||
+ | drop sequence thesaurus_seq; | ||
+ | drop sequence thesaurus_phrases_seq; | ||
+ | drop sequence thesaurus_relations_seq; | ||
+ | |||
+ | create sequence thesaurus_seq; | ||
+ | create sequence thesaurus_phrases_seq; | ||
+ | create sequence thesaurus_relations_seq; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Über diese Tabellenstruktur lassen sich mehrere Thesaurus aufbauen und abbilden. | ||
+ | |||
+ | Aus den Daten in den Tabellen wird dann mit dem PL/SQL Package CTX_THES der eigentliche Thesaurus aufgebaut. | ||
+ | |||
+ | ---- | ||
+ | |||
+ | |||
+ | ==== Ladeskript für die Dokumente in Python erstellen und Daten laden ==== | ||
+ | |||
+ | Das Lade Script wird in Python erstellt. | ||
+ | |||
+ | |||
+ | |||
+ | === Vorbereitung -Directory Objekt anlegen und Rechte vergeben === | ||
+ | Über ein Directory Object wird der Einstieg in die Verzeichnisstruktur auf der Festplatte definiert. | ||
+ | |||
+ | In unseren Test Fall liegen die Daten unter " | ||
+ | |||
+ | Anlegen als SYS und Rechte vergeben: | ||
+ | <code sql> | ||
+ | sqlplus / as sysdba | ||
+ | #Directory anlegen | ||
+ | create directory INFO_ARCHIVE as ' | ||
+ | #Rechte vergeben | ||
+ | grant read,write on directory INFO_ARCHIVE to GPI; | ||
+ | </ | ||
+ | |||
+ | === Testdaten manuell einfügen === | ||
+ | Um den prinzipiellen Aufbau zu testen, können natürlich am Anfang ein paar Dokument zum Testen dort abgelegt werden. | ||
+ | |||
+ | Dazu einige auf Platte existierende Dokument unter dem Directory " | ||
+ | Hash und weitere Werte füllen wir später richtig mit der Laderoutine, | ||
+ | |||
+ | Um den Bfile Pointer zu setzen die Methode BFILENAME verwenden: | ||
+ | <code sql> | ||
+ | INSERT INTO documents (ID, | ||
+ | | ||
+ | INSERT INTO documents (ID, | ||
+ | VALUES | ||
+ | commit; | ||
+ | |||
+ | </ | ||
+ | |||
+ | === Lade Skript erstellen === | ||
+ | |||
+ | Die Detail zum Lade Script siehe dazu hier: [[prog: | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ====Filter Script für eigenen PDF Filter von "Foxit PDF IFilter" | ||
+ | |||
+ | Über ein Script wird der Inhalt einer Datei in reinen Text bzw. HTML Text gewandelt. Auf diesen Text basiert dann auch die Volltext Suche über die binären Dokumente wie PDF, | ||
+ | |||
+ | Siehe dazu auch => [[dba: | ||
+ | |||
+ | |||
+ | |||
+ | Für die PDF Dateien wird auf den Filter von https:// | ||
+ | |||
+ | Download Foxit PDF IFilter (30 Tage Trial für den ersten Test von https:// | ||
+ | |||
+ | |||
+ | === Installation Foxit PDF IFilter | ||
+ | |||
+ | Testsystem ist eine Windows 10 Workstation | ||
+ | |||
+ | * Für die Installation Datei FoxitPDFIFilter311_Server_x64_enu.msi starten | ||
+ | * Dialoge nacheinander bestätigen, | ||
+ | * Am Ende wird dann noch nach der Lizenz gefragt, nach 30 Tage läuft dann das ab | ||
+ | |||
+ | |||
+ | Test ob der Filter auch registriert ist: | ||
+ | |||
+ | {{ : | ||
+ | === Microsoft Windows Search per Script ansprechen === | ||
+ | |||
+ | Der PDF Filter ist für das Microsoft [[https:// | ||
+ | |||
+ | |||
+ | Um das in einem Script zu verwenden kann dazu das Werkzeug **[[https:// | ||
+ | Das Programm dient eigentlich dazu die Filter zu testen. | ||
+ | |||
+ | |||
+ | Das Programm ist unter anderen in der " | ||
+ | |||
+ | |||
+ | Datei herunterladen und entpacken, z.b. nach D: | ||
+ | |||
+ | Erster Test führt aber zum Fehler **<fc # | ||
+ | <code powershell> | ||
+ | cd D: | ||
+ | |||
+ | .\FiltDump.exe -b D: | ||
+ | |||
+ | FILE: D: | ||
+ | |||
+ | Error 0x80004005 loading IFilter | ||
+ | |||
+ | </ | ||
+ | |||
+ | Das ist dann aber nicht so recht das gewünschte Ergebnis ... ist ein 64bit Problem, Filtdump.exe ist in diesem Download nur 32Bit tauglich! | ||
+ | |||
+ | Nach etwas Internet Recherche könnte das Programm auch in MS SDK enthalten sein. Leider ist das auch nicht so klar was und wo da nun genau das richtige ist. | ||
+ | |||
+ | Habe daher als nächstes das Windows 10 SDK über https:// | ||
+ | |||
+ | Leider ist es nicht so klar in welchen Packet dort das Programm FiltDump.exe wirklich steckt. | ||
+ | |||
+ | Mit den folgenden ausgewählten Featuren war es dann aber dabei: | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | |||
+ | Nächster Test: | ||
+ | <code powershell> | ||
+ | cd C:\Program Files (x86)\Windows Kits\10\bin\x64 | ||
+ | |||
+ | |||
+ | .\FiltDump.exe -b D: | ||
+ | |||
+ | # viel Text wird angezeigt, aber keine echten Strukturen .... | ||
+ | # hmm hatte mehr erwartet | ||
+ | |||
+ | </ | ||
+ | |||
+ | Das kann nun in eine Script eingebaut werden und damit lassen sich nun alle Filter die Microsoft auf dem System kennt verwenden! | ||
+ | |||
+ | Nun kann auch einfach überprüft werden welcher Filter mit welcher DDL für was eingesetzt wird: | ||
+ | <code powershell> | ||
+ | | ||
+ | |||
+ | ... | ||
+ | .pdf --> Foxit PDF Filter (C:\Program Files\Foxit Software\Foxit PDF IFilter\PDFFilt.dll) | ||
+ | ... | ||
+ | </ | ||
+ | |||
+ | |||
+ | === USER_FILTER Script für den IFilter mit FiltDump=== | ||
+ | |||
+ | Der ersten Entwurf, der aber so nicht funktioniert, | ||
+ | <code dos> | ||
+ | @echo off | ||
+ | echo PARAM 1: %1 >> d: | ||
+ | echo PARAM 2: %2 >> d: | ||
+ | |||
+ | set FILTDUMP_HOME=C: | ||
+ | |||
+ | " | ||
+ | </ | ||
+ | |||
+ | Testweise aufrufen und pürfen ob Daten erzeugt wurden | ||
+ | <code powershell> | ||
+ | D: | ||
+ | </ | ||
+ | |||
+ | |||
+ | Und schon das nächste Problem, wird der Index angelegt und damit das Script im Scope des Oracle Users aufgerufen, erhalten ich eine <fc # | ||
+ | |||
+ | |||
+ | Das Problem liegt wohl daran das Windows eine Datei Endung erwartet und von Oracle aber nur eine Datei OHNE Endung erhält. | ||
+ | |||
+ | |||
+ | Jetzt wird es kompliziert, | ||
+ | |||
+ | Wir müssen nun mit einem Tool wie " | ||
+ | |||
+ | Version 2, nun mit Erkennung des Datei Types und beiden Filteren: | ||
+ | <code dos> | ||
+ | @echo off | ||
+ | |||
+ | echo -- Start Filter at : %date% %time% >> d: | ||
+ | echo -- Info: PARAM 0 : %0 >> d: | ||
+ | echo -- Info: PARAM 1 : %1 >> d: | ||
+ | echo -- Info: PARAM 2 : %2 >> d: | ||
+ | |||
+ | set ORACLE_HOME=D: | ||
+ | set FILTDUMP_HOME=C: | ||
+ | set MAGIC_HOME=D: | ||
+ | |||
+ | rem use fixed path, error get result as oracle job??? | ||
+ | for /f %%i in (' | ||
+ | |||
+ | echo -- Info: File type : %FILE_TYPE% >> d: | ||
+ | |||
+ | IF %FILE_TYPE% NEQ PDF goto ORACLE_FILTER | ||
+ | |||
+ | :FILTER_PDF | ||
+ | echo -- Info: Use Filter: iFilter | ||
+ | copy %1 %1.pdf 2>> d: | ||
+ | " | ||
+ | del %1.pdf 2>> d: | ||
+ | goto END | ||
+ | |||
+ | : | ||
+ | echo -- Info: Use Filter: Oracle | ||
+ | %ORACLE_HOME%/ | ||
+ | |||
+ | :END | ||
+ | echo -- End Filter at : %date% %time% >> d: | ||
+ | echo -- ============================= | ||
+ | </ | ||
+ | |||
+ | Allerdings ist das ganze nicht wirklich stabil, nach ein paar Versuchen wieder ORA-07445 Fehler erhalten! | ||
+ | |||
+ | Nach einiger Suche sind das PDF Dokument mit Password!!, die bleiben anscheinend dann wohl im Hintergrund hängen und warten auf ein Passwort! | ||
+ | |||
+ | |||
+ | |||
+ | Besser wäre natürlich eine direkte Integration in der PowerShell oder ähnlich, hier dazu ein paar Anregungen dazu: | ||
+ | |||
+ | * http:// | ||
+ | * http:// | ||
+ | * https:// | ||
+ | * https:// | ||
+ | |||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ====APEX Pflege Oberfläche für den Thesaurus==== | ||
+ | |||
+ | Für die Pflege des Thesaurus wird eine einfache Formular Maske in APEX generiert. | ||
+ | |||
+ | siehe http:// | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | Beispiel für das SQL um den Baum aufzubauen: | ||
+ | <code sql> | ||
+ | select | ||
+ | , level | ||
+ | , name as title | ||
+ | , ' | ||
+ | , id as value | ||
+ | , tooltip as tooltip | ||
+ | , case when item_type = ' | ||
+ | | ||
+ | else | ||
+ | null | ||
+ | end as link | ||
+ | from (select ' | ||
+ | , thes.name as label | ||
+ | , to_char (thes.id) as id | ||
+ | , null as parent | ||
+ | , thes.name name | ||
+ | , thes.name as tooltip | ||
+ | , null link | ||
+ | from thesaurus thes | ||
+ | union all | ||
+ | select ' | ||
+ | , tp.phrase as label | ||
+ | , to_char (tp.id) || ' | ||
+ | , to_char (tp.ths_id) parent | ||
+ | , tp.phrase as name | ||
+ | , tp.phrase as tooltip | ||
+ | , to_char (tp.id) link | ||
+ | from thesaurus_phrases tp | ||
+ | union all | ||
+ | | ||
+ | , rs.relation label | ||
+ | , to_char (rs.id)||' | ||
+ | , to_char (rs.thp_phrase) || ' | ||
+ | , '-> Relation :' | ||
+ | , rs.relation || ' ' || tp_rel.phrase tooltip | ||
+ | , to_char (rs.id) idlink | ||
+ | from thesaurus_relations rs inner join thesaurus_phrases tp_rel on (rs.thp_rel_phrase = tp_rel.id) | ||
+ | ) | ||
+ | start with parent is null | ||
+ | connect by prior id = parent | ||
+ | order siblings by name | ||
+ | </ | ||
+ | |||
+ | Der eigentliche Thesaurus wird dann über PL/SQL aus den Texteinträgen in dieser Thesaurus Tabelle erzeugt. | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ====Thesaurus pflegen und für Oracle Text erstellen, Theme Information in der Datenbank hinterlegen==== | ||
+ | |||
+ | Aus den Tabelleneinträgen für unseren Thesaurus wird mit dem PL/SQL Package " | ||
+ | |||
+ | Das hätte auch über eine Text Datei stattfinden können, so ist das aber deutlich einfacher in der Pflege. | ||
+ | |||
+ | |||
+ | |||
+ | Siehe dazu auch => [[dba: | ||
+ | |||
+ | |||
+ | Die ersten Daten des Thesaurus werden per SQL in die DB eingespielt, | ||
+ | |||
+ | <code sql> | ||
+ | |||
+ | variable THS_ID number | ||
+ | variable THP_PHRASE number | ||
+ | variable THP_REL_PHRASE number | ||
+ | |||
+ | |||
+ | insert into THESAURUS ( id ,name , | ||
+ | values ( thesaurus_seq.nextval,' | ||
+ | |||
+ | DOC | ||
+ | ----------------------------------- | ||
+ | # | ||
+ | Pascal | ||
+ | SYN Delphi | ||
+ | | ||
+ | SQL | ||
+ | RT PL/SQL | ||
+ | Java | ||
+ | NT SCALA | ||
+ | NT Groovy | ||
+ | JavaScript | ||
+ | NT CoffeeScript | ||
+ | Python | ||
+ | NT Juliactx | ||
+ | ----------------------------------- | ||
+ | # | ||
+ | |||
+ | ------------------------- Pascal | ||
+ | |||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_phrases | ||
+ | |||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | ----------------------- SQL | ||
+ | |||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_phrases | ||
+ | |||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | ----------------------- Java | ||
+ | |||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_phrases | ||
+ | |||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | ----------------------- JavaScript | ||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_phrases | ||
+ | |||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | ----------------------- Python | ||
+ | insert into thesaurus_phrases | ||
+ | insert into thesaurus_phrases | ||
+ | |||
+ | insert into thesaurus_relations (id, | ||
+ | |||
+ | commit; | ||
+ | </ | ||
+ | |||
+ | Um dann den eigentlichen Thesaurus aufbauen zu können, wird eine PL/SQL Procedure verwandt, hier die einfachste Variante: | ||
+ | <code sql> | ||
+ | |||
+ | set serverout put on | ||
+ | |||
+ | CREATE OR REPLACE procedure createthesaurus | ||
+ | is | ||
+ | cursor c_thes | ||
+ | is | ||
+ | select * | ||
+ | from thesaurus | ||
+ | order by id; | ||
+ | |||
+ | cursor c_pharse (p_ths_id number) | ||
+ | is | ||
+ | select * | ||
+ | from thesaurus_phrases | ||
+ | where ths_id = p_ths_id | ||
+ | order by phrase; | ||
+ | |||
+ | cursor c_relation (p_ths_id number) | ||
+ | is | ||
+ | select p1.phrase | ||
+ | , p2.phrase as rel_phrase | ||
+ | , r.relation | ||
+ | from thesaurus_relations r | ||
+ | inner join thesaurus_phrases p1 | ||
+ | on (r.thp_phrase = p1.id) | ||
+ | inner join thesaurus_phrases p2 | ||
+ | on (r.thp_rel_phrase = p2.id) | ||
+ | where r.ths_id = p_ths_id; | ||
+ | begin | ||
+ | for trec in c_thes | ||
+ | loop | ||
+ | -- löschen und neu anlegen | ||
+ | dbms_output.put_line ('-- Info :: drop thesaurus ::' || trec.name); | ||
+ | |||
+ | begin | ||
+ | ctx_thes.drop_thesaurus (name => trec.name); | ||
+ | exception | ||
+ | when others | ||
+ | then | ||
+ | dbms_output.put_line ('-- Info :: drop thesaurus Error ::' || sqlerrm); | ||
+ | end; | ||
+ | |||
+ | -- create the empty thesaurus case insensitiv | ||
+ | dbms_output.put_line ('-- Info :: create thesaurus ::' || trec.name); | ||
+ | ctx_thes.create_thesaurus (name | ||
+ | , casesens | ||
+ | | ||
+ | |||
+ | --create a Phrase to the thesaurus | ||
+ | for prec in c_pharse (p_ths_id => trec.id) | ||
+ | loop | ||
+ | dbms_output.put_line ('-- Info :: create pharse ::' || prec.phrase); | ||
+ | ctx_thes.create_phrase (tname => trec.name | ||
+ | , phrase => | ||
+ | | ||
+ | end loop; | ||
+ | |||
+ | -- define a relation to this phrases | ||
+ | for rrec in c_relation (p_ths_id => trec.id) | ||
+ | loop | ||
+ | dbms_output.put_line ( | ||
+ | ' | ||
+ | ctx_thes.create_relation (tname | ||
+ | , | ||
+ | , | ||
+ | , | ||
+ | ); | ||
+ | end loop; | ||
+ | end loop; | ||
+ | end; | ||
+ | / | ||
+ | </ | ||
+ | |||
+ | Nach dem Aufruf mit "exec createthesaurus" | ||
+ | |||
+ | <fc # | ||
+ | |||
+ | Wenn nur die Thesaurus | ||
+ | |||
+ | Gerade am Testen, nur der Thesaurus kann auch ohne Neuaufbau verwendet werden, d.h. es können auch mehrere davon gleichzeitig eingesetzt werden. | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Thesaurus für den Theme Index übersetzen ==== | ||
+ | |||
+ | Vorhandenen Thesarus für den Theme Index übersetzen: | ||
+ | |||
+ | <code bash> | ||
+ | | ||
+ | </ | ||
+ | |||
+ | |||
+ | Bzgl. Theme siehe auch [[dba: | ||
+ | |||
+ | |||
+ | ---- | ||
+ | ====Oracle Text Index konfigurieren==== | ||
+ | |||
+ | |||
+ | Unser User GPI, unter dem der Oracle Text Index aufgebaut wird, benötigt die Rolle CTXAPP. | ||
+ | |||
+ | Vor dem Aufbau einer Oracle Text Indexes können die verschiedenen Parameter für den Index Aufbau konfiguriert werden. | ||
+ | |||
+ | <code sql> | ||
+ | |||
+ | -- zuvor als sys | ||
+ | sqlplus / as sysdba | ||
+ | |||
+ | grant CTXAPP to GPI; | ||
+ | grant all on ctxsys.ctx_thes to GPI; | ||
+ | |||
+ | -- als context User die Eigenschaften einstellen | ||
+ | connect admin | ||
+ | |||
+ | --- LEXER | ||
+ | EXEC ctx_ddl.create_preference( ' | ||
+ | EXEC ctx_ddl.set_attribute (' | ||
+ | |||
+ | -- STORAGE | ||
+ | -- Forward Indexing | ||
+ | -- Plain Text speichern | ||
+ | begin | ||
+ | ctx_ddl.create_preference | ||
+ | ( | ||
+ | preference_name => ' | ||
+ | object_name | ||
+ | ); | ||
+ | end; | ||
+ | / | ||
+ | exec ctx_ddl.set_attribute(' | ||
+ | exec ctx_ddl.set_attribute(' | ||
+ | </ | ||
+ | |||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ==== Oracle Text Index auf den Dokumenten anlegen==== | ||
+ | |||
+ | Index mit entsprechenden Eigenschaften dann anlegen | ||
+ | |||
+ | <code sql> | ||
+ | -- create the Oracle Text Index | ||
+ | -- Frist try with AUTO_FILTER | ||
+ | |||
+ | drop index idx_doc_files; | ||
+ | |||
+ | CREATE INDEX idx_doc_files ON documents(FilePointer) | ||
+ | | ||
+ | | ||
+ | LEXER GPI_LEXER | ||
+ | STORAGE | ||
+ | STOPLIST GPI_STOPLIST' | ||
+ | / | ||
+ | |||
+ | |||
+ | --Auf Fehler prüfen | ||
+ | SELECT * FROM ctx_user_index_errors; | ||
+ | |||
+ | |||
+ | -- | ||
+ | --Index tabellen anzeigen lassen | ||
+ | |||
+ | SELECT TABLE_NAME FROM user_tables WHERE TABLE_NAME LIKE ' | ||
+ | |||
+ | TABLE_NAME | ||
+ | ------------------- | ||
+ | DR$IDX_DOC_FILES$I | ||
+ | DR$IDX_DOC_FILES$R | ||
+ | DR$IDX_DOC_FILES$K | ||
+ | DR$IDX_DOC_FILES$N | ||
+ | |||
+ | |||
+ | --testen ob Text Tockens auch eingetragen wurden | ||
+ | |||
+ | select TOKEN_TEXT from DR$IDX_DOC_FILES$I where rownum < 10; | ||
+ | |||
+ | |||
+ | --prüfen ob der Theme Index auch geklappt hat | ||
+ | SELECT token_type FROM dr$idx_documents_docs$i GROUP BY token_type; | ||
+ | |||
+ | </ | ||
+ | |||
+ | Nun kann getestet werden ob eine erste Suche mit Hilfe eines Thesaurus auch erfolgreich ist: | ||
+ | |||
+ | <code sql> | ||
+ | SELECT * FROM DOCUMENTS WHERE contains(filepointer, | ||
+ | </ | ||
+ | |||
+ | |||
+ | ---- | ||
+ | |||
+ | ====APEX Suchmaske für die Dokumente erstellen==== | ||
+ | |||
+ | Über eine APEX Maske wird die Volltextsuche über die Dokumente gesteuert | ||
+ | |||
+ | Für die Suche über den Index wird dazu der Oracle Contains Operator (siehe [[prog: | ||
+ | |||
+ | In der Treffermenge soll ein Stück des gefundenen Text als Preview in jeder Trefferzeile angezeigt werden. | ||
+ | |||
+ | Der gefundene Text wird dabei farblich hervorgehoben. | ||
+ | |||
+ | Für die Aufbereitung der Trefferliste wird das [[https:// | ||
+ | |||
+ | ==== Tree Ansicht über die Einträge im Thesaurus ===== | ||
+ | |||
+ | Einfache Varianten nur auf Vorkommen der Suchwörter: | ||
+ | <code sql> | ||
+ | |||
+ | select | ||
+ | , level | ||
+ | , name as title | ||
+ | , ' | ||
+ | , id as value | ||
+ | , tooltip as tooltip | ||
+ | , case when item_type = ' | ||
+ | | ||
+ | else | ||
+ | null | ||
+ | end as link | ||
+ | from (select ' | ||
+ | , thes.name as label | ||
+ | , to_char (thes.id) as id | ||
+ | , null as parent | ||
+ | , thes.name||' | ||
+ | , thes.name as tooltip | ||
+ | , null link | ||
+ | from thesaurus thes | ||
+ | union all | ||
+ | select ' | ||
+ | , tp.phrase as label | ||
+ | , to_char (tp.id) || ' | ||
+ | , to_char (tp.ths_id) parent | ||
+ | , tp.phrase as name | ||
+ | , tp.phrase as tooltip | ||
+ | , to_char (tp.id) link | ||
+ | from thesaurus_phrases tp | ||
+ | union all | ||
+ | | ||
+ | , d.filename | ||
+ | , to_char (d.id)||' | ||
+ | , to_char (tp.id) || ' | ||
+ | , '-> Found :' | ||
+ | , score(1) || ' | ||
+ | , to_char (d.id) idlink | ||
+ | from documents d, | ||
+ | where contains(d.filepointer, | ||
+ | and contains(d.filepointer, | ||
+ | ) | ||
+ | start with parent is null | ||
+ | connect by prior id = parent | ||
+ | order siblings by name | ||
+ | </ | ||
+ | |||
+ | Sieht dann so aus: | ||
+ | |||
+ | {{ : | ||
+ | |||
+ | ---- | ||
+ | ==== Quellen ==== | ||
+ | |||
+ | Siehe jeweils die Detail Artikel |
prog/oracle_apex_oracle_text_document_archive.txt · Zuletzt geändert: 2016/04/26 14:28 von gpipperr