Club Delphi  
    FTP   CCD     Buscar   Trucos   Trabajo   Foros

Retroceder   Foros Club Delphi > Temas relacionados > Redes
Registrarse FAQ Miembros Calendario Guía de estilo Temas de Hoy

Respuesta
 
Herramientas Buscar en Tema Desplegado
  #1  
Antiguo 06-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 16
elaguna Va por buen camino
Búsqueda de contenido en documentos Word en Linux

Qué tal foro.

Antes que nada les agradezco a todos el tiempo que se dan para compartir conocimientos con los demás, en más de una ocasión me han sacado de apuros, considerando que soy un novato.

Pues así como dice el título. Les comento:

Tengo un sistema de gestión de documentos alojado en un servidor Linux; la base de datos es postgres, el programa está hecho en Delphi (en qué otra cosa?! ) y en un directorio del mismo servidor se almacenan los documentos de Word principalmente.

El programa funciona bien; registran un documento de Word, le ponen un título, el sistema asigna un nombre de archivo que se almacena y posteriormente lo recuperan a modo de plantilla; también pueden hacer búsquedas de archivos y que se localizan por medio del título que hubieran escrito, todos éstos datos están en postgres; hasta ahí todo bien pero...

Al cliente se le ocurrió que quiere hacer búsquedas por palabras en el contenido de los documentos de Word y posteriormente listar los archivos para que puedan abrirlos y trabajar con ellos.

Después de mucho darle vueltas he logrado realizar la dichosa búsqueda, se tarda uno o dos minutos más que en el Explorer de Windows, pero no siendo yo Microsoft, es tolerable.

La cuestión es que para hacer esa búsqueda abro cada uno de los archivos de Word (de uno en uno) y realizo la búsqueda, mi pregunta es: ya que los archivos están en el servidor al momento de abrirlos y cerrarlos desde los equipos cliente, seguramente me va a generar bastante tráfico.

Había pensado en hacer ese mismo procedimiento de búsqueda desde dentro del servidor y únicamente enviar los resultados al cliente pero no tengo idea de como hacerlo en Linux.

Alguien tiene alguna sugerencia de cómo se podría solucionar esto?

De antemano, muchas gracias a todos.

Eduardo Laguna.
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita
  #2  
Antiguo 07-09-2012
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Con grep puedes buscar un texto dentro de ficheros y la salida puedes enviarla a un fichero.log (por ejemplo).
Aunque puede que te convenga más guardar el documento dentro de la base de datos y hacer la búsqueda ahí. Si no son muchos millones de documentos
Responder Con Cita
  #3  
Antiguo 07-09-2012
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Pero grep es para archivos de texto ¿no? En un documento de word, no sé si podrá buscar.

// Saludos
Responder Con Cita
  #4  
Antiguo 07-09-2012
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Cita:
Empezado por roman Ver Mensaje
Pero grep es para archivos de texto ¿no? En un documento de word, no sé si podrá buscar.
Cierto, aunque si no está "cifrado" el texto (no lo sé) podría buscar palabras.
Creo que la mejor opción es crear un sistema de etiquetas/tags/palabras claves... que se guarden en un campo junto al registro, pero ahí se dependería de que el usuario que crea el registro lo haga correctamente y ponga las etiquetas adecuadas para luego encontrarlo.
Responder Con Cita
  #5  
Antiguo 07-09-2012
Avatar de movorack
[movorack] movorack is offline
Miguel A. Valero
 
Registrado: feb 2007
Ubicación: Bogotá - Colombia
Posts: 1.346
Poder: 20
movorack Va camino a la famamovorack Va camino a la fama
Hola a todos.

Creo que Grep tratará el documento cual fuese un documento de texto cualquiera. así que en teoria si podrá encontrar una cadena dentro del documento.
__________________
Buena caza y buen remar... http://mivaler.blogspot.com
Responder Con Cita
  #6  
Antiguo 07-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 16
elaguna Va por buen camino
En principio había contemplado el guardar los documentos dentro de la base de datos, pero como son documentos con bastantes "cosillas" en su formato pues mejor los dejamos por fuera y en la base sólo guardo la ruta del archivo.

