Limites da busca com LIKE

Relevância versus busca por substring

Como wildcards confundem tokens de idioma com sequências de caracteres e geram falsos positivos.

Intermediário 40 min 30 pontos Leitura 0%

Nesta aula você vai

  • Explicar a diferença entre token linguístico e sequência de caracteres
  • Identificar falsos positivos típicos gerados por LIKE com curingas
  • Relacionar relevância com campos, frequência e intenção do usuário

Relevância versus busca por substring

Objetivos

Nesta aula você vai:

  • Separar token (unidade de idioma) de substring (fatia de caracteres)
  • Mapear falsos positivos e falsos negativos causados por curingas
  • Definir relevância como critério de ordenação, não como “bateu ou não bateu”

Introdução

Linguagem natural não é uma fita contínua de bytes. Em português, “ferramentas”, “ferramenta” e “a ferramenta elétrica” compartilham uma ideia; a sequência menta aparece em “ferramenta” e também em “fundamenta” e “comentário”. Busca por substring trata o texto como corda; busca por relevância trata o texto como documento com termos.

No OficinaHub, um marketplace B2B de ferramentas manuais e elétricas, o comprador digita serra. Com LIKE '%serra%', o sistema pode trazer “asserra de madeira” (se o catálogo tiver o termo), “conservação de serra” em um FAQ colado na descrição, e até SKUs cujo código interno contém SERRA por acaso. Ao mesmo tempo, pode deixar de lado “serras circulares” se a consulta for serra circular e a sinopse usar outra ordem de palavras.

Conteúdo

Substring: o motor vê caracteres

-- OficinaHub: predicado por substring
SELECT sku, nome, categoria
FROM produtos
WHERE nome LIKE '%serra%'
   OR descricao LIKE '%serra%';

O predicado é verdadeiro sempre que a sequência s-e-r-r-a aparece. Não há noção de limite de palavra. Em muitos collations, maiúsculas e minúsculas se igualam; ainda assim, morfologia (plural, gênero, derivados) continua fora do jogo.

Consulta Pode casar indevidamente Pode falhar em casar
%para% “preparação”, “paradoxo” (dependendo do texto) “pára” com acentuação diferente
%sol% “consolador”, “absoluto” “sóis” / “solares”
%kit% “marketing”, “packet” em importações EN “kits” se stemming não existir

Token: o motor vê palavras (depois de normalizar)

Full-text primeiro tokeniza: corta o texto em unidades, normaliza caixa, descarta stopwords e, em motores com stemming, reduz formas flexionadas a um lexema. A consulta serra circular vira um conjunto de termos com operadores, não uma fatia rígida de caracteres.

-- Ilustração conceitual (PostgreSQL): tokens, não substrings
SELECT to_tsvector('portuguese', 'Serra circular de 7 polegadas para madeira úmida');
-- resultado típico: 'circular':2 'madeir':6 'poleg':4 'serr':1 'umid':7

Observe que preposições e artigos somem, e “madeira”/“úmida” podem virar radicais. Isso é o oposto de LIKE, que exige a sequência literal (salvo collation).

Relevância não é booleana

Substring responde sim/não. Relevância responde “quanto este documento importa para esta consulta?”. Em um ranking simples:

  1. Ocorrência no nome vale mais que na descrição
  2. Termos raros no catálogo pesam mais que termos ubíquos
  3. Documentos curtos e focados podem superar paredes de texto genérico
-- LIKE não tem score nativo; a aplicação improvisaria algo frágil
SELECT sku, nome,
       CASE
         WHEN nome LIKE '%serra circular%' THEN 3
         WHEN nome LIKE '%serra%' THEN 2
         WHEN descricao LIKE '%serra%' THEN 1
         ELSE 0
       END AS score_improvisado
FROM produtos
WHERE nome LIKE '%serra%' OR descricao LIKE '%serra%'
ORDER BY score_improvisado DESC;

Esse CASE é um ranking de brinquedo: não entende sinônimos, não normaliza morfologia e multiplica a quantidade de predicados LIKE. Em escala, vira dívida técnica.

Problema comum e solução

Problema: o time adiciona mais OR e CASE para “melhorar relevância” em cima de LIKE, e a consulta fica ilegível, lenta e ainda cheia de falsos positivos.

Solução: modelar a busca como recuperação de documentos — índice invertido + ranking do motor — e usar substring só quando o requisito for literalmente “contém este código/trecho exato”.

Como analisar

Monte um conjunto de consultas de regressão qualitativa (dez a quinze buscas reais do suporte) e compare:

-- Amostra de falsos positivos por substring curta
SELECT sku, nome
FROM produtos
WHERE nome LIKE '%kit%'
  AND nome NOT ILIKE '%kit %'
  AND nome NOT ILIKE 'kit%'
LIMIT 30;

Se a lista estiver cheia de nomes que só “passam por cima” da sequência, você tem prova de que substring ≠ relevância. Guarde esses casos para validar a migração para full-text.

Resumo

  • Substring opera em caracteres; relevância opera em tokens e pontuação
  • Curingas geram falsos positivos (sol dentro de outras palavras) e falsos negativos (flexões, ordem de termos)
  • Improvisar score com CASE + LIKE mascara o problema e piora o SQL
  • Full-text existe precisamente para alinhar o motor à linguagem do usuário