Apache Lucene with Tika not returning words with accent

Asked

Viewed 467 times

2

I implemented the library Lucene and Tika of the Apache package and managed to make it work super well for what I want. But I have a problem in words with accent, he can not return results for words with accent, I believe that at some point the texts are being saved with a encoding whatever loses these characters. Someone’s been through this trouble?

Java indexer.

package br.com.ir;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.br.BrazilianAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.TextField;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.IndexWriterConfig;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;
import org.apache.tika.Tika;

import javax.swing.*;
import java.io.File;
import java.io.FilenameFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;

class Indexador {
    private static final Logger logger = Logger.getLogger(Indexador.class);
    // IndexWriter: cria e mantém o índice;
    private IndexWriter writer;
    // Biblioteca que extrai texto de diversos formatos conhecidos;
    private Tika tika;
    private int qntArq = 0;

    public void iniciaIndexacao() {
        try {
            File diretorio = new File(ArquivoDeConfiguracao.retornaValorIndice());

            apagaIndices(diretorio);

            // Directory: representa o diretório do índice
            Directory d = new SimpleFSDirectory(diretorio);

            // Analyser/StandardAnalyser: fazem o pré-processamento do texto
            // Existem analisadores inclusive em português
            BrazilianAnalyzer analyzer = new BrazilianAnalyzer(Version.LUCENE_4_9);

            // IndexWriterConfig: configurações para criação do índice
            IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_4_9,
                    analyzer);

            // Inicializa o IndexWriter para gravação
            writer = new IndexWriter(d, config);

            long inicio = System.currentTimeMillis();
            indexaArquivosDoDiretorio(new File(ArquivoDeConfiguracao.retornaValorFonte()));
            // Fecha o IndexWriter e comita as mudanças
            writer.commit();
            long fim = System.currentTimeMillis();
            JOptionPane.showMessageDialog(
                    null,
                    "Quantidade de arquivos indexados: " + qntArq + "\n"
                            + "Tempo para indexar: "
                            + String.valueOf((fim - inicio) / 1000) + "s"
            );
        } catch (IOException e) {
            logger.error(e);
        } finally {
            if (writer != null) try {
                writer.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private void apagaIndices(File diretorio) {
        if (diretorio.exists()) {
            File arquivos[] = diretorio.listFiles();
            if (arquivos != null) {
                for (File arquivo : arquivos) {
                    //noinspection ResultOfMethodCallIgnored
                    arquivo.delete();
                }
            }
        }
    }

    void indexaArquivosDoDiretorio(File raiz) {
        FilenameFilter filtro = new FilenameFilter() {
            public boolean accept(File arquivo, String nome) {
                return nome.toLowerCase().endsWith(".pdf")
                        || nome.toLowerCase().endsWith(".odt")
                        || nome.toLowerCase().endsWith(".doc")
                        || nome.toLowerCase().endsWith(".docx")
                        || nome.toLowerCase().endsWith(".ppt")
                        || nome.toLowerCase().endsWith(".pptx")
                        || nome.toLowerCase().endsWith(".xls")
                        || nome.toLowerCase().endsWith(".xlsx")
                        || nome.toLowerCase().endsWith(".txt")
                        || nome.toLowerCase().endsWith(".rtf")
                        || nome.toLowerCase().endsWith("");
            }
        };

        for (File arquivo : raiz.listFiles(filtro)) {
            if (arquivo.isFile()) {
                try {
                    // Extrai o conteúdo do arquivo com o Tika;
                    String textoExtraido = getTika().parseToString(arquivo);
                    indexaArquivo(arquivo, textoExtraido);
                    qntArq++;
                } catch (Exception e) {
                    logger.error(e);
                }
            } else {
                indexaArquivosDoDiretorio(arquivo);
            }
        }
    }

    private void indexaArquivo(File arquivo, String textoExtraido) {
        SimpleDateFormat formatador = new SimpleDateFormat("ddMMyyyy");

        String ultimaModificacao = formatador.format(arquivo.lastModified());
        // Monta um Document para indexação
        // Field.Store.YES: armazena uma cópia do texto no índice, aumentando
        // muito o seu tamanho
        // Os Fields precisam ser TextField pois senão não irão ser analizados
        // na busca
        Document documento = new Document();
        documento.add(new TextField("UltimaModificacao", ultimaModificacao,
                Field.Store.YES));
        documento.add(new TextField("Caminho", arquivo.getAbsolutePath(),
                Field.Store.YES));
        documento.add(new TextField("Texto", textoExtraido, Field.Store.YES));

        try {
            // Adiciona o Document no índice, mas este só estará disponível para
            // consulta após o commit.
            getWriter().addDocument(documento);
        } catch (IOException e) {
            logger.error(e);
        }
    }

    Tika getTika() {
        if (tika == null) {
            tika = new Tika();
        }
        return tika;
    }

    IndexWriter getWriter() {
        return writer;
    }
}

1 answer

3


As answered in English version of the OS my problem was in the Query Analyzer, I was using the StandardAnalyzer instead of BrazilianAnalyzer, so the search query was not getting the proper treatment when finding the accents.

Java search.

package br.com.ir;

import org.apache.log4j.Logger;
import org.apache.lucene.analysis.Analyzer;
import org.apache.lucene.analysis.br.BrazilianAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.queryparser.classic.QueryParser;
import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.SimpleFSDirectory;
import org.apache.lucene.util.Version;

import javax.swing.*;
import java.io.File;

class Buscador {
    private final static Logger logger = Logger.getLogger(Buscador.class);
    public int totalDeOcorrencias;
    public String quantBusca;

    @SuppressWarnings({"unchecked", "rawtypes"})
    public Buscador(String parametro, DefaultListModel listModel) {
        try {
            Directory diretorio = new SimpleFSDirectory(new File(
                    ArquivoDeConfiguracao.retornaValorIndice()));
            // IndexReader: classe abstrata responsável por acessar
            // o índice;
            IndexReader leitor = DirectoryReader.open(diretorio);
            // IndexSearcher: implementa os métodos necessários para
            // realizar buscas em um índice;
            IndexSearcher buscador = new IndexSearcher(leitor);
            Analyzer analisador = new BrazilianAnalyzer(Version.LUCENE_4_9);
            // QueryParser/Query: representa a consulta do usuário. Outros
            // exemplos de query podem ser vistos no Javadoc;
            QueryParser parser = new QueryParser(Version.LUCENE_4_9, "Texto",
                    analisador);
            Query consulta = parser.parse(parametro);
            long inicio = System.currentTimeMillis();
            // Realiza a busca e armazena o resultado em um TopDocs;
            TopDocs resultado = buscador.search(consulta, 100);
            long fim = System.currentTimeMillis();
            totalDeOcorrencias = resultado.totalHits;
            quantBusca = String.valueOf((fim - inicio) / 1000);

            // ScoreDoc: representa cada um dos documentos retornados na busca.
            for (ScoreDoc sd : resultado.scoreDocs) {
                Document documento = buscador.doc(sd.doc);
                // Preenche o modelo
                listModel.addElement(documento.get("Caminho"));
            }
            leitor.close();
        } catch (Exception e) {
            logger.error(e);
        }
    }
}

Browser other questions tagged

You are not signed in. Login or sign up in order to post.