Por otra parte ya había intentado con catdoc y grep desde terminal pero no funciona con .docx
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita
  #7  
Antiguo 07-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
En principio, recordemos que un archivo .doc/.docx/.odt, etc... no es mas que un paquete con mas archivos en su interior que definen el contenido y estructura del documento, entonces, si podemos desempaquetar ese archivo y manipular su contenido seremos los dioses del universo ...ah no, creo que ya me pasé.

Así que, como el .doc y .docx son formatos cerrados, porqué no convertirlos a un .odt (automatizado, claro) o similar y buscar el contenido allí. Revisando el código de loook podemos ver esto:
Código:
def processFile(self, filename, query):
  suffix = self.getSuffix(filename)
  try:
    # Handle OpenOffice.org files:
    if suffix in ('sxw', 'stw',				# OOo 1.x swriter
		    'sxc', 'stc',					# OOo 1.x scalc
		    'sxi', 'sti'					# OOo 1.x simpress
		    'sxg',							# OOo 1.x master document
		    'sxm',							# OOo 1.x formula
		    'sxd', 'std',					# OOo 1.x sdraw
		    'odt', 'ott',					# OOo 2.x swriter
		    'odp', 'otp',					# OOo 2.x simpress
		    'odf',							# OOo 2.x formula
		    'odg', 'otg',					# OOo 2.x sdraw
		    'ods', 'ots'					# OOo 2.x scalc
		    ):
	    zip = zipfile.ZipFile(filename, "r")
	    content = ""
	    docinfo = ""
	    try:
		    # TODO: are all OOo files utf-8?
		    content = unicode(zip.read("content.xml"), 'utf-8')
		    # TODO: is replace_with_space=0 correct?
		    content = self.removeXMLMarkup(content, replace_with_space=0)
		    docinfo = unicode(zip.read("meta.xml"), 'utf-8')
		    docinfo = self.removeXMLMarkup(docinfo, replace_with_space=0)
		    self.ooo_count = self.ooo_count + 1
	    except KeyError, err:
		    print "Warning: %s not found in '%s'" % (err, filename)
		    return None
	    title = ""
	    title_match = re.compile("<dc:title>(.*?)</dc:title>", re.DOTALL|re.IGNORECASE).search(docinfo)
	    if title_match:
		    title = title_match.group(1)
	    if self.match(query, "%s %s" % (content.lower(), docinfo.lower())):
		    return (filename, title)
    
  except zipfile.BadZipfile, err:
    print "Warning: Supposed ZIP file '%s' could not be opened: %s" % (filename, err)
  except IOError, err:
    print "Warning: File '%s' could not be opened: %s" % (filename, err)
  return None
Este código está en python y hace lo que se requiere, extrae el contenido y busca si el patrón de búsqueda se encuentra en el título, contenido o metadata del documento.

No te digo que hagas esto con cada búsqueda, sino que, se me ocurre que al momento de que se carga un nuevo documento al sistema se extraiga el contenido de este y se almacene en una bd o en otro lugar donde se nos simplifique la búsqueda.

Saludos
Responder Con Cita
  #8  
Antiguo 07-09-2012
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
Interesante ese loook
Responder Con Cita
  #9  
Antiguo 07-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
Cita:
Empezado por Casimiro Notevi Ver Mensaje
Interesante ese loook
cough.. cough.. ¿dije que está hecho en python?
Responder Con Cita
  #10  
Antiguo 07-09-2012
Avatar de Casimiro Notevi
Casimiro Notevi Casimiro Notevi is offline
Moderador
 
Registrado: sep 2004
Ubicación: En algún lugar.
Posts: 32.257
Poder: 10
Casimiro Notevi Tiene un aura espectacularCasimiro Notevi Tiene un aura espectacular
ya, ya...
Si tengo muchas pequeñas utilidades de línea de comando que hacen cosas fantásticas fácilmente y están hechas en python
Responder Con Cita
  #11  
Antiguo 07-09-2012
Avatar de mamcx
mamcx mamcx is offline
Moderador
 
Registrado: sep 2004
Ubicación: Medellín - Colombia
Posts: 3.927
Poder: 26
mamcx Tiene un aura espectacularmamcx Tiene un aura espectacularmamcx Tiene un aura espectacular
Cita:
Empezado por elaguna Ver Mensaje
Qué tal foro.
La cuestión es que para hacer esa búsqueda abro cada uno de los archivos de Word (de uno en uno) y realizo la búsqueda, mi pregunta es: ya que los archivos están en el servidor al momento de abrirlos y cerrarlos desde los equipos cliente, seguramente me va a generar bastante tráfico.
Este paso se puede mejorar considerablemente.

Primero, si ya tienes resuelto como extraer el texto de los documentos de word, que por mucho es el paso MAS dificil, entonces lo puedes colocar en un campo TEXT de la BD de postgres.

Una vez alli, montas una busqueda de texto completo:

http://www.postgresql.org/docs/9.1/s...extsearch.html

Y obtendras resultados es milisegundos (con los indices adecuados, que te lo explica la documentacion) y busquedas tipo google.

El resto es mantener actualizado el cache del contenido que metes en la BD (recuerda, es el texto de word, NO el archivo). Para eso, puedes usar una comparación de timestamp + tamaño de archivo y/o MD5 de estos + un detector de que el archivo ha cambiado.
__________________
El malabarista.
Responder Con Cita
  #12  
Antiguo 11-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 16
elaguna Va por buen camino
Cita:
Empezado por mamcx Ver Mensaje
Este paso se puede mejorar considerablemente.

Primero, si ya tienes resuelto como extraer el texto de los documentos de word, que por mucho es el paso MAS dificil, entonces lo puedes colocar en un campo TEXT de la BD de postgres.

Una vez alli, montas una busqueda de texto completo:

http://www.postgresql.org/docs/9.1/s...extsearch.html

Y obtendras resultados es milisegundos (con los indices adecuados, que te lo explica la documentacion) y busquedas tipo google.

El resto es mantener actualizado el cache del contenido que metes en la BD (recuerda, es el texto de word, NO el archivo). Para eso, puedes usar una comparación de timestamp + tamaño de archivo y/o MD5 de estos + un detector de que el archivo ha cambiado.

Interesante y práctico, lo voy a probar y les comento. Lo único aquí sería la cantidad de texto que entraría en el campo text, pero veremos qué pasa.

Con la sugerencia del compañero D-MO, está muy interesante el proceso, sólo que los equipos clientes son todo Microsoft y los usuarios no tienen tiempo (ni ganas!!) de aprender como cambiar el formato de su archivo de .odt a .docx, aparte de que algunas cosas tales como texto resaltado, comentarios y otras cosas se manejan distinto de un formato a otro. Pero para documentos más sencillos funciona perfectamente.

Cuando hago la búsqueda directa en .docx se tarda unos minutos, pero al hacer la conversión, aún cuando se está realizando en el servidor Linux se tarda un poco más. Pero muy interesante el método.

Gracias a todos.
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita
  #13  
Antiguo 11-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
Cita:
Empezado por elaguna Ver Mensaje
...sólo que los equipos clientes son todo Microsoft y los usuarios no tienen tiempo (ni ganas!!) de aprender como cambiar el formato de su archivo...
Si lees bien mi mensaje anterior verás que indiqué que el proceso de extracción debería ser automatizado. Veámos cual sería la secuencia (siguiendo la recomendación de mamcx).
  • El usuario carga el archivo al sistema
  • El sistema extrae extrae la metadata y texto del archivo (basándonos en como loook hace la búsqueda)
  • Se almacena esta info en la BD, junto con la referencia al archivo original (¿path?)
Y al hacer búsquedas
  • EL usuario ingresa un término de búsqueda
  • Se hace la búsqueda en la bd (texto plano del doc)
  • Al encontrar un match, se devuelve el archivo original (.docx)
De esta forma, en la bd tendrías un texto plano que simplificaría las búsquedas y al usuario de devuelves el archivo original.

Saludos
Responder Con Cita
  #14  
