概要
SEO観点で内部リンクを適切に埋め込み、サイト内部の回遊を促す仕組みは非常に重要です。
例えば、Handbookでは記事本文中の単語へのリンク埋め込み(画像中のアンダーバーがついている文字)や関連記事カードの埋め込みを行っています。
本記事では、Pineconeを活用して内部リンクを効率的に生成する方法とその精度を向上させる工夫についてHandbookでの事例を基に解説します。
Pineconeの概要
Pineconeは、高速かつスケーラブルなベクトルデータベースとして、多くのLLMベースのアプリケーションで利用されています。特に内部リンク生成においては、以下のようなメリットがあります。
数十億のアイテムを扱う場合でも、あらゆるスケールで超低遅延のクエリレイテンシーを実現
ベクトル検索とメタデータフィルタを組み合わせて、より適切で迅速な結果を得ることができる
内部リンク生成の実装フロー
Pineconeを使った内部リンク生成の実装フローをHandbookの事例を基に解説します。
具体的には、Pinecone のような、記事本文中の単語の内部リンクを生成する方法について解説します。
1. 記事情報データベースの作成
前準備として、記事の本文を埋め込んだPinceconeのデータベースを作成しておきます。
Handbookではgithubで管理している記事データをバッチ処理でpineconeに移行しています。
なお、インデックスの作成方法はこちら の記事で解説しています。
2. ChatGPTによる単語の選定
本文の中から内部リンクを付与する単語を選定します。なお、この処理も自動化するために、ChatGPTを使って選定させます。
具体的には、system_promptとして以下のような指示を与えます。
web記事の本文を与えるので、内部リンクを埋め込む単語を5個選んで出力してください。なお、一般的すぎたり、ありふれた言葉は避け、製品名や技術名もしくは読者が詳細を知りたくなるような単語を選んでください\n"
3. テキストからのベクトル生成
選択した単語(テキスト)をベクトル化してPineconeで検索ができるようにします。
具体的にはOpenAI API
を使用して、入力テキストをベクトル形式に変換します。以下はPythonでの実装例です。
from openai import OpenAI
def vectorize_text(text):
client = OpenAI(api_key="YOUR_API_KEY")
response = client.embeddings.create(model="text-embedding-3-small", input=text)
return response.data[0].embedding
4. ベクトル検索でリンク候補を取得
3で変換したベクトルに対して、Pineconeのクエリ機能を使用してベクトル検索を行い、リンク候補を取得します。
from pinecone import Pinecone
def search_vector(index, vector, top_k=5):
query_params = {
"vector": vector,
"top_k": top_k,
"include_values": False,
"include_metadata": True,
}
query_result = index.query(**query_params)["matches"]
matches = query_result["matches"]
return matches
なお、top_kは与えたベクトル(単語)と類似するベクトル(記事)を類似度が高い順に何個取ってくるかを表していますが、ここでは1よりも大きい数を指定しています。
5. 候補の中から最適なリンクを選定
各単語について、top_k 個だけ類似記事を取ってくることができているので、後はどの記事を内部リンクとして埋め込むかを考えます。
記事の選定についてHakkyでは、以下の4つの工夫をしています。
リンクを張りたい記事と、リンク先の記事が同じトップレイヤー(記事の大カテゴリ)であること
既に同じ記事に内部リンクとして張った記事ではないこと
類似度(score)が閾値以上であること
1-3の条件をすべて満たす中で最も類似度が高い記事であること
実装例は次のようになります。
def get_best_match(matches, used_uris):
matches = sorted(matches, key=lambda x: x["score"], reverse=True)
matches = [match for match in matches if match["score"] > minimal_score]
for match in matches:
uri = match["metadata"]["uri"] #pineconeには記事のuriも埋め込んでおく
link_article_layer = uri.split("/")[0] #
if (uri not in self.used_uris) and (not id or id not in uri):
if not top_layer or link_article_layer == top_layer:
self.used_uris.append(uri)
return uri
このようにすることで、単語ごとに内部リンク先のuriを取得することができます。(条件を満たす記事がなく、取得できない場合もありますが精度の低いリンクを貼ってしまうことを防ぐため、このような実装にしています。)
6. 記事本文への反映
各単語(word)に対してリンク先のuriを取得することができたので、記事の本文(text)に埋め込みます。
実装としては以下のようにします。
text = text.replace(f"[{word}]", f"[{word}](https://book.st-hakky.com/{link})")
これで内部リンクの埋め込みは完了です。
まとめ
本記事では、Pineconeを活用して効率的かつ精度の高い内部リンク生成を実現する方法について具体例を用いて解説しました。
Pineconeを活用しつつ、さらにリンクの関連性を高める工夫を施すことで、より良いユーザーエクスペリエンスを提供することが可能です。ぜひ、試してみてください。
備考
Hakky ではエンジニアを募集中です!まずは話してみたいなどでも構いませんので、ぜひお気軽に採用ページからお問い合わせくださいませ。