Rozšíření o pokročilé fulltextové funkce a podporu formátu XML umožňující bezproblémový přenos strukturovaných dat v heterogenních prostředích.
Fulltext - Příklad 4
Mějme sadu dokumentů uložených na disku. Cílem je obsah dokumentů zaindexovat a umožnit v nich fulltextově vyhledávat.
Nástin řešení:
Je nutné si uvědomit, že dokumenty v tomto případě nejsou uloženy v databázových tabulkách a přístup k nim je složitější, nicméně z hlediska návrhu ftx systému se jedná pouze o jeden změněný přepínač oproti předchozímu příkladu.
Indexace souborů může probíhat buď zcela v režii SQL serveru nebo se může o část práce (a zatížení) podělit s klientem. Klient může sám rozebrat soubor na slova a serveru pouze zasílat jednotlivá slova k indexování. Tím se může zvýšit výkon serveru, neboť nemusí komunikovat s externími programy a dělá jen to, na co je optimalizovaný, tj. vkládání a indexování dat. Dále v textu si ukážeme oba způsoby indexování.
Aby fulltextové jádro vědělo o externích souborech, je nezbytné, aby plná jména souborů byla uložena v databázové tabulce. Pokud tedy je cílem indexovat existující soubory, musí nějaký program předem přečíst jména souborů a uložit je do databáze. POZOR! Cesta k souboru musí být vztažena k počítači, kde běží SQL server (pokud soubory čte server) nebo k počítači, kde je spuštěn klient (v případě načítání souborů klientskou aplikací).
V řešení si ukážeme manuální indexování (tj. zde indexování odložené na pozdější vhodnou dobu menší zátěže). Budeme proto muset více programovat, nelze již kompletně řešení „naklikat“ z Vývojového prostředí.
Pokud by indexování externích souborů na disku bylo jediným cílem autora, bez návaznosti na databázovou aplikaci, pak lze nalézt jiné specializované indexovací programy, které tuto činnost mohou provádět s výrazně menší režií a tedy rychleji a spolehlivěji.
Vytvoření fulltextu
Tabulka TAB_FT_4 má následující strukturu:
Definice je výrazně jednodušší než v předchozích příkladech: obsahuje sloupec JMENO_SOUBORU, do něhož se bude zapisovat plná cesta k indexovanému souboru. Dále je zde boolovský sloupec INDEXOVANO, do něhož budeme při odložené indexaci zaznamenávat, jestli byl záznam již zaindexován.
POZOR! Cesta musí být uvedena z hlediska počítače, kde je spuštěn program, který čte soubory, což může být jinde než je spuštěno Vývojové klientské prostředí, v němž objekty definujeme!
V tomto popisu neřešíme, jakým způsobem bude aplikace nebo uživatelé vkládat cesty k souborům do tabulky, to záleží na konkrétní aplikaci. Pro práci se soubory je nutné nějaké klientské programátorské rozhraní, jazyk SQL serveru práci se soubory nezná.
Vytvoření fulltextového systému pro obě varianty (klientskou i serverovou) je z počátku stejné: vytvoří se pouze jakási kostra systému bez pokynů k indexaci – ty jsou přenechány funkci Fulltext_index_doc, která se volá buď z jazyka SQL (varianta server) nebo z klientského jazyka (varianta klient).
Návrh fulltextu v návrháři se ukončí před definováním fulltextových triggerů. Systém tedy ví, v jakém jazyce budou dokumenty, že se mají slova lemmatizovat, že se prohlíží ZIPy, ale neprovádí to vše automaticky, protože nezná soubory k indexaci.
Odbočka k automatickému indexování serverem
Aby byl popis kompletní, ukažme si i variantu (a v ní dva různé způsoby) automatického indexování serverem: 1) pomocí ftx triggerů v návrháři fulltextu nebo 2) pomocí normálních SQL triggerů.
Ad 1)
Pro toho, kdo četl předchozí příklady nebude problémem vytvořit příslušný ftx trigger:
Jedinou novinkou je zde zapnutí příznaku Nepřímý v definici ftx triggeru, který se říká, že text ve sloupci JMENO_SOUBORU není přímo text k indexování, ale jen odkaz na soubor na disku. Pokud by všechny soubory byly jednoho typu, je efektivnější v poli Formát zvolit příslušný typ souboru, indexování pak bude o něco rychlejší.
Ad 2)
Návrh fulltextu ponecháme bez ftx triggerů a vytvoříme triggery v jazyce SQL, nad nimiž máme lepší kontrolu, nicméně tím neřešíme odložení indexování na jinou dobu. Budeme potřebovat minimálně triggery dva – pro vkládání a smazání záznamu. Pokud může nastat změna (přepis) ve sloupci se jménem souboru, zachytí ji trigger třetí.
Trigger pro indexaci při vložení záznamu:
TRIGGER `ft4_ins` AFTER INSERT ON `TAB_FT_4`
REFERENCING NEW AS `nove`
FOR EACH ROW
WHEN (nove.jmeno_souboru IS NOT NULL)
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE 'W0226', SQLSTATE 'W6005' BEGIN
CALL Log_write("Indexace souboru "+nove.jmeno_souboru+" se nezdařila.
Číslo chyby: "+SQLSTATE);
END;
CALL Fulltext_index_doc('.ftx_priklad4', nove.id, nove.jmeno_souboru, '', 1);
END
Trigger pro odstranění slov indexu při smazání záznamu:
TRIGGER `ft4_del` AFTER DELETE ON `TAB_FT_4`
REFERENCING OLD AS `stare`
FOR EACH ROW
BEGIN
CALL Fulltext_remove_doc(".ftx_priklad4", stare.id);
END
Trigger pro přeindexaci při změně ve sloupci:
TRIGGER `ft4_upd` AFTER UPDATE OF `JMENO_SOUBORU` ON `TAB_FT_4`
REFERENCING NEW AS `nove`
FOR EACH ROW
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE 'W0226', SQLSTATE 'W6005' BEGIN
CALL Log_write("Indexace souboru "+nove.jmeno_souboru+" se nezdařila.
Číslo chyby: "+SQLSTATE);
END;
CALL Fulltext_index_doc('.ftx_priklad4', nove.id, nove.jmeno_souboru, '', 1);
END
Dále se již automatickému indexování v tomto příkladu nebudeme věnovat.
a) Varianta manuálního indexování serverem
V tomto případě bude třeba „jednou a čas“, např. v noci, spustit SQL proceduru, která vybere nové, dosud nezaindexované záznamy a ty zaindexuje. Procedura může vypadat takto:
PROCEDURE Odlozene_indexovani( );
BEGIN
DECLARE i,j INTEGER DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLSTATE 'W0226', SQLSTATE 'W6005' BEGIN
CALL Log_write("Indexace souboru "+nove.jmeno_souboru+" se nezdařila.
Číslo chyby: "+SQLSTATE);
END;
FOR radek AS cx CURSOR FOR
SELECT id, jmeno_souboru, indexovano
FROM Tab_ft_4
WHERE NOT indexovano AND jmeno_souboru IS NOT NULL
DO
IF Fulltext_index_doc('.ftx_priklad4', radek.id, radek.jmeno_souboru, '', 1)
THEN
SET i = i+1;
ELSE
SET j = j+1;
END IF;
UPDATE SET indexovano = TRUE WHERE CURRENT OF cx;
END FOR;
CALL log_write(Int2str(i)+' dokumentů indexováno, '+Int2str(j)+' s chybou');
END
V proceduře musí být deklarován CONTINUE handler pro chyby, které mohou nastat v souvislosti s indexací – v opačném případě by procedura skončila na prvním výskytu chyby (tj. na první indexaci souboru, který buď nenajde nebo nedokáže poznat formát).
b) Varianta indexování klientem
Indexování klientem je vždy manuální a spočívá v tom, že klientská aplikace sama najde soubory, rozebere je na slova a ta zasílá serveru, který si je ukládá do systémových fulltextových tabulek. Tím může poněkud ulehčit práci SQL serveru, který se nemusí starat o práci se soubory. Při návrhu je třeba uvažovat další faktory: pokud je klientský program na stejném počítači jako sever (často v PHP skriptech), tak je počítač zatížen podobně jako v případě, že indexaci provádí sám server, pokud je klientský program na jiném počítači v síti, pak se indexují soubory uložené na počítači klienta, což nemusí být praktické.
Ukázka použití v jazyce Pascal v Delphi:
procedure TForm1.ButtonIndexClick(Sender: TObject);
var
i,max,err : integer;
id : integer;
filename : string;
begin
Memo1.Lines.Clear;
with SQL602DataSet1 do begin
CommandType := dsctQuery;
CommandText := 'SELECT id,jmeno_souboru,indexovano FROM Tab_ft_4
WHERE NOT indexovano AND jmeno_souboru IS NOT NULL';
Open;
max := RecordCount;
First;
for i := 1 to max do
begin
Next;
id := Fields.Fields[0].AsInteger;
filename := Fields.Fields[1].AsString;
if cd_Fulltext_index_doc(SQL602Conn.cdp,'Ft_dev.ftx_priklad4',id,
Pchar(filename),'') then
Memo1.Lines.Add('OK'+' '+inttostr(i)+' '+inttostr(id)+' '+filename)
else begin
err := SQL602Conn.sz_error;
Memo1.Lines.Add('FAILED'+' '+inttostr(i)+' '+inttostr(err)+' '+filename);
end;
end;
Close;
end;
end;
