четверг, 9 июня 2011 г.

Индекс для контекстного поиска на основе функции

   В Oracle есть замечательная возможность осуществлять контекстный поиск по тексту, который в явном виде не хранится в таблице. Для того, чтобы воспользоваться этой возможностью необходимо написать функцию, которая по rowid целевой таблицы построит соответсвующую ей текстовую строку строку.
   Прототип данной функции, или скорее процедуры, т.к. это процедура выглядит так:
   procedure ctx_foo(p_rid in rowid, p_ctx_text in out nocopy varchar2);
   p_rid - rowid таблицы, в которой находятся данные, которые мы будем искать
   p_ctx_text - текст, который мы проиндексируем контекстным индексом для дальнейшего применения функции CONTAINS.
   Далее надо настроить контекстный индекс при помощи функций: создать perference в словаре Oracle при помощи процедуры ctx_ddl.create_preference и установить его атрибуты при помощи процедуры ctx_ddl.set_attribute.
   Теперь создаём контексный индекс, на любую колонку тип которой: VARCHAR2, CLOB, BLOB, CHAR, BFILE, XMLType, URIType.
   create index <index_name> on <table_name(column_name) indextype is ctxsys.context parameters('<params>')
   Подробности про параметры можно прочитать по ссылке: http://download.oracle.com/docs/cd/E11882_01/text.112/e16594/ind.htm#i1006887
   Ниже я приведу пример создания контекстного индекса, у котрого строка для индексации генерируется процедурой.
   Создаём таблицы и заполняем их исходными данными.
create table ctx_source(
 grp number,
 word varchar2(32),
 pos number);
insert into ctx_source values (1, 'Oracle', 1);
insert into ctx_source values (1, 'database', 2);
insert into ctx_source values (1, '11g', 3);
insert into ctx_source values (2, 'Mary', 1);
insert into ctx_source values (2, 'had', 2);
insert into ctx_source values (2, 'a', 3);
insert into ctx_source values (2, 'little', 4);
insert into ctx_source values (2, 'lamb', 5);
insert into ctx_source values (3, 'Lamb', 1);
insert into ctx_source values (3, 'with', 2);
insert into ctx_source values (3, 'sauce', 3);
create table ctx_foo (
 id number,
 ctx_text varchar2(1));
insert into ctx_foo(id) values (1);
insert into ctx_foo(id) values (2);
insert into ctx_foo(id) values (3);
   Создаём пакеты с функциями
create or replace
package ctx as
 procedure ctx_foo(p_rid in rowid, p_ctx_text in out nocopy varchar2);
 function print_foo(p_id in number)  return varchar2;
end ctx;
create or replace
package body ctx as
 procedure ctx_foo(p_rid in rowid, p_ctx_text in out nocopy varchar2)
 is
 begin
   for r in (select word
             from ctx_source
             where grp = (select id from ctx_foo where rowid = p_rid)
             order by pos)
   loop
     p_ctx_text := p_ctx_text || r.word || ' ';
   end loop;
   p_ctx_text := rtrim(p_ctx_text);
 end ctx_foo;
 function print_foo(p_id in number) return varchar2
 is
   l_return varchar2(256);
 begin
   for r in (select word
             from ctx_source
             where grp = p_id
             order by pos)
   loop
     l_return := l_return || r.word || ' ';
   end loop;
   return rtrim(l_return);
 end print_foo;
end ctx;
   Создаём perference
exec ctx_ddl.create_preference( 'foo_datastore', 'user_datastore' );
exec ctx_ddl.set_attribute('foo_datastore', 'procedure', 'ctx.ctx_foo');
exec ctx_ddl.set_attribute('foo_datastore', 'output_type', 'varchar2');
   Создаём индекс на основе нашего perference
create index index_ctx_foo on ctx_foo(ctx_text)  indextype is ctxsys.context parameters( 'datastore foo_datastore sync (on commit)');
/*sync (on commit) необходимо, чтобы индекс обновлялся автоматически при втавке новых данных, этот параметр не обязательный*/
   Тестируем
select id, ctx.print_foo(id) from ctx_foo where contains(ctx_text,'lamb') > 0;
id  ctx.print_foo(id)
------------------------
2  Mary had a little lamb
3  Lamb with sauce
select id, ctx.print_foo(id) from ctx_foo where contains(ctx_text,'oracle') > 0;
id  ctx.print_foo(id)
------------------------
1   Oracle database 11g
   Желаю успешно использовать в своей работе контекстный индексы. У Oracle есть целый гайд работе с Oracle Text, прочитать его можно по адресу: http://download.oracle.com/docs/cd/E11882_01/text.112/e16594/toc.htm

Комментариев нет:

Отправить комментарий