Correzione per l’errore “Record is too big” che interrompe la reindicizzazione dei post di Algolia
Ho riscontrato un problema in cui Algolia conteneva solo una piccola parte dei post del mio forum. L’esecuzione della reindicizzazione dei post ha rivelato la causa:
Algolia::AlgoliaHttpError:
Record at the position 258 objectID=1006 is too big:
size: 108426 byte(s), maximum allowed: 10000 byte(s).
Nella versione del plugin installata nel mio ambiente, PostIndexer#to_object invia l’intero testo in chiaro di un post come singolo record, senza verificare la dimensione del record serializzato. Un record eccessivamente grande causava l’interruzione del task di reindicizzazione.
La seguente soluzione alternativa locale ha permesso alla reindicizzazione di completarsi.
Cosa fa questa patch
La patch limita ogni record completo di post serializzato a 9.500 byte, mantenendo un margine al di sotto del limite di 10.000 byte segnalato da Algolia.
Fa sì che:
-
Il calcolo della dimensione includa i metadati e l’escaping JSON.
-
Venga troncato solo il campo content inviato ad Algolia.
-
Il post originale su Discourse rimanga invariato.
-
Vengano conservati gli ID oggetto esistenti e la struttura di un record per ogni post.
Il compromesso è che il testo omesso alla fine di un post lungo non sarà cercabile tramite Algolia. Si tratta di troncamento, non di suddivisione del documento in chunk.
Patch
In:
plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb
Trova il valore di ritorno finale in to_object, immediatamente dopo l’aggiunta dei metadati facoltativi della categoria:
object
end
Sostituisci quella sezione con:
# 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
La ricerca binaria individua un prefisso del contenuto che rientra nel budget di byte dopo la serializzazione JSON. Se i soli metadati superano il budget, la patch solleva un errore esplicito invece di scartare silenziosamente i metadati.
Effettua il backup del file prima della modifica. Questa patch è destinata alla versione in cui to_object restituisce un singolo hash contenente content; esaminala rispetto alla tua versione installata prima di applicarla.
Valida e reindicizza
Per un’installazione Docker standard, accedi al container dall’host:
cd /var/discourse
./launcher enter app
Passa all’utente Discourse:
su - discourse
Una volta che appare il prompt dell’utente discourse, esegui:
cd /var/www/discourse
ruby -c plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb
Se viene riportato Syntax OK, esegui:
RAILS_ENV=production LOAD_PLUGINS=1 bundle exec rails algolia:reindex_posts
Questo task cancella e ripopola l’indice dei post. Nel mio caso, dopo l’applicazione della patch si è completato con successo.
Anche i processi applicativi/background worker già in esecuzione devono essere riavviati per utilizzare il codice patchato per l’indicizzazione continua.
Un’altra insidia: il numero di post segnalato
Il task ha riportato:
Successfully pushed 723 posts to Algolia
But Algolia contained 272 records.
Ma Algolia conteneva 272 record.
Nella mia versione installata, il task incrementa il contatore prima di chiamare il filtro di visibilità dell’indexer. Una diagnostica che utilizzava lo stesso indexer ha confermato:
Posts examined: 723
Eligible for indexing: 272
Excluded by visibility: 451
Pertanto, il messaggio di successo conta i post esaminati, non necessariamente i record caricati. Questa discrepanza era separata dall’errore dovuto ai record troppo grandi.