Correção para o erro “Record is too big” que interrompe a reindexação de posts do Algolia
Encontrei um problema em que o Algolia continha apenas uma pequena parte dos posts do meu fórum. A execução da reindexação de posts revelou a causa:
Algolia::AlgoliaHttpError:
Record at the position 258 objectID=1006 is too big:
size: 108426 byte(s), maximum allowed: 10000 byte(s).
Na versão do plugin instalada por mim, PostIndexer#to_object envia o texto sem formatação inteiro de um post como um único registro, sem verificar o tamanho do registro serializado. Um registro de tamanho excessivo fez com que a tarefa de reindexação fosse interrompida.
O workaround local a seguir permitiu que a reindexação fosse concluída.
O que este patch faz
O patch limita cada registro serializado completo do post a 9.500 bytes, deixando uma margem abaixo do limite de 10.000 bytes relatado pelo Algolia.
Ele:
-
Inclui metadados e o escape de JSON no cálculo do tamanho.
-
Trunca apenas o content enviado ao Algolia.
-
Mantém o post original do Discourse inalterado.
-
Preserva os IDs de objeto existentes e a estrutura de um registro por post.
A desvantagem é que o texto omitido no final de um post longo não será pesquisável por meio do Algolia. Isso é truncamento, não particionamento de documentos.
Patch
Em:
plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb
Localize o retorno final em to_object, imediatamente após a adição dos metadados de categoria opcionais:
object
end
Substitua essa seção por:
# Limit the complete serialized record, not just its content.
algolia_record_budget = 9_500
if object.to_json.bytesize > algolia_record_budget
full_content = object[:content]
object[:content] = ""
if object.to_json.bytesize > algolia_record_budget
raise "Algolia metadata alone exceeds the record budget for post #{post.id}"
end
low = 0
high = full_content.length
best_content = ""
while low <= high
midpoint = (low + high) / 2
object[:content] = full_content[0, midpoint]
if object.to_json.bytesize <= algolia_record_budget
best_content = object[:content]
low = midpoint + 1
else
high = midpoint - 1
end
end
object[:content] = best_content
end
object
end
A busca binária encontra um prefixo de conteúdo que se encaixa no limite de bytes após a serialização JSON. Se os metadados sozinhos excederem o limite, o patch gera um erro explícito em vez de descartar silenciosamente os metadados.
Faça um backup do arquivo antes de editar. Este patch destina-se à versão em que to_object retorna um único hash contendo content; revise-o contra a sua versão instalada antes de aplicá-lo.
Validação e reindexação
Para uma instalação padrão com Docker, acesse o container a partir do host:
cd /var/discourse
./launcher enter app
Mude para o usuário do Discourse:
su - discourse
Quando o prompt do usuário discourse aparecer, execute:
cd /var/www/discourse
ruby -c plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb
Se isso reportar Syntax OK, execute:
RAILS_ENV=production LOAD_PLUGINS=1 bundle exec rails algolia:reindex_posts
Esta tarefa limpa e repopula o índice de posts. No meu caso, foi concluída com sucesso após a aplicação do patch.
Processos de aplicação/trabalhadores em segundo plano em execução também precisam ser reiniciados para usar o código corrigido durante a indexação contínua.
Uma pegadinha separada: a contagem de posts relatada
A tarefa reportou:
Successfully pushed 723 posts to Algolia
But Algolia contained 272 records.
Mas o Algolia continha 272 registros.
Na minha versão instalada, a tarefa incrementa seu contador antes de chamar o filtro de visibilidade do indexador. Um diagnóstico usando o mesmo indexador confirmou:
Posts examined: 723
Eligible for indexing: 272
Excluded by visibility: 451
Portanto, a mensagem de sucesso conta os posts examinados, não necessariamente os registros enviados. Essa discrepância era separada do erro de registro de tamanho excessivo.