Firebird: Volltextindex
3 - Indizierung
Die Indizierung erfolgt in den SP's "prc_ftx_index_char" und "prc_ftx_index_text" wobei "prc_ftx_index_text" Text-BLOB's in für "prc_ftx_index_char" verarbeitbare Zeichenketten zerlegt und damit "prc_ftx_index_char" aufruft.SP "prc_ftx_index_char"
CREATE OR ALTER PROCEDURE "prc_ftx_index_char" (
IN_TEXT TYPE OF "dom_TextCache" COLLATE UTF8,
IN_WHOLE_WORD TYPE OF "dom_BOOL",
IN_WORD_BEGINNINGS TYPE OF "dom_BOOL",
IN_WORD_TRAILINGS TYPE OF "dom_BOOL",
IN_WORD_PARTS TYPE OF "dom_BOOL",
IN_MIN_WORD_PART_LENGTH TYPE OF "dom_WordLength" = 1,
IN_POSITION_OFFSET TYPE OF "dom_Position" = 0,
IN_WORD_INDEX_OFFSET TYPE OF "dom_Position" = 0)
RETURNS (
OUT_WORD_INDEX INTEGER)
AS
DECLARE VARIABLE TEXT_LEN TYPE OF "dom_Position"; /* Textlänge */
DECLARE VARIABLE WORD_INDEX TYPE OF "dom_Position"; /* aktueller Wortindex */
DECLARE VARIABLE WORD_START TYPE OF "dom_Position"; /* Wortstartposition im Text */
DECLARE VARIABLE WORD_STOP TYPE OF "dom_Position"; /* Wortendeposition im Text */
DECLARE VARIABLE CHAR_IS_ALPHANUM TYPE OF "dom_BOOL"; /* aktuell untersuchte Position */
/* ist alphanumerisch oder nicht */
BEGIN
/* Wortindex initialisieren */
WORD_INDEX = IN_WORD_INDEX_OFFSET;
/* Textlänge bestimmen */
TEXT_LEN = COALESCE(CHAR_LENGTH(IN_TEXT), 0);
IF (TEXT_LEN > 0)
THEN
BEGIN
WORD_START = 1;
WHILE (WORD_START <= TEXT_LEN)
DO
BEGIN
/* Wortanfang suchen */
EXECUTE PROCEDURE "prc_ftx_is_alpha_num"(SUBSTRING(IN_TEXT FROM WORD_START FOR 1))
RETURNING_VALUES CHAR_IS_ALPHANUM;
WHILE (
(WORD_START <= TEXT_LEN)
AND
(CHAR_IS_ALPHANUM = 0)
)
DO
BEGIN
WORD_START = WORD_START + 1;
IF (WORD_START <= TEXT_LEN)
THEN
EXECUTE PROCEDURE "prc_ftx_is_alpha_num"(SUBSTRING(IN_TEXT FROM WORD_START FOR 1))
RETURNING_VALUES CHAR_IS_ALPHANUM;
END
/* Wortanfang gefunden? */
IF (CHAR_IS_ALPHANUM = 0)
THEN
BREAK;
/* Wortende suchen */
WORD_STOP = WORD_START;
WHILE (
(WORD_STOP <= TEXT_LEN)
AND
(CHAR_IS_ALPHANUM = 1)
)
DO
BEGIN
WORD_STOP = WORD_STOP + 1;
IF (WORD_STOP <= TEXT_LEN)
THEN
EXECUTE PROCEDURE "prc_ftx_is_alpha_num"(SUBSTRING(IN_TEXT FROM WORD_STOP FOR 1))
RETURNING_VALUES CHAR_IS_ALPHANUM;
END
IF (WORD_STOP > WORD_START)
THEN
/* Wort extrahieren und indizieren */
EXECUTE PROCEDURE "prc_ftx_word_index"(
SUBSTRING(IN_TEXT FROM WORD_START FOR WORD_STOP - WORD_START),
WORD_START + IN_POSITION_OFFSET,
WORD_INDEX, IN_WHOLE_WORD,
IN_WORD_BEGINNINGS,
IN_WORD_TRAILINGS,
IN_WORD_PARTS,
IN_MIN_WORD_PART_LENGTH)
RETURNING_VALUES WORD_INDEX;
/* nächstes Wort */
WORD_START = WORD_STOP + 1;
END /* WHILE (WORD_START <= TEXT_LEN) */
END /* IF (TEXT_LEN > 0) */
/* Wortindex zurückgeben */
OUT_WORD_INDEX = WORD_INDEX;
END
Die SP "prc_ftx_index_char" zerlegt die Zeichenkette in einzelne Wörter, indem über die SP "prc_ftx_is_alpha_num" geprüft wird, ob das aktuelle Zeichen alphanumerisch ist oder nicht. Dabei werden die Position und der Index des Wortes im Text mitgezählt. In der SP "prc_ftx_word_index" wird dann jedes gefundene Wort mit der Worttabelle verknüpft.
Aufrufparameter
IN_TEXT | Die zu indizierende Zeichenkette. |
IN_WHOLE_WORD | 1: Es werden ganze Wörter in die Worttabelle eingetragen. |
IN_WORD_BEGINNINGS | 1: Es werden Wortanfänge (ohne ganzes Wort) in die Worttabelle eingetragen. |
IN_WORD_TRAILINGS | 1: Es werden Wortenden (ohne ganzes Wort) in die Worttabelle eingetragen. |
IN_WORD_PARTS | 1: Es werden die restlichen Wortteile in die Worttabelle eingetragen. |
IN_MIN_WORD_PART_LENGTH | Die minimale Länge von Wortteilen, die in die Worttabelle eingetragen werden. Ganze Wörter werden in jedem Fall eingetragen. |
IN_POSITION_OFFSET | Aktuelle Position im Text bei Aufruf durch "prc_ftx_index_text". |
IN_WORD_INDEX_OFFSET | Aktueller Index des Wortes im Text bei Aufruf durch "prc_ftx_index_text". |
SP "prc_ftx_word_index"
CREATE OR ALTER PROCEDURE "prc_ftx_word_index" (
IN_WORD "dom_Word" COLLATE UTF8,
IN_WORD_START "dom_Position",
IN_WORD_INDEX "dom_Position",
IN_WHOLE_WORD "dom_BOOL",
IN_WORD_BEGINNINGS "dom_BOOL",
IN_WORD_TRAILINGS "dom_BOOL",
IN_WORD_PARTS "dom_BOOL",
IN_MIN_WORD_PART_LENGTH "dom_WordLength" = 1)
RETURNS (
OUT_WORD_INDEX "dom_Position")
AS
DECLARE VARIABLE WORD_LENGTH "dom_WordLength"; /* Länge des Wortes */
DECLARE VARIABLE IDX "dom_WordLength"; /* Laufvariable 1 */
DECLARE VARIABLE IDY "dom_WordLength"; /* Laufvariable 2 */
BEGIN
OUT_WORD_INDEX = IN_WORD_INDEX;
WORD_LENGTH = COALESCE(CHAR_LENGTH(IN_WORD), 0);
IF (WORD_LENGTH > 0)
THEN
BEGIN
/* Wortindex aktualisieren */
OUT_WORD_INDEX = OUT_WORD_INDEX + 1;
/* Wort speichern */
IF (IN_WHOLE_WORD <> 0)
THEN
EXECUTE PROCEDURE "prc_ftx_word_link"(IN_WORD, OUT_WORD_INDEX, IN_WORD_START, 0,
IN_MIN_WORD_PART_LENGTH);
/* Wortanfänge speichern */
IF ((IN_WORD_BEGINNINGS <> 0) AND (WORD_LENGTH > 1))
THEN
BEGIN
IDX = 1;
WHILE (IDX < WORD_LENGTH)
DO
BEGIN
/* Wortteil speichern */
EXECUTE PROCEDURE "prc_ftx_word_link"(LEFT(IN_WORD, IDX), OUT_WORD_INDEX,
IN_WORD_START, 1, IN_MIN_WORD_PART_LENGTH);
/* nächster Teil */
IDX = IDX + 1;
END
END
/* Wortteile ohne Anfang und Ende speichern*/
IF ((IN_WORD_PARTS <> 0) AND (WORD_LENGTH > 2))
THEN
BEGIN
IDX = 2;
WHILE (IDX <= WORD_LENGTH - 1)
DO
BEGIN
IDY = IDX + 1;
WHILE (IDY <= WORD_LENGTH)
DO
BEGIN
/* Wortteil speichern */
EXECUTE PROCEDURE "prc_ftx_word_link"(
SUBSTRING(IN_WORD FROM IDX FOR IDY - IDX),
OUT_WORD_INDEX,
IN_WORD_START + IDX - 1,
2,
IN_MIN_WORD_PART_LENGTH);
/* nächster Teil */
IDY = IDY + 1;
END
/* nächster Teil */
IDX = IDX + 1;
END
END
/* Wortenden speichern */
IF ((IN_WORD_TRAILINGS <> 0) AND (WORD_LENGTH > 1))
THEN
BEGIN
IDX = 2;
WHILE (IDX <= WORD_LENGTH)
DO
BEGIN
/* Wortteil speichern */
EXECUTE PROCEDURE "prc_ftx_word_link"(
SUBSTRING(IN_WORD FROM IDX FOR WORD_LENGTH - IDX + 1),
OUT_WORD_INDEX, IN_WORD_START + IDX - 1,
3,
IN_MIN_WORD_PART_LENGTH);
/* nächster Teil */
IDX = IDX + 1;
END
END
END /* IF (WORD_LENGTH > 0) */
END
Die SP "prc_ftx_word_index" zerlegt das übergebene Wort und übergibt die einzelnen Bestandteile zusammen mit den Positionsangaben im Text an die SP "prc_ftx_word_link".
Aufrufparameter
IN_WORD | Das zu zerlegende Wort. |
IN_WORD_START | Position des Wortes im Text. |
IN_WORD_INDEX | Index des Wortes im Text. |
IN_WHOLE_WORD | 1: Es werden ganze Wörter in die Worttabelle eingetragen. |
IN_WORD_BEGINNINGS | 1: Es werden Wortanfänge (ohne ganzes Wort) in die Worttabelle eingetragen. |
IN_WORD_TRAILINGS | 1: Es werden Wortenden (ohne ganzes Wort) in die Worttabelle eingetragen. |
IN_WORD_PARTS | 1: Es werden die restlichen Wortteile in die Worttabelle eingetragen. |
IN_MIN_WORD_PART_LENGTH | Die minimale Länge von Wortteilen, die in die Worttabelle eingetragen werden. Ganze Wörter werden in jedem Fall eingetragen. |
SP "prc_ftx_word_link"
CREATE OR ALTER PROCEDURE "prc_ftx_word_link" (
IN_WORD "dom_Word" COLLATE UTF8,
IN_WORD_INDEX "dom_Position",
IN_WORD_POSITION "dom_Position",
IN_WORD_TYPE "dom_WordType",
IN_MIN_WORD_PART_LENGTH "dom_WordLength" = 1)
AS
DECLARE VARIABLE WORD_ID TYPE OF "dom_PK"; /* ID des Wortes in Tabelle words */
BEGIN
/* Wort speichern */
IF (
(IN_WORD_TYPE = 0) /* ganzes Wort */
OR
(CHAR_LENGTH(IN_WORD) >= IN_MIN_WORD_PART_LENGTH)
)
THEN
BEGIN
IN_WORD = LOWER(IN_WORD);
SELECT
"PK_wrd"
FROM
"words"
WHERE
LOWER("CL_wrd_word") = :IN_WORD
INTO
:WORD_ID;
IF (WORD_ID IS NULL)
THEN
INSERT INTO
"words"
("CL_wrd_word")
VALUES
(:IN_WORD)
RETURNING
"PK_wrd"
INTO
:WORD_ID;
/* Verknüpfung auf das Wort speichern */
INSERT INTO "_temp_text_link_words"
(
"FK_ttw_wrd",
"CL_ttw_index",
"CL_ttw_position",
"FK_ttw_wty"
)
VALUES
(
:WORD_ID,
:IN_WORD_INDEX,
:IN_WORD_POSITION,
:IN_WORD_TYPE
);
END
END
In der SP "prc_ftx_word_link" wird schließlich das Wort oder der Wortteil in die Worttabelle eingetragen. Die Verlinkung wird vorerst in eine temporäre Tabelle eingetragen und erst bei vollständiger Indizierung des Textes im Trigger in die entsprechende Linktabelle übertragen. Damit kann man dieses System leicht auf andere Tabellen mit eigenen Linktabellen adaptieren.
Aufrufparameter
IN_WORD | Das zu indizierende Wort. |
IN_WORD_INDEX | Index des Wortes im Text. |
IN_WORD_POSITION | Position des Wortes im Text. |
IN_WORD_TYPE | Der Worttyp aus der Tabelle "wort_types". |
IN_MIN_WORD_PART_LENGTH | Die minimale Länge von Wortteilen, die in die Worttabelle eingetragen werden. Ganze Wörter werden in jedem Fall eingetragen. |