Lucene ou PostgresSQL

2008-10-09

Estou num certo impasse num projecto. Necessito de indexar um repositório de documentos, como também armazenar dados sobre esses documentos, numa aplicação. A aplicação terá um conjunto extra de funcionalidades, para além da gestão documental, e que utilizarei uma base de dados como suporte. mas para os documentos, dada a modelariedade do sistema, quer um indexador com base em sistema de ficheiros, quer com base em pesquisa de texto livre numa base de dados, são opções válidas. Simplesmente a manipulação dos dados (organização) e o cruzamento de dados teria que ser planeada consoante a forma de indexação.

Percori uma série de artigos e experiências na tentativa de chegar a uma conclusão. Uma hipótese era o Index Server da Microsoft que tinha sido usado num projecto universitário sobre o qual laborei. Pedi opinião a um colega que mantém o projecto e recomendou evitar… Sobrou o Lucene, que armazena os indices no sistema de ficheiros e tem uma versão .NET e o PostgresSQL, que sendo aberto e funcionando sobre o Windows, pareceu-me uma óptima escolha parta o suporte de dados. Ambos indexam o texto do documento, se bem que esse texto deve ser extraído, por exemplo, no caso dos PDFs. Decidi testar ambos para de alguma forma comparar e verificar se um é claramente melhor que outro.

Primeiro passo, criar um dataset. Usei cerca de 10000 mensagens de email, da qual tive que extrair os documentos em attachment (que é efectivamente o conjunto de dados que vou indexar na aplicação). Sobre esse processo falerei noutro post, que por si só é bastante interessante. Dos emails tenho cerca de 10000 emails, 2500 dos quais PDF.

Próximo passo, indexar ambos e comparar pesquisas. Para o caso do Lucene, utilizei um exemplo do KeyLimeTie. O exemplo inclui a biblioteca do Lucene.Net e um projecto de interface de utilizador, para indexar e pesquisar. Foi necessário efectuar uma pequena alteração para incluir a indexação de PDFs (os .doc funcionou nativamente no exemplo). Para o efeito, criei um novo tipo de documento PDFDocument, similar ao Document que já estava definido, e alterei apenas o pedaço de código que define o campo de texto a armazenar no Lucene:

Este processo utiliza a biblioteca do PDFBox, que apesar de ser Java, é utilizável através de outra referência, o IKVM .

para proceder á indexação, separei o formato PDF dos restantes num switch/case e adicionei ao IndexWriter um PDFDocument em vez de um Document

Indexar os documentos todos demorou aproximadamente 65 minutos (9830 documentos, 580 não indexados, 181 com erro). O índice (a pasta) ocupava cerca de 360MB). Posteriormente re-indexei apenas os PDF com o resultados de 23minutos para 2551 documentos, 580 não indexados, 181 com erro).

Para o Postgres, criei uma base através do pgAdmin III, com uma tabela:

e com um trigger para criar o tsvector (vector com os termos e localização do módulo tsearch2).

também importante foi a criação do indice GIN sobre o vector:

Em termos de aplicação, utilizei a base do exemplo do Lucene, mas modifiqeui o processo de indexação, claro. Extraí o texto e inseri os dados na BD, o método de extração dos dados do PDF é identico:

Consegui em termos de tempos de indexação, este foi feito em dois tempos (devido a um bug q tinah no meu código) mas a app identificou 4093 ficheiros, indexando 3549 e os restantes com erros em cerca de 37 minutos.

Em ambos os casos houve um largo conjunto de campos não indexados, devido, especialmente, a problemas de abertura de ficheiros ou de codificação do mesmo. Mas para o efeito do teste essa situação não era grave.

À partida sabia que o caso da base de dados seria naturalmente mais lenta. Entre conectar à BD, e processar o insert, certamente que o tempo de execução seria mais longa que o da escrita para ficheiro no Lucene. De qualquer forma, a diferença encontrada não foi tão elevada quanto a que estava à espera.

Em temros de pesquisa, há algumas diferenças quer no conjunto de resultados, quer nos tempos:

<td>
  Lucene
</td>

<td>
  Postgres
</td>
<td>
  2551
</td>

<td>
  3549
</td>
<td>
  23min.
</td>

<td>
  37minutos
</td>
<td>
  465 hits / 184ms
</td>

<td>
  718 hits / 287ms
</td>
<td>
  10 hits / 60ms
</td>

<td>
  132 hits / 17ms
</td>
<td>
  6 hits / 80ms
</td>

<td>
  9 hits / 20ms
</td>
<td>
  208 hits / 80ms
</td>

<td>
  0 hits / 200ms*
</td>
<td>
  244 hits / 72ms
</td>

<td>
  120 hits / 20ms
</td>

Há resultados aceitaveis e outros muito estranhos. Por exemplo “psicologia” retornou resultados correctamente no Lucene e não no Postgres, apesar de “psicolog” ser um “stem” presente na coluna de vector. A generalidade das pesquisas parecem ser suficientemente rápidas, quer num sistema, quer noutro. Ainda vou ter de investigar melhor o porquê da falha na palavra “psicologia” (se alguem souber, agradeço comentário).

Apesar de o Postgres ser mais lento na indexação (em massa) penso que o vou manter. Tornará a gestão da aplicação mais simples (menos um repositório) e permitirá efectuar cruzamento de dados directamente na base, através das relações entre tabelas.