Problemas de reindexação do Algolia

Ao executar algolia:reindex usando a tarefa rake, ele travou com o seguinte erro

Limpando usuários do Algolia
Enviando usuários para o Algolia
...
Enviados com sucesso 1849 usuários para o Algolia
Limpando tags do Algolia
Enviando tags para o Algolia
..
Enviadas com sucesso 53 tags para o Algolia
Limpando posts do Algolia
Enviando posts para o Algolia
rake abortou!
Algolia::AlgoliaHttpError: Registro na posição 662 objectID=690 é muito grande tamanho=20920/20000 bytes. Por favor, dê uma olhada em https://www.algolia.com/doc/guides/sending-and-managing-data/prepare-your-data/in-depth/index-and-records-size-and-usage-limitations/#record-size-limits (Algolia::AlgoliaHttpError)

Pelo que pude ver, o plugin não contém nenhuma funcionalidade para dividir posts mais longos em partes separadas. Consegui contornar o problema não incluindo posts longos adicionando

objects.reject! { |object| object.to_json.bytesize > 20000 }

logo antes da chamada @index.save_objects, mas isso também significa que esses posts não estão sendo indexados.

2 curtidas

Alguma ideia do que a API espera? Devemos truncar ou enviar em vários pedaços?

Conforme Index long pages - Algolia ele precisa ser dividido em partes (chunked) e distinct precisa ser definido como true ao pesquisar.

O tamanho máximo é dependente do plano, mas não consigo encontrar uma maneira de consultá-lo. Dado o fato de que também existe um limite de “tamanho médio de registro em todos os registros” em certos planos, pode ser bom dividir em partes 10 KB 10000 bytes.

2 curtidas

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.