Antiguo 15-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 16
elaguna Va por buen camino
Solucionado

Muchas gracias a todos los que se tomaron el tiempo de leer, pero principalmente gracias a los que aportaron ideas.

Entre que ya había logrado sacar la información de los Word y con las sugerencias de mamcx y de D-MO se solucionó el problema, además de otra solución colateral.

Del modo en que en un principio lo estaba haciendo, mantenía oculto Word y realizaba las búsquedas en cada uno de los archivos, pero si mientras se ejecutaban las búsquedas, abrías Word entonces se quedaba abierto permanentemente o se cerraba (según la parte de código que se estuviera ejecutando) y se mostraba todo el proceso, pero no dejaba trabajar en ningún otro archivo (algo faltó por ahí al instanciar ).

Con la solución final, como todo se hace en el servidor, es mucho más rápido y no "molestamos" a Microsoft con nada.

Gracias a todos. Son geniales!!!

Eduardo Laguna
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita
  #15  
Antiguo 15-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
Me alegra saber que sirvió de algo las aportaciones que se hicieron. Sería bueno que detallaras un poco mas de como quedó el proceso final para que nos sirva de retroalimentación.

Saludos
Responder Con Cita
  #16  
Antiguo 15-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 16
elaguna Va por buen camino
Cita:
Empezado por D-MO Ver Mensaje
Me alegra saber que sirvió de algo las aportaciones que se hicieron. Sería bueno que detallaras un poco mas de como quedó el proceso final para que nos sirva de retroalimentación.
Claro que sí, en este momento todavía estoy modificando este "busca lo que te digo", pero en un momento más lo subo y gracias de nuevo.

Eduardo Laguna
__________________
No lo intentes!. Hazlo o no lo hagas, pero no lo intentes !!! (Yoda)
Responder Con Cita
  #17  
Antiguo 15-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
No te apures, que no hay prisa
Responder Con Cita
  #18  
Antiguo 19-09-2012
Avatar de elaguna
elaguna elaguna is offline
Miembro
 
Registrado: abr 2009
Ubicación: México
Posts: 51
Poder: 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
  #19  
Antiguo 19-09-2012
Avatar de roman
roman roman is offline
Moderador
 
Registrado: may 2003
Ubicación: Ciudad de México
Posts: 20.269
Poder: 10
roman Es un diamante en brutoroman Es un diamante en brutoroman Es un diamante en bruto
Muchas felicidades y muchas gracias por la solución

Este hilo me parece que puede ser de ayuda para mucha gente.

// Saludos
Responder Con Cita
  #20  
Antiguo 19-09-2012
Avatar de D-MO
D-MO D-MO is offline
Miembro
 
Registrado: ago 2005
Ubicación: root@debian:/#
Posts: 1.042
Poder: 21
D-MO Va por buen camino
Cita:
Empezado por elaguna Ver Mensaje
...especialmente a mamcx y a D-MO por sus ideas (prácticamente la solución)...
Pues no, no tienes nada que agradecer

A ti te agradecemos que hayas compartido la solución.

Saludos.
Responder Con Cita
Respuesta



Normas de Publicación
no Puedes crear nuevos temas
no Puedes responder a temas
no Puedes adjuntar archivos
no Puedes editar tus mensajes

El código vB está habilitado
Las caritas están habilitado
Código [IMG] está habilitado
Código HTML está deshabilitado
Saltar a Foro

Temas Similares
Tema Autor Foro Respuestas Último mensaje
adjuntar documentos de word pabloloustau Conexión con bases de datos 5 04-04-2010 02:13:04
Documentos de word zidfrid C++ Builder 2 05-09-2008 03:17:11
Formatear documentos Word abril0404 Servers 1 27-02-2008 15:23:25
documentos .dot(word) en delphi CARSOFT_AR Varios 2 11-02-2005 18:39:25
documentos word Albano Varios 0 12-01-2005 03:19:38


La franja horaria es GMT +2. Ahora son las 03:02:10.


Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
Traducción al castellano por el equipo de moderadores del Club Delphi
Copyright 1996-2007 Club Delphi