Como Adicionei Busca com Tolerância a Erros de Digitação com OpenSearch e CJK

Consultas sem resultados estavam acabando com o nosso tempo de exibição.

Durante um ano, o TopVideoHub usou SQLite FTS5 para busca. Funcionava para correspondências exatas. Falhava quando os usuários cometiam erros de digitação.

As pessoas buscavam por "demon slyer" em vez de "demon slayer". Adicionavam espaços extras em títulos em japonês ou coreano. Como o FTS5 faz correspondência de tokens exatos, um único erro de digitação significava zero resultados. Os usuários não buscavam novamente. Eles simplesmente iam embora.

Mudei nossa busca de títulos para o OpenSearch. Aqui está como resolvi isso para um público multilíngue.

O Problema com a Fuzziness Padrão

A maioria dos tutoriais diz para usar "fuzziness" para corrigir erros de digitação. Isso funciona para o inglês, mas falha para textos em chinês, japonês e coreano (CJK).

  • A distância de edição (edit distance) é ruim para CJK. Um erro de digitação em CJK geralmente significa usar um caractere completamente errado.
  • A fuzziness padrão cria lixo semântico. Ela pode combinar "fire" com "water" porque estão a apenas uma edição de distância.
  • A tokenização é difícil. Idiomas CJK não utilizam espaços entre as palavras.

A Solução: Uma Abordagem de Múltiplos Campos

Parei de tratar todo o texto da mesma forma. Criei um único campo lógico de título que indexa de três maneiras diferentes:

  • Latim e Romaji: Usei tokenização padrão com fuzziness ativado. Defini um comprimento de prefixo (prefix length) de 1. Isso garante que "demon" corresponda a "demn", mas "lemon" não corresponda a "demon".
  • Texto CJK: Usei um analisador de bigramas CJK e um normalizador ICU. Desativei a fuzziness. Em vez disso, usei um limite mínimo de correspondência (minimum match threshold) de 70%.
  • Autocomplete: Usei um campo edge-ngram para alimentar os resultados de busca conforme você digita (search-as-you-type).

Arquitetura e Segurança de Dados

Mantive o SQLite como a única fonte de verdade. O OpenSearch atua como um índice rápido e reconstruível.

  • Uso PHP para enviar atualizações para o OpenSearch em lotes (bulk batches).
  • Nunca executo a indexação durante uma requisição de usuário.
  • Executo um script Python para verificar "drift" (desvio). Isso garante que a contagem no OpenSearch corresponda à contagem no SQLite.

Os Resultados

A mudança foi enorme:

  • Consultas sem resultados caíram de 14% para menos de 3%.
  • As sessões de busca tornaram-se mais longas porque os usuários encontraram o que queriam imediatamente.
  • A latência permanece baixa, em torno de 40ms.

Se você atende a um público multilíngue, lembre-se: tolerância a erros de digitação e correspondência CJK são dois problemas diferentes. Você precisa de duas soluções diferentes.

Fonte: https://dev.to/ahmet_gedik778845/how-i-added-typo-tolerant-video-title-search-with-opensearch-and-cjk-3e5d