Performance, antipadrões e decisão em produção

Checklist de arquitetura de busca

Decisão: FTS no banco vs motor dedicado; critérios de volume, relevância, equipe e custo.

Intermediário 50 min 35 pontos Leitura 0%

Nesta aula você vai

  • Aplicar uma checklist objetiva FTS-no-banco versus motor dedicado
  • Pesar volume, relevância, equipe, custo e requisitos de atualidade dos dados
  • Registrar a decisão de arquitetura com critérios verificáveis

Checklist de arquitetura de busca

Objetivos

Nesta aula você vai:

  • Aplicar uma checklist objetiva FTS-no-banco versus motor dedicado
  • Pesar volume, relevância, equipe, custo e requisitos de atualidade dos dados
  • Registrar a decisão de arquitetura com critérios verificáveis

Introdução

A pergunta certa não é “qual o melhor motor de busca?”, e sim “qual capacidade mínima resolve o produto agora, com a equipe e o orçamento que temos?”. Esta aula consolida o módulo em uma checklist reutilizável de arquitetura.

Conteúdo

Passo 1 — Clarificar o job da busca

Responda por escrito:

  1. A busca é auxiliar (achar um registro) ou produto (descoberta, facetas, personalização)?
  2. Precisa de typo-tolerance, sinônimos, multilíngue?
  3. Precisa de semântica (paráfrase) ou lexical basta?
  4. Qual o SLA de atualidade após uma publicação?
  5. Multi-tenant? Isolamento por tenant na query é obrigatório?

Sem essas respostas, qualquer diagrama é especulação.

Passo 2 — Dimensões de decisão

Dimensão FTS no banco (Postgres/MariaDB/SQL Server/SQLite D1/Mongo text) Motor dedicado (OpenSearch, Meili, Typesense, Atlas Search)
Volume Até dezenas de milhões com query seletiva, conforme motor Centenas de milhões+, QPS alto de busca
Relevância BM25/textScore “bom o bastante” Analyzers, synonyms, ranking functions, A/B
Facetas Limitadas / SQL aggregations Nativas e baratas relativamente
Equipe DBA/dev já no SGBD Precisa de responsabilidade de search/platform
Custo Marginal no DB existente Cluster/RAM/managed + sync
Atualidade Transacional ou triggers Eventual (segundos+) típico
Edge D1 FTS5 excelente encaixe Motor central + Worker cliente

Passo 3 — Checklist binária (FTS no banco)

Marque “sim” só com evidência:

  • Conjunto de dados e QPS cabem no orçamento medido (P95 OK no teste de carga realista)
  • Relevância lexical aprovada por product/UX em amostra de queries
  • Não há requisito forte de facetas complexas ou fuzzy agressivo
  • Sync resolvido (mesma transação, triggers ou text index nativo)
  • Plano de escape documentado (quando sair do banco)

Se três ou mais itens falham, avalie motor dedicado.

Passo 4 — Checklist binária (motor dedicado)

  • Há SoR claro (DB) e indexer idempotente
  • Lag monitorado e alertado
  • Estratégia de reindex (alias/zero-downtime)
  • Segurança: ACL/tenant filters em toda query
  • Custo de RAM/replicas projetado para 12–18 meses
  • Roteiro de incidente (cluster vermelho, quebra de mapping)

Passo 5 — Híbridos comuns

1) D1/Postgres FTS → API
2) FTS top-K → re-rank vetorial (Vectorize)
3) OpenSearch lexical + vector field
4) Autocomplete no Meili/Typesense + detalhe no OLTP

Híbrido aumenta poder e complexidade: só adote se a checklist de relevância exigir.

Passo 6 — Registrar a ADR

Documente em uma ADR curta:

  • Contexto e drivers (volume, UX, equipe)
  • Decisão (ex.: “FTS5 no D1 com triggers; reavaliar aos 5 M docs”)
  • Consequências (limites conhecidos, métricas de gatilho)
  • Gatilhos de revisão (P95, tamanho do DB, novas funcionalidades de faceta)
## ADR: Busca lexical no D1
- Status: aceita
- Decisão: articles_fts (fts5) + triggers; autocomplete prefix; sem OpenSearch no MVP
- Gatilho de revisão: P95 > 300 ms por 7 dias OU facetas no roadmap

Fluxo mental final

Job da busca → métricas atuais → checklist FTS banco
        ↘ falhou → checklist motor dedicado
        ↘ semântica necessária → vetores ± lexical
        → ADR + gatilhos de revisão

Exemplos práticos

// Scorecard simples para workshop de arquitetura
function scorecard(answers) {
  const weights = {
    volumeHigh: 2,
    facetsNeeded: 2,
    typoSynonyms: 2,
    teamHasSearchOncall: 1,
    edgeFirst: -1, // favorece D1/FTS embutido
    semanticNeeded: 2,
  };
  let score = 0; // >3 sugere motor dedicado
  for (const [k, w] of Object.entries(weights)) {
    if (answers[k]) score += w;
  }
  return {
    score,
    recommendation:
      score >= 3 ? 'motor-dedicado-ou-hibrido' : 'fts-no-banco',
  };
}
-- Evidência mínima antes de decidir "cabe no D1"
-- Rodar sob carga com EXPLAIN QUERY PLAN + latência no Worker
SELECT count(*) AS approx
FROM articles_fts
WHERE articles_fts MATCH 'produto*';

Problemas e como resolver

Problema Causa Mitigação
Decisão por moda “Todo mundo usa ES” Lista de verificação + teste de carga
Lock-in sem escape Sem ADR/gatilhos Documentar revisão
Dois SoR Índice editável na UI de busca SoR no OLTP apenas
Custo surpresa Sem projeção de RAM/QPS Capacity plan 12–18 meses

Resumo

Use a checklist: esclareça o job, meça, prefira FTS no banco quando couber, escale para motor dedicado quando relevância/volume/facetas exigirem, e registre ADR com gatilhos. Assim a busca permanece uma decisão de engenharia — não um salto de fé.