Busca full-text: guia passo a passo para implementar
Implementar busca full-text vai além de um simples LIKE. Este guia mostra o caminho passo a passo, desde a escolha do banco até a otimização de consultas, com dicas para evitar erros comuns.
Implementar busca full-text vai além de um simples LIKE. Este guia mostra o caminho passo a passo, desde a escolha do banco até a otimização de consultas, com dicas para evitar erros comuns.
Implementar busca full-text em um banco de dados resolve um problema comum: encontrar registros por palavras parciais, sinônimos ou variações de termo, sem sacrificar a performance. Diferente do operador LIKE, que varre a tabela inteira a cada consulta, a busca full-text usa índices invertidos, o que acelera a resposta em conjuntos de dados grandes. O resultado esperado deste guia é uma busca funcional, com relevância básica e sem os gargalos típicos das consultas textuais ingênuas.
Pré-requisitos: acesso de escrita ao banco, permissão para criar índices, e conhecimento intermediário de SQL. O guia usa exemplos em MySQL e PostgreSQL, mas a lógica se aplica a outros SGBDs com suporte nativo, como SQL Server e SQLite.
Passo 1: Escolha a coluna e o tipo de dado
A busca full-text exige que o conteúdo esteja em uma coluna de texto, como VARCHAR, TEXT ou CLOB. Se o dado estiver em múltiplos campos, como título e descrição, você pode criar um índice combinado. Antes de criar o índice, verifique o charset da coluna: para português, use utf8mb4 ou equivalente para acentuação correta.
Erro comum: tentar criar índice full-text em coluna numérica ou binária. O índice só funciona em tipos textuais.
Passo 2: Crie o índice full-text
Cada banco tem sua sintaxe. No MySQL, o comando é:
ALTER TABLE artigos ADD FULLTEXT INDEX idx_busca (titulo, conteudo);
No PostgreSQL, você precisa de uma coluna tsvector ou de um índice GIN com expressão:
CREATE INDEX idx_busca ON artigos USING GIN (to_tsvector('portuguese', titulo || ' ' || conteudo));
Dica: no PostgreSQL, defina o idioma do dicionário para 'portuguese' para tratar stopwords e radicalização.
Erro comum: esquecer que o MySQL não usa stopwords para português por padrão, o que pode incluir artigos e preposições nos resultados.
Passo 3: Escreva a consulta com operadores de busca
No MySQL, use MATCH...AGAINST:
SELECT * FROM artigos WHERE MATCH(titulo, conteudo) AGAINST ('banco de dados' IN NATURAL LANGUAGE MODE);
No PostgreSQL, a consulta usa tsquery:
SELECT * FROM artigos WHERE to_tsvector('portuguese', titulo || ' ' || conteudo) @@ to_tsquery('portuguese', 'banco & dados');
Operadores comuns: aspas para frase exata, sinal de menos para excluir termo, e booleano para combinar.
Erro comum: usar LIKE e full-text na mesma condição com OR, o que pode ignorar o índice. Prefira apenas full-text.
Passo 4: Avalie a relevância dos resultados
A busca full-text retorna uma pontuação de relevância. No MySQL, use:
SELECT *, MATCH(titulo, conteudo) AGAINST ('banco de dados') AS score FROM artigos ORDER BY score DESC;
No PostgreSQL, a função ts_rank() ordena por relevância. Sem isso, a ordem é aleatória.
Dica: comece com LIMIT 10 para evitar custo alto em tabelas grandes.
Erro comum: não ordenar por score, o que faz o usuário ver resultados irrelevantes no topo.
Passo 5: Trate a acentuação e variações linguísticas
A busca full-text lida com acentos de forma inconsistente entre bancos. No MySQL, o collation utf8mb4_unicode_ci ignora acentos, mas a busca com AGAINST pode não fazer isso. No PostgreSQL, o dicionário 'portuguese' aplica radicalização, mas não remove acentos.
Para normalizar, você pode usar funções como unaccent no PostgreSQL ou criar uma coluna auxiliar com texto sem acento no MySQL.
Erro comum: assumir que o banco trata acentos automaticamente. Teste com palavras como "ação" e "acao".
Passo 6: Monitore a performance e ajuste
Após a implementação, execute EXPLAIN para confirmar que o índice está sendo usado. Se a consulta ainda fizer full scan, revise a sintaxe ou o tamanho do índice.
Dica: para tabelas com milhões de linhas, considere particionar a tabela por data ou categoria para reduzir o escopo do índice.
Erro comum: ignorar o crescimento do índice, que pode consumir espaço em disco. Monitore o tamanho com SHOW TABLE STATUS (MySQL) ou pg_relation_size (PostgreSQL).
Checklist do que foi feito
- [ ] Coluna textual identificada e com charset adequado
- [ ] Índice full-text criado com sintaxe correta do banco
- [ ] Consulta usando MATCH...AGAINST ou tsquery, sem LIKE
- [ ] Ordenação por relevância implementada
- [ ] Testes com acentuação e stopwords
- [ ] EXPLAIN confirma o uso do índice
FAQ
Busca full-text é melhor que LIKE?
Sim, para volumes grandes. O LIKE faz varredura sequencial, enquanto full-text usa índice invertido, respondendo em milissegundos. Para tabelas pequenas, a diferença é irrelevante.
Como tratar acentos na busca full-text?
Depende do banco. No PostgreSQL, use a extensão unaccent; no MySQL, defina collation sem acento ou crie uma coluna normalizada. Teste sempre com palavras acentuadas.
Preciso de um banco específico para full-text?
Não. MySQL, PostgreSQL, SQL Server e SQLite têm suporte nativo. A sintaxe varia, mas o conceito de índice invertido é o mesmo.
Como melhorar a relevância dos resultados?
Use operadores booleanos, defina pesos por campo (título vale mais que conteúdo) e ajuste o dicionário de idioma. No PostgreSQL, ts_rank permite configurar pesos.
Busca full-text funciona com dados em português?
Sim, desde que configure o dicionário de idioma. No PostgreSQL, use 'portuguese'; no MySQL, você pode adicionar stopwords manualmente. Sem isso, artigos e preposições poluem os resultados.
É possível usar full-text com JSON?
Depende do banco. PostgreSQL permite criar índice GIN em colunas JSONB, mas é mais complexo. MySQL não suporta diretamente em JSON, exigindo colunas virtuais.
Implementar busca full-text é um processo de poucas horas, mas que exige atenção a detalhes de configuração. O ganho em performance e qualidade de busca compensa o esforço inicial. Se o volume de dados crescer, revise o índice periodicamente e considere ferramentas externas como Elasticsearch apenas quando a complexidade dos filtros aumentar além do SQL.