プログラミング
週末に10ドルでメイカー向け50万ドメイン検索エンジンを構築した話
I Built a 500k-Domain Search Engine for Makers in a Weekend for $10 (alexmorleyfinch.github.io)
要約
筆者は、企業サイトやSEOスライムに埋もれがちなメイカーのポートフォリオやアートプロジェクトなどを発見するための検索エンジンを、週末にわずか10ドルで構築しました。この検索エンジンは、約50万ドメインのホームページをクロールし、ローカルの小規模言語モデル(Gemma 4B)を使用してメタデータ(名前、要約、カテゴリ、タグ)を抽出し、ディスク容量1GB未満で個人利用可能な検索インデックスを作成しました。
全文翻訳
marlin 週末に10ドルでメイカー向け50万ドメイン検索エンジンを構築した話 日曜、午前2時。眠れず、また検索エンジンにイライラしていました。私が本当に気にかけているクエリ、ポートフォリオ、ジン、奇妙な小さなアートプロジェクト、一人で作ったソフトウェアなどは、企業のドキュメントやSEOスライムの山に埋もれていました。そこで、午前2時にすることをする:ターミナルを開き、計画を打ち込みました。「自分だけの検索エンジンを作りたい。ドメインは4000万ほどある。それぞれのドメインについて少量のメタデータを保存できる。1KBずつでも40GBになり、これは可能だ。」水曜の昼までには、560,183のホームページをカタログ化し、次に取得する価値のあるもののキューは空になり、停止することを決定しました。これはその週末の話です:私が何を作ったか、何が壊れたか、いくらかかったか、そして自分で作りたいなら何を伝えるか。もし1つの段落しか読まないなら、見出し:約10ドル、一晩GPUレンタル、そして実行中に数時間監視することで、ディスク容量1GB未満で数百サイトの個人検索インデックスを持つことができます。これが全てのピッチです。以下は、私がそこに至った経緯と、鋭いエッジの部分です。完全な技術的詳細は別途提供されます。私が実際に作ろうとしていたもの「ウェブ全体をインデックスする」のではなく、ただ:何かを作っている人、アート、コード、ハードウェア、詩、小さな劇場を見つけ、docs.company.comに溺れないようにすること。個人向け、単一ユーザー、アカウントなし。ホームページだけを見るクローラー、それぞれを読み込んで名前、2〜3文、カテゴリ、数個のタグを書き出す小さなローカル言語モデル。あいまい検索を備えた小さな検索UIで、単語の半分を入力しても正しいサイトを見つけられるようにすること。私が意図的に作っていないものを書き留めました。これは、手伝ってくれるエージェントがそれを静かに何か大きなものに「単純化」しないようにするためです:IPスキャンなし、Redisなし、完全なページHTMLの保存なし、再クロールスケジューラなし、マルチテナントなし。無視はカテゴリのチェックボックスに過ぎず、検索時に適用されました。クローラーはまだeコマースサイトを要約していましたが、それを見る必要はありませんでした。ナプキン計算では、数千万のドメインにそれぞれ約1KBのメタデータが必要で、これはPostgresボックスにとっては本当に何もありません。ページテキスト自体が決してコーパスになることはなく、モデルが処理を終えた瞬間に破棄されるスクラッチバッファに過ぎませんでした。マシン4つのプロセス、そのうち3つは私のPC上で、1つはデータベースに直接触れないレンタルGPU:フェッチャー。保留中のドメインを取得し、HTTPS、次にHTTPを試み、タイトル、本文、および単純なHTMLパーサーで外部リンクを取得します。JavaScript実行はありません。行を「準備完了」に設定します。ワーカー。準備完了のドメインを取得し、ページが空、駐車中、またはボットチャレンジウォールの場合、モデルを完全にスキップします。そうでなければ、小さなローカルモデル(Gemma、4Bパラメータ)に1つの構造化リクエストを送信し、名前、要約、カテゴリ、タグを取得します。スクラッチテキストを消去し、外部リンクを送信元のページのタイプに基づいて優先度を付けてキューに入れます。スチュワード。これはメインキューには一切触れません。疑わしいほど多くのページを生成しているホストからドメインをサンプリングし、モデルに「ブロック、維持、または不確実」と尋ね、ブロックリストを静かに維持します。なぜこれが必要だったのかについては後述します。APIと小さなWeb UI。フィルタ付き検索、非表示にするカテゴリを切り替えるページ、およびダッシュボード。これにより、ログを覗き込むのではなく、工場が何をしているかを実際に確認できます。フェッチャーが取得するものはすべて、「進行中」の間、ドメイン自身のデータベース行に直接保存されます。モデルがそれを処理し終えると、そのテキストは消去されます。これは思ったよりも重要です。なぜなら、実際の規模では、生のページテキストが永遠に積み上がるのを許すことはできないからです。4000万行に数キロバイトを掛けるとすぐに増えますが、モデルが読んでいる数秒間だけそのテキストが必要でした。ウェブは実際には90%が企業サイトです最初のバージョンは数時間で動作しました。ドメインのサンプルに向け、要約が進むのを見て、それらを検索します。素晴らしい。その後、日曜日の午後に、実際にカタログ化されたものを見ると、それは間違ったウェブでした。90%以上が企業のサイトとドキュメントでした。私のシードリストは偏っており、クローラーは次に何を追いかけるかについて意見がありませんでした。修正は何もブロックすることではありませんでした。ブロックは魅力的でしたが、間違っていると感じました。なぜなら、退屈な企業のドキュメントページが個人のブログにリンクしている可能性があり、それを失いたくなかったからです。代わりにキューに重みを付けました:「ポートフォリオ」または「ジン」または「ソフトウェア」と分類されたページは、外部リンクの優先度を大幅に上げ、企業やドキュメントと分類されたページはそれらを下げます。1つのテキストファイル、category-priority.txtが、週末の残りの操縦桿になりました。数値を調整し、1時間後に何が入ってくるかを見て、再び調整しました。その日の午後、品質が悪かったため、データベースを2回消去して最初からやり直しました。2つのバグが際立っていました:1つのサイトの要約フィールドは単に「academic-profile」と言っていました。これは、モデルが間違ったスロットに押し込んだカテゴリラベルでした。修正:疑わしいほど短い要約を失敗とみなし、より厳格なプロンプトで一度再試行します。別のサイト、実質的に実際のHTMLがほとんどないGoDaddyのドメインパーキングページは、モデルによって「ファーコミュニティ向け」と要約されました。しかし、それはホスト名で「ファー」という単語を見ただけで、本文は空で、そこから全くファンタジーサイトをでっち上げました。それは私に実際のルールを教えました:タイトルよりも表示されているテキストを信頼し、ドメイン名から推測されたものよりもタイトルを信頼し、ページがほぼ空か明らかに駐車されている場合は、モデルに尋ねる必要さえなく、マークして進むだけです。日曜の夜:Tumblrはウェブではない夕方までに、クロールは新しい問題を抱えていました。TumblrとNeocitiesのブログが大量に表示され、インデックス全体を占めるようになりそうでした。私の最初の本能はそれらをブロックすることでしたが、それは間違っていると感じました。なぜなら、Neocitiesは特に私が探していた美的感覚だったからです。実際の修正はキャップでした:メインドメインは常に許可しますが、特定のルートドメインが100以上のサブドメインを生成したら、それ以上エンキューするのを停止します。そのルールの1回のパスで、45,000ページ以上のキューが即座に削除されました。キャップは今後適用されるだけなので、Tumblrは最終インデックスに9,000ページ以上を寄付しましたが、それは物語全体ではなくなりました。この夜、実際の目的が明確になりました。「全てをインデックスする」よりも、「コミュニティのために何かを作っている人を見つける」こと。私は約10個の意図的に選ばれたドアでクロールを再シードしました:チルダコミュニティ、小さな独立系ブログプラットフォーム、いくつかのウェブリング。最終インデックスのほぼ全体が、これらの10個のシードから見つかったリンクに由来しており、シードリスト自体からではありません。月曜日の朝には、同じ問題の関連するバリエーションが現れました:フォーラムファームと中国のB2Bベンダーのマイクロサイトが、「フォーラム」カテゴリのブーストに乗って、ほぼ同一のページがブラックホールに吸い込まれていました。同じ教訓、異なるカテゴリ。「フォーラム」を大幅に格下げし、既知のミル(大量生産サイト)の明示的なブロックリストファイルを保持し始めました。GPUをレンタルする、まず悪く、次に良く私のGPU、コンシューマーカードは、ローカルで実行すると約1秒に1ページを要約できました。プロンプトの構築には十分ですが、実際にインデックスを埋めるには絶望的です。そこで、同じ小さなモデルを実際の並行処理で実行するためにクラウドGPUをレンタルしました。そして、ここで私の実際のデバッグ時間のほとんどが費やされました。AI自体に関するものではありません。短いバージョン:私の最初のレンタルセットアップは、単一GPUでも分散コンピューティングフレームワークを起動することを主張するラッパーライブラリを使用しており、そのフレームワークはホストマシンとCPU時間を奪い合っていました。GPUの料金を払っていたのに、全く求めていなかったCPU競合によってスロットリングされていました。それを捨て、単純なオープンソース推論サーバーを代わりに実行しました。ラッパーなしです。高並行処理でのコールドスタート時にクラッシュが発生しました。これは、最初のバッチ中のメモリスパイクが原因であり、定常状態の問題ではないことが判明しました。コールドスタートから全速力で急激に並行処理を開始するのではなく、徐々に並行処理を上げていくことで修正されました。実際に仕事をしたマシンは、ミドルレンジのワークステーションGPUで、完全な、未