Algoliaの再インデックスの問題

rake タスクを使用して algolia:reindex を実行したところ、次のエラーでクラッシュしました。

Clearing users from Algolia
Pushing users to Algolia
...
Successfully pushed 1849 users to Algolia
Clearing tags from Algolia
Pushing tags to Algolia
..
Successfully pushed 53 tags to Algolia
Clearing posts from Algolia
Pushing posts to Algolia
rake aborted!
Algolia::AlgoliaHttpError: Record at the position 662 objectID=690 is too big size=20920/20000 bytes. Please have a look at 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)

確認した限りでは、このプラグインには長い投稿を個別のチャンクに分割する機能は含まれていません。 @index.save_objects 呼び出しの直前に objects.reject! { |object| object.to_json.bytesize > 20000 } を追加することで、長い投稿を含めないようにして問題に対処できましたが、これらの投稿はまったくインデックス化されません。

「いいね!」 2

APIは何を期待しているのでしょうか? 複数のチャンクで送信するのか、それとも切り捨てるべきなのでしょうか?

Index long pages - Algolia によると、チャンク化する必要があり、検索時に distinct を true に設定する必要があります。

最大サイズはプランによって異なりますが、クエリする方法が見つかりません。「すべてのレコードの平均レコードサイズ」という制限も一部のプランにあることを考えると、10 KB 10000 バイトでチャンク化するのが良いかもしれません。

「いいね!」 2

「Record is too big」エラーによる Algolia 投稿再インデックスの中断の修正

Algolia にフォーラムの投稿のほんの一部しか含まれていないという問題に遭遇しました。投稿の再インデックスを実行したところ、原因が判明しました:

Algolia::AlgoliaHttpError:
Record at the position 258 objectID=1006 is too big:
size: 108426 byte(s), maximum allowed: 10000 byte(s).

私のインストール済みプラグインバージョンでは、PostIndexer#to_object が投稿全体のプレーンテキストを単一のレコードとして送信しており、シリアライズ後のレコードサイズを確認していません。サイズオーバーのレコードにより、再インデックスタスクが中断されました。

以下のローカルワークアラウンドにより、再インデックスを完了させることができました。

このパッチの内容

このパッチは、完全にシリアライズされた投稿レコードそれぞれを 9,500 バイトに制限し、Algolia から報告された 10,000 バイトの制限に対して余裕を持たせます。

パッチは以下を行います:

  • メタデータと JSON エスケープをサイズ計算に含めます。
  • Algolia に送信される content 要素のみを切り詰めます。
  • 元の Discourse 投稿は変更しません。
  • 既存の object ID と「1 投稿につき 1 レコード」という構造を維持します。

トレードオフとして、長い投稿の末尾から省略されたテキストは Algolia 経由で検索できなくなります。これはドキュメントのチャンク分割ではなく、単なる切り詰め処理です。

パッチ

対象ファイル:

plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb

to_object の最後の return 文、任意のメタデータカテゴリが追加された直後を探します:

    object
  end

そのセクションを以下に置き換えます:

# 完全なシリアライズ済みレコードのサイズを制限する(コンテンツのみではなく)。
    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

二分探索により、JSON シリアライズ後にバイト予算に収まるコンテンツプレフィックスが見つかります。メタデータだけで予算を超えている場合、このパッチはメタデータをサイレントに破棄するのではなく、明示的なエラーを発生させます。

編集前にファイルのバックアップを作成してください。このパッチは、to_object が content を含む単一のハッシュを返すバージョンを対象としています。適用前にインストール済みのバージョンに対して確認してください。

検証と再インデックス

標準的な Docker インストールの場合、ホストからコンテナに入ります:

cd /var/discourse
./launcher enter app

Discourse ユーザーに切り替えます:

su - discourse

discourse ユーザーのプロンプトが表示されたら、以下を実行します:

cd /var/www/discourse
ruby -c plugins/discourse-algolia/lib/discourse_algolia/post_indexer.rb

Syntax OK と表示されたら、以下を実行します:

RAILS_ENV=production LOAD_PLUGINS=1 bundle exec rails algolia:reindex_posts

このタスクは投稿インデックスをクリアして再作成します。私の場合は、パッチ適用後に正常に完了しました。

継続的なインデックス処理でパッチ済みコードを使用するには、既に実行中のアプリケーション/バックグラウンドワーカープロセスの再起動も必要です。

別の落とし穴:報告される投稿数

タスクは以下を報告しました:

Successfully pushed 723 posts to Algolia
But Algolia contained 272 records.

しかし Algolia には 272 件のレコードしかありませんでした。

私のインストール済みバージョンでは、タスクはインデクサーの可視性フィルターを呼び出す前にカウンターを増加させます。同じインデクサーを使用した診断により、以下が確認されました:

Posts examined:         723
Eligible for indexing:  272
Excluded by visibility: 451

したがって、成功メッセージはアップロードされたレコード数ではなく、検証された投稿数をカウントしています。この不整合は、サイズオーバーのレコードエラーとは別の問題でした。