Do1e

Do1e

github
email

ブログの設定Algolia検索、ページネーションでテキストの長さ制限を解除する

この文は Mix Space によって xLog に同期更新されています
最適なブラウジング体験を得るために、元のリンクを訪問することをお勧めします
https://www.do1e.cn/posts/code/algolia-search


Algolia 検索設定方法#

mx-space のドキュメントには、比較的詳細な設定チュートリアルがあります。他のブログフレームワークも大同小異かもしれません。

インデックスサイズ制限#

残念ながら、ドキュメントに従って設定を完了した後、ログにエラーが表示されました:

16:40:40  ERROR   [AlgoliaSearch]  algolia プッシュエラー
16:40:40  ERROR   [Event]  Record at the position 10 objectID=xxxxxxxx is too big size=12097/10000 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 では 1 つのデータが 10KB しかありません。私のようにタダで利用したい人には耐えられないので、すぐに解決策を考えました。

解決策#

思路#

mx-space の場合、API トークンを設定した後、/api/v2/search/algolia/import-jsonから Algolia インデックスに手動で送信する json ファイルを取得できます。
これはposts、pages、notesを含むリストです。サンプルデータは以下の通りです:

{
  "title": "南京大学IPv4アドレス範囲",
  "text": "# 動機\n\n<details>\n<summary>動機は構築したウェブページから来ています。校内と公衆網の両方に構築されている....",
  "slug": "nju-ipv4",
  "categoryId": "abcdefg",
  "category": {
  "_id": "abcdefg",
  "name": "その他",
  "slug": "others",
  "id": "abcdefg"
  },
  "id": "1234567",
  "objectID": "1234567",
  "type": "post"
},

ここでobjectIDが重要で、Algolia に提出するものは必ずユニークでなければなりません。

私が考えたアイデアは、ページネーションを行い、長すぎるtextのある記事を分割し、同時にobjectIDを変更することです!(明らかに、この時点では問題の深刻さを考えていませんでした)
また、私のいくつかのページには<style><script>が書かれているので、この部分も正規表現で直接削除できます。
そこで、以下の Python コードを作成し、上記のインターフェースからダウンロードした json を編集して Algolia に送信します。

from algoliasearch.search.client import SearchClientSync
import requests
import json
import math
import os
from copy import deepcopy
import re

MAXSIZE = 9990
APPID = "..."
APPKey = "..."
MXSPACETOKEN = "..."
url = "https://www.do1e.cn/api/v2/search/algolia/import-json"
headers = {
  "Authorization": MXSPACETOKEN,
  "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0",
}

ret = requests.get(url, headers=headers)
ret = ret.json()
with open("data.json", "w", encoding="utf-8") as f:
  json.dump(ret, f, ensure_ascii=False, indent=2)
to_push = []

def json_length(item):
  content = json.dumps(item, ensure_ascii=False).encode("utf-8")
  return len(content)

def right_text(text):
  try:
    text.decode("utf-8")
    return True
  except:
    return False

def cut_json(item):
  length = json_length(item)
  text_length = len(item["text"].encode("utf-8"))
  # 分割数を計算
  n = math.ceil(text_length / (MAXSIZE - length + text_length))
  start = 0
  text_content = item["text"].encode("utf-8")
  for i in range(n):
    new_item = deepcopy(item)
    new_item["objectID"] = f"{item['objectID']}_{i}"
    end = start + text_length // n
    # 分割時は正しくデコードできることを確認する必要があります(中国語は2バイトを占めます)
    while not right_text(text_content[start:end]):
      end -= 1
    new_item["text"] = text_content[start:end].decode("utf-8")
    start = end
    to_push.append(new_item)

for item in ret:
  # styleとscriptタグを削除
  item["text"] = re.sub(r"<style.*?>.*?</style>", "", item["text"], flags=re.DOTALL)
  item["text"] = re.sub(r"<script.*?>.*?</script>", "", item["text"], flags=re.DOTALL)
  if json_length(item) > MAXSIZE: # 制限を超えた場合、分割
    print(f"{item['title']} は大きすぎます、分割します")
    cut_json(item)
  else: # 制限を超えていない場合もobjectIDを変更して一貫性を保つ
    item["objectID"] = f"{item['objectID']}_0"
    to_push.append(item)

with open("topush.json", "w", encoding="utf-8") as f:
  json.dump(to_push, f, ensure_ascii=False, indent=2)

client = SearchClientSync(APPID, APPKey)
resp = client.replace_all_objects("mx-space", to_push)
print(resp)

他のブログフレームワークを使用している場合、ここまでで十分です。何かの参考になれば幸いです。

素晴らしい、Python を使用して検索インデックスを修正し、再度 Algolia に送信して mx-space のバックエンドで検索機能を有効にし、制限を超えたJPEG エンコーディングの詳細を検索してみてください。
結果が出ないのはなぜですか?バックエンドで再びエラーが表示されました。

17:03:46  ERROR   [Catch]  Cast to ObjectId failed for value "1234567_0" (type string) at path "_id" for model "posts"
  at SchemaObjectId.cast (entrypoints.js:1073:883)
  at SchemaType.applySetters (entrypoints.js:1187:226)
  at SchemaType.castForQuery (entrypoints.js:1199:338)
  at cast (entrypoints.js:159:5360)
  at Query.cast (entrypoints.js:799:583)
  at Query._castConditions (entrypoints.js:765:9879)
  at Hr.Query._findOne (entrypoints.js:768:4304)
  at Hr.Query.exec (entrypoints.js:784:5145)
  at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
  at async Promise.all (index 0)

mx-space のコードを編集しましょう#

上記のログから、mx-space がObjectIdをインデックスとして使用していることが簡単にわかります。idではなく、コードのここに位置を特定します:

https://github.com/mx-space/core/blob/20a1eef/apps/core/src/modules/search/search.service.ts#L164-L165

これを以下のように修正すれば大丈夫です。

https://github.com/Do1e/mx-space-core/blob/1d50851/apps/core/src/modules/search/search.service.ts#L167-L168

さらに改善する#

これだけではあまり優雅ではありません。定期的に Python スクリプトを実行してデータを Algolia にプッシュする必要があります。せっかく mx-space のコードを修正したのだから、ページネーションを統合してしまいましょう。今の AI は、元々あまり得意でなかったプログラミング言語を素早く習得するのに役立ちます。

/apps/core/src/modules/search/search.service.tsbuildAlgoliaIndexData()の後に以下のコードを追加し、ロジックは上記の Python と同じです:

https://github.com/Do1e/mx-space-core/blob/1d50851/apps/core/src/modules/search/search.service.ts#L297-L333

Docker イメージを再構築し、公式イメージに切り替えれば OK です!

ただし、元のバージョンでは、単一の要素のプッシュをトリガーするために 3 種類のイベント(追加、削除、変更)が定義されているので、ここは面倒なので、デコレーター(ts では何と呼ばれるのでしょう?Python ではこう呼ばれますが)をpushAllToAlgoliaSearchに移動させれば良いでしょう。

小話#

コードを編集しているとき、実際にはコード内で制限を超えた場合に切り捨てるように定義されていることに気付きました。しかし、定義されているのは 100KB で、開発者は有料ユーザーのようです。個人的には、この設定を環境変数にする方が良いと思います。コードにハードコーディングするのではなく。

https://github.com/mx-space/core/blob/20a1eef/apps/core/src/modules/search/search.service.ts#L370

2024/12/21: 作者が設定可能な切り捨てを更新しましたが、私はページネーションでの送信の方が好きです。全文検索ができるからです。

https://github.com/mx-space/core/commit/6da1c13799174e746708844d0b149b4607e8f276

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。