Criação e uso de Busca Fonetizada em Base de Dados  Relacionais, em Português – Parte 03

Neste ponto podemos criar um aplicativo que realize a busca de modo a trazer, por exemplo, a palavra Edson e seu similar “fonético” em qualquer parte do nome, Edson Nascimento Fernades, Paulo Edison Do Nascimento, Jose Paulo edhison, etc...

Para ilustrar vou usar um exemplo de aplicativo, desenvolvido pelo meu amigo Cristiano Wilson Cruge, que pode ser facilmente adaptado para outras linguagens e usos.

O aplicativo é o seguinte, feito em Delphi7:

sql-30-09-2008pic09.JPG


O código fonte se encontra nos anexos, no final do artigo, para exemplificar vamos procurar “Rafael”, na base, obtemos o seguinte retorno:

sql-30-09-2008pic10.JPG


Dessa forma podemos implementar uma busca fonética mais eficiente para bases de dados maiores, implementando o uso de índices. Podemos inclusive potencializar a utilização desse tipo de busca com melhorias nos índices e uso de recursos textuais e de expressões regulares em bancos de dados.  

 

III - Anexos

 

-- Script 1

 

CREATE TABLE CLIENTE(

  CODIGO CHAR (08)  NOT NULL,

  NOME  VARCHAR2 (80)  NOT NULL,

  CONSTRAINT PK_CODIGO_CLIENTE

  PRIMARY KEY ( CODIGO )

   );

 

--Script 2

 

 --Carga da Tabela

 

 

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701023','ACUCENA RAFHAEL');

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701024','ADALTO PEREIRIA BARBOSA');

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701025','ADRIANA LUIS DOS SANTOS');

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701026','BENEDITO RUI BARBOSA');

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701027','BARTOLOMEU DIAS');

INSERT INTO CLIENTE (CODIGO,NOME) VALUES('31701028','CAMILA PITANGA NASCIMENTO DIAS');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701029','CAMILA PARKSON');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701030','CARLOS MAGNO RAFAEL');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701031','CARLOS LUIZ  AUGUSTO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701032','CHRISTIANA DE OLIVEIRA BARBOZA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701033','CRISTINA MARTINS FONSECA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701034','DANIEL BOOM');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701035','DANIELA BOOM NASCIMENTO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701036','DANIELLA BAUER');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701037','DAVI CARDOSO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701038','DAVID JACK NACIMENTO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701039','EDNA LUIZ GRANDE');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701040','EDINA CONCEIÇÃO DE ALMEIDA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701041','EDSON ARANTES DO NASCIMENTO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701042','EDISON NASCIMENTO BARBOSA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701043','FÁBIO MITSUAKI ISHIKAWA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701044','FABIO NOGUEIRA');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701045','FLÁVIO VESPASIANO NOBRE');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701046','FLAVIO DE OLIVEIRA FIGUEIREDO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701047','FRAVIO EDSON CELULAI');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701048','HELIO SOLAR CENTRO');

INSERT INTO CLIENTE (CODIGO,NOME)VALUES('31701049','ELIO FILHO DE APOLO');

COMMIT;

 

--Script 3

 

SELECT NOME,CODIGO FROM CLIENTE WHERE FONETIZAR(NOME)=FONETIZAR('CARLOS LUIZ AUGUSTO');

 

--Script 4

 

CREATE TABLE CLIENTE_FONETICA (

  DES_FONETICA VARCHAR2 (40)  NOT NULL,

  CODIGO  CHAR(08)  NOT NULL

   );

 

-- Script 5

 

CREATE OR REPLACE PROCEDURE FONETIZAR_CLIENTE

IS

  CURSOR CLIENTE_cur IS

    SELECT CODIGO, FONETIZAR(NOME) AS NOME_CLIENTE FROM CLIENTE;

  NOME_CLIENTE CLIENTE.NOME%TYPE;

  i INTEGER;

  j INTEGER;

  saida CLIENTE.NOME%TYPE;

BEGIN

  -- Apaga o indíce fonético

  DELETE FROM CLIENTE_FONETICA;

 

  FOR CLIENTE_REC IN CLIENTE_CUR LOOP

           -- Separa as palavras fonetizadas e salva na tabela MATERIAL_FONETICA

           NOME_CLIENTE := CLIENTE_REC.NOME_CLIENTE||' ';

           i := 1;

           WHILE TRUE LOOP

                            saida      := SUBSTR(NOME_CLIENTE, 1, INSTR(NOME_CLIENTE, ' '));

                            NOME_CLIENTE := SUBSTR(NOME_CLIENTE, INSTR(NOME_CLIENTE, ' ') + 1, LENGTH(NOME_CLIENTE));

                            saida := TRIM(saida);

                                                        IF LENGTH(saida) IS NULL THEN

                               EXIT;

                            END IF;

                            IF LENGTH(saida) <= 30 THEN

                               INSERT INTO CLIENTE_FONETICA (CODIGO, DES_FONETICA ) VALUES (CLIENTE_rec.CODIGO, saida);

                            END IF;

           END LOOP;

  END LOOP;

END FONETIZAR_CLIENTE;

/

 

 

--codigo fonte 1

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, FMTBcd, DB, DBClient, Provider, SqlExpr, Grids, DBGrids,

  StdCtrls, DBXpress;

 

type

  TForm1 = class(TForm)

    Edit1: TEdit;

    Button1: TButton;

    Button3: TButton;

    DBGrid1: TDBGrid;

    DataSource1: TDataSource;

    SQLDataSet1: TSQLDataSet;

    DataSetProvider1: TDataSetProvider;

    ClientDataSet1: TClientDataSet;

    SQLConnection1: TSQLConnection;

    procedure Button2Click(Sender: TObject);

    procedure Button1Click(Sender: TObject);

    procedure DBGrid1DblClick(Sender: TObject);

    procedure Button3Click(Sender: TObject);

    procedure FormCreate(Sender: TObject);

  private

    { Private declarations }

    Function GetPiece(Node: string; Delimiter: string; FirstPiece: integer): string;

    Function GetPieces(Node: string; Delimiter: string; FirstPiece: integer; LastPiece: integer): string;

    Function PieceLength(Node: string; Delimiter: string): integer;

  public

    { Public declarations }

    Resultado: string;

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

 

Function TForm1.GetPiece(Node: string; Delimiter: string; FirstPiece: integer): string;

begin

 Result := GetPieces(Node, Delimiter, FirstPiece, FirstPiece);

end;

 

Function TForm1.GetPieces(Node: string; Delimiter: string; FirstPiece: integer; LastPiece: integer): string;

var

  p, p0, p1, i, c: integer;

  s: string;

begin

 

  s := Node + Delimiter;

 

  if (FirstPiece = 1) and (LastPiece = 1) then begin

     if Pos(Delimiter, Node) = 0 then

       Result := Node

     else

       Result := Copy(Node, 0, Pos(Delimiter, Node) - 1);

     Exit;

  end;

 

  p  := 1;

  p0 := 0;

  p1 := 0;

  c  := 0;

 

  for i := 0 to Length(Node) do begin

    if s[i] = Delimiter then

      inc(p);

 

    if FirstPiece = 1 then begin

      c := 1;

    end;

 

    if (c = 0) and (p = FirstPiece) then begin

      p0 := i + 1;

      c := 1;

    end;

 

    if (c = 1) and (p < (LastPiece + 1)) then begin

      inc(p1);

    end;

 

  end;

 

  if p1 <> Length(s) then dec(p1);

 

  Result := Copy(Node, p0, p1);

 

end;

 

Function TForm1.PieceLength(Node: string; Delimiter: string): integer;

var i,j: integer;

  begin

    i := 1;

    j := 0;

    while i > 0 do

      begin

        i := pos(Delimiter, node);

        node := copy(node,i+1,length(node)-1);

        j := j + 1;

      end;

  Result := j;

end;

 

 

 

procedure TForm1.Button2Click(Sender: TObject);

begin

  Resultado := ClientDataSet1.Fields[0].AsString;

end;

 

 

 

 

procedure TForm1.Button1Click(Sender: TObject);

const

  FONETIZAR  = 'SELECT FONETIZAR(''%s'') AS RESULTADO FROM DUAL';

  CONSULTAR1 = 'SELECT B.COD_MATERI AS "Código", B.NOM_MATERI AS "Nome do Material" FROM ('+

                 'SELECT DISTINCT COD_MATERI FROM MATERIAL_FONETICA WHERE ';

  CONSULTAR2 = 'DES_FONETI = ''%s'' ';

  CONSULTAR3 = ') A, MATERIAL B '+

               'WHERE A.COD_MATERI = B.COD_MATERI';

var

  Aux, Comando: string;

  i: integer;

begin

  if Edit1.Text = '' then begin

    ShowMessage('Digite um texto para Pesquisar; ');

    Exit;

  end;

 

  if ClientDataSet1.Active then

    ClientDataSet1.Close;

 

  ClientDataSet1.CommandText := Format(FONETIZAR,[Edit1.Text]);

  ClientDataSet1.DisableControls;

 

  ClientDataSet1.Open;

  Aux := (ClientDataSet1.Fields[0].AsString);

 

  Comando := CONSULTAR1;

  for i := 1 to PieceLength(Aux, ' ') do begin

    Comando := Comando + Format(CONSULTAR2,[GetPiece(Aux,' ', i)]);

    if i <> PieceLength(Aux,' ') then

      Comando := Comando + 'OR ';

  end;

  Comando := Comando + CONSULTAR3;

 

  ClientDataSet1.Close;

  ClientDataSet1.EnableControls;

  ClientDataSet1.CommandText := Comando;

  ClientDataSet1.Open;

 

  if ClientDataSet1.RecordCount = 0 then begin

     ShowMessage('Sua pesquisa não retornou nenhum resultado.');

     ClientDataSet1.Close;

  end;

 

end;

 

procedure TForm1.DBGrid1DblClick(Sender: TObject);

begin

  Resultado := ClientDataSet1.Fields[0].AsString;

  ModalResult := mrOk;

end;

 

procedure TForm1.Button3Click(Sender: TObject);

begin

close;

end;

 

procedure TForm1.FormCreate(Sender: TObject);

begin

 

end;

 

end.

 

 

Links

http://www.oracle.com/technology/software/products/sql/index.html