Ver Mensaje Individual
  #18  
Antiguo 19-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Reputación: 16
elaguna Va por buen camino
Solucionado (definitivamente)

Pues como quedamos, esta es la solución que implemente para las búsquedas.

1. Modifiqué mi tabla en la DB (Postgresql) para almacenar al contenido de cada documento. Mi tabla se llama "planti_corr", agregué un campo de texto e indexé la tabla por ese campo siguiendo lo indicado por mamcx y en la documentación http://www.postgresql.org/docs/9.1/s...extsearch.html

Código SQL [-]
CREATE INDEX pgcontenido_idx
  ON planti_corr
  USING gin
  (to_tsvector('spanish'::regconfig, contenido));


2. Ahora que extraer el contenido de cada documento que se vaya a dar de alta, esto lo hice en el botón de "Altas" en el formulario de registro de documentos:
  • Crear una instancia del Portapapeles de Windows
  • Crear una instancia de Word y abrir el documento
  • Seleccionar todo el contenido del documento de Word y copiarlo en el Portapapeles de Windows
  • Cerrar Word
  • Poner el contenido del Portapapeles en una variable
    • El límite de tsvector en Postgresql es de 1048575 bytes por lo que limito el tamaño del contenido de la variable a 1040000 con la función LeftBStr()
  • Envío todo a Postgres en un Query
Código Delphi [-]
var
  word : Variant;
  plantiOrig : TClipBoard;
  wnContenido : WideString;
  wnGuarda : oleVariant;

begin
  ...
  ...
  Word := CreateOleObject('Word.Application');
  Word.Visible := False;
  
  try
     Word.Documents.Open(, EmptyParam, EmptyParam, EmptyParam,
                                      EmptyParam, EmptyParam, EmptyParam, EmptyParam,
                                      EmptyParam, EmptyParam);

     Word.Selection.WholeStory;    // Seleccionar todo el contenido del documento de Word
     Word.Selection.Copy;            //  Copiar al portapapeles
     Word.ActiveDocument.Close(wnGuarda, EmptyParam, EmptyParam);
     Word.Quit;

     wnContenido := LeftBStr(plantiOrig.AsText, 1040000);    // Extrae únicamente 1040000 bytes
     plantiOrig.Clear;

     Query1.Active := False;
     Query1.SQL.Clear;
     Query1.SQL.Add('insert into planti_corr (nombre, archivo, contenido) values (:vNombre, :vArchivo, :vContenido)');
     
     Query1.ParamByName('vNombre').AsString := ;
     Query1.ParamByName('vArchivo').AsString := 
     Query1.ParamByName('vContenido').AsWideString := wnContenido;
     Query1.ExecSQL;
  Except
     Application.MessageBox('Error al cargar el archivo en la base de datos', 'Buscador', MB_OK or MB_ICONERROR);
  End;
  ...
  ...
end;

3. Ahora la búsqueda. En otro botón:
  • Tomo el texto con las palabras que desean buscar, éstas deben quedar separadas únicamente por el símbolo '&' (primerapalabra&segundapalabra&tercerapalabra); (no espacios, no comas, no puntos, no... nada) y asigno la nueva cadena a una variable, para esto utilizo la función ReplaceStr()
  • Ejecuto la consulta esta debe ser con la función "tsquery" de Postgres en el campo indexado, (que el servidor haga todo!!!)
  • ... y hago muy feliz a mi usuario !!!
Código Delphi [-]
var
  w_palabras : String;
  wpTotalReg : Integer;



begin
  ...
  ...


  w_palabras := ReplaceStr(edtFrases.Text,' ', '&');


  Query1.Close;
  Query1.SQL.Clear;
  Query1.SQL.Add('SELECT id_planti, nombre, archivo FROM planti_corr WHERE contenido @@ to_tsquery(:wqPalabras)');
  Query1.ParamByName('wqPalabras').AsString := w_Palabras;
  Query1.Open;

  wpTotalReg := Query1.RecordCount;
  ...
  ...
end;


Estas son las instrucciones básicas, obviamente hay cosas antes y después, pero concretando esta es la forma en que lo solucioné y efectivamente el tiempo de la búsqueda se redujo de algunos minutos a pocos segundos, bastante bien diría yo!!!.


Muchas gracias a todos, especialmente a mamcx y a D-MO por sus ideas (prácticamente la solución)


Saludos.


Eduardo Laguna
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita