Introdução ao Oracle Text – Parte 02


IV - Criação e Utilização de Índices Textuais

 

A estrutura geral do índice Oracle Text é um índice invertido, ou seja, uma lista de palavras existentes em um documento, com cada palavra tendo uma lista de documentos onde elas aparecem. É chamado de invertido porque é o inverso da forma usual de analisar um texto, que neste caso é uma lista de documentos onde cada documento contém uma lista de palavras.

 

É possível criar um índice texto como um índice extensível para o Oracle utilizar o SQL padrão, ou seja, o índice Oracle Text poderia operar como um índice do Oracle. Provendo assim, um nome pelo qual seria referenciado e manipulado através de expressões SQL padrão.

 

A opção em escolher um índice Oracle Text é influenciada por um rápido tempo

de resposta para consultas com as funções CONTAINS, CATSEARCH, e MATCHES do

Oracle Text, que consultam os tipos de índices CONTEXT, CTXCAT, e CTXRULE

respectivamente.

 

Tanto os índices baseados em função quanto os índices Oracle Text permitem

navegação, podendo utilizá-los intercalados. Assim, é possível usar, primeiramente, o

índice Oracle Text para remover todos os documentos que potencialmente coincidem com

o critério, e então, aplicam-se posteriormente, filtros tais como as funções existsNode() ou

extract() sobre o restante dos documentos

 

Como um exemplo simples, iremos criar e popular algumas tabelas que relacionam uma publicação com autor e editora.

 

--CRIAÇÃO DAS TABELAS PARA OS TESTES

 

CREATE TABLE PUBLICACAO (

  CODIGO_PUBLIC               VARCHAR2 (4)  NOT NULL,

  CODIGO_EDITORA              VARCHAR2 (4),

  CODIGO_AUTOR               VARCHAR2 (4),

  DESCRICAO_TITULO               VARCHAR2 (300));


CREATE TABLE AUTOR (

  CODIGO_AUTOR         VARCHAR2 (4)  NOT NULL,

  NOME_AUTOR_INVERTIDO  VARCHAR2 (250));

CREATE TABLE EDITORA (

  CODIGO_EDITORA         VARCHAR2 (4)  NOT NULL,

  NOME_EDITORA         VARCHAR2 (250));

 

 

  

--POPULANDO AS TABELAS

 

--TABELA AUTOR

INSERT INTO AUTOR VALUES('0001','Machado, Antônio Cláudio da Costa');

INSERT INTO AUTOR VALUES('0002','Houaiss, AnTOnio');

INSERT INTO AUTOR VALUES('0003','KNUTH, DONALD ERVIN');

--TABELA EDITORA

INSERT INTO EDITORA VALUES('0001','Manole');

INSERT INTO EDITORA VALUES('0002','Objetiva');

INSERT INTO EDITORA VALUES('0003','ADDISON WESLEY');

INSERT INTO EDITORA VALUES('0004','LTC');

--TABELA PUBLICACAO

INSERT INTO PUBLICACAO VALUES('0001','0001','0001','Código de Processo Civil Interpretado : artigo por artigo, parágrafo por parágrafo');

INSERT INTO PUBLICACAO VALUES('0002','0002','0002','Dicionário Houaiss da língua portuguesa');

INSERT INTO PUBLICACAO VALUES('0003','0002','0002','Dicionário Houaiss de sinônimos e antônimos');

INSERT INTO PUBLICACAO VALUES('0004','0003','0003','ART OF COMPUTER PROGRAMMING - V.3');

INSERT INTO PUBLICACAO VALUES('0005','0004','0003','MATEMATICA CONCRETA');

 

Neste momento apresento o primeiro problema, recuperar as publicações. Podemos fazer isso facilmente com o seguinte bloco de comandos sql:

 

SELECT

 P.DESCRICAO_TITULO,A.NOME_AUTOR_INVERTIDO,E.NOME_EDITORA

FROM

 AUTOR A, EDITORA E, PUBLICACAO P

WHERE

 P.CODIGO_AUTOR=A.CODIGO_AUTOR

AND

P.CODIGO_EDITORA=E.CODIGO_EDITORA

 

Teríamos como retorno:


sql-28-04-2008pic02.JPG
 

Neste momento desejamos fazer uma busca, por titulo(DESCRICAO_TITULO), nome do autor(NOME_AUTOR_INVERTIDO) e nome da editora(NOME_EDITORA), com as seguintes características:

 

1)                    A busca deverá ser feita com qualquer parte do nome.

2)                    A busca deve ser “case-insentive”.

3)                    A acentuação ou não deve ser irrelevante na busca. 

 

 

Para isso iniciaremos com a criação das preferências que serão utilizados na criação dos índices:

 

OBS.:O usuário para tanto deve ter privilégios em CTXPAA.

 

 

Begin

  Ctx_Ddl.Create_Preference ('mixed_case_lexer_pref','BASIC_LEXER');

  Ctx_Ddl.Set_Attribute ( 'mixed_case_lexer_pref', 'mixed_case', 'FALSE');

  Ctx_Ddl.Set_Attribute ( 'mixed_case_lexer_pref', 'base_letter','TRUE'); 

end;

 

 

O próximo passo é a criação dos índices, neste exemplo usaremos um índice do tipo CONTEXT.

 

create index MIX_TITULO_01_IDX on  PUBLICACAO(DESCRICAO_TITULO)

  indextype is ctxsys.context

  parameters ('LEXER MIXED_CASE_LEXER_PREF')  ;

 

 

create index MIX_NOM_AUTOR_01_IDX on  AUTOR(NOME_AUTOR_INVERTIDO)

  indextype is ctxsys.context

  parameters ('LEXER MIXED_CASE_LEXER_PREF')  ;

 

create index MIX_NOME_EDITORA_01_IDX on  EDITORA(NOME_EDITORA)

  indextype is ctxsys.context

  parameters ('LEXER MIXED_CASE_LEXER_PREF')  ;

 

 

Pronto, já podemos utilizar os índices criados para pesquisa, abaixo crio um bloco de código que permite a busca desejada:

 

SELECT

P.DESCRICAO_TITULO,A.NOME_AUTOR_INVERTIDO,E.NOME_EDITORA

FROM AUTOR A, EDITORA E, PUBLICACAO P

WHERE

P.CODIGO_AUTOR=A.CODIGO_AUTOR

AND

P.CODIGO_EDITORA=E.CODIGO_EDITORA

AND

(

CONTAINS( NOME_AUTOR_INVERTIDO, (:NOME_PESQ))>0

OR

CONTAINS(DESCRICAO_TITULO, (:NOME_PESQ))>0

OR

CONTAINS(NOME_EDITORA, (:NOME_PESQ))>0

)

 

 

 Fazendo a busca pelo nome AntôniO, teremos o seguinte retorno:

 

sql-28-04-2008pic01.JPG 

 

Como podemos constatar a busca foi “case-insensitive” e ignorou a posição do nome solicitado.

 

Notem que podemos realizar pesquisas com “OR” ou “AND” entradas como:

Antonio OR dicionario, são válidas, inclusive podemos deixar nosso código mais sofisticado de modo que automaticamente o mesmo procure múltiplas palavras em vários campos:

 

 

SELECT

P.DESCRICAO_TITULO,A.NOME_AUTOR_INVERTIDO,E.NOME_EDITORA

FROM AUTOR A, EDITORA E, PUBLICACAO P

WHERE

P.CODIGO_AUTOR=A.CODIGO_AUTOR

AND

P.CODIGO_EDITORA=E.CODIGO_EDITORA

AND

(

CONTAINS( NOME_AUTOR_INVERTIDO,replace((TRIM(:NOME_PESQ)),' ',' OR '))>0

OR

CONTAINS(DESCRICAO_TITULO, replace((TRIM(:NOME_PESQ)),' ',' OR '))>0

OR

CONTAINS(NOME_EDITORA, replace((TRIM(:NOME_PESQ)),' ',' OR '))>0

)

 

Obs: Apesar do TRIM, esse código necessita de uma função de tratamento para o caso do usuário digitar dois ou mais espaços no meio da busca, creio que é ótimo treino para o leitor.

 

Caso necessitemos “dropar”  essas preferências usamos o seguinte comando:

 

begin

  Ctx_Ddl.Drop_Preference ('mixed_case_lexer_pref');

end;     

 

No caso dos índices:

 

drop index MIX_TITULO_01_IDX;

drop index MIX_NOM_AUTOR_01_IDX;

drop index MIX_NOME_EDITORA_01_IDX;

 

 

Espero que tenham gostado e que seja muito útil a todos, no meu próximo artigo estarei combinando a busca textual exposta com a busca fonética e em grandes bases de dados, até a próxima!     

 

V - Referências :

  

Oracle Text – Reference – Release 9.2, March 2002 Part Nº A98518-01