Shopifyで記事や特集などのコンテンツを関連付ける方法 ― embeddings × メタフィールドで作る意味的レコメンド
このコラムの下までスクロールすると、「関連記事」として3本のコラムが表示されます。ありふれた機能に見えるかもしれませんが、実はShopifyのブログには関連記事を出す標準機能がありません。そして当サイトのコラムには、記事同士を結びつけるためのトピックタグも付いていません。
それでも表示されている関連記事は、AIのembeddings(埋め込みベクトル)で記事本文の「意味の近さ」を事前に計算し、Shopifyのメタフィールドに保存しておくという仕組みで選ばれています。本稿では、この機能をどう設計・実装したかを、設計判断の理由も含めて解説します。仕組みは記事同士に限らず、特集ページや商品などShopify上のコンテンツ全般の関連付けに応用でき、後述のとおりLiquidテーマでもHydrogenでも使える構成です。「重い計算をどこでやるか」という設計の一般論としても参考になるはずです。
この記事でわかること
- → Shopifyブログに「関連記事」機能を実装する設計パターン
- → embeddings(埋め込みベクトル)で記事の「意味の近さ」を測る方法とコスト感
- → 計算結果を記事参照メタフィールドに保存する利点
- → ブログ更新のwebhookがないShopifyで、再計算をcronで回す運用
前提:タグがない、標準機能もない
前提を整理します。
- 当サイトのコラムは、Shopifyのブログ機能で配信している(サイト自体はHydrogen製。経緯は別コラムで詳しく書いています)。日本語と英語の両ロケールがある。
- 記事に付いているタグは「Japanese」「English」という言語タグのみ。どの記事がどのトピックかを示すタグは存在しない。
- Shopifyのブログには「関連記事」を自動表示する標準機能がない。
よくある実装は「同じタグが付いた記事を出す」ですが、トピックタグがないので使えません。かといって、いまから全記事にタグ体系を設計して付与し、新記事のたびにタグ運用を続けるのは負荷が大きい。編集者が記事ごとに関連記事を手で選ぶのも同様です。「人手の運用を増やさずに、意味的に近い記事を機械に選ばせる」のが今回の要件でした。
設計方針:表示のたびに計算しない
「意味的に近い記事を選ぶ」だけなら、表示リクエストのたびに検索や類似度計算を走らせる構成も考えられます。しかし記事ページはサイトで最もアクセスされる場所のひとつで、そこに重い処理を置くのは筋が悪い。今回は「計算は夜間にまとめて済ませ、表示時は保存済みの結果を読むだけ」という構成にしました。
「意味の近さ」をどう測るか ― embeddings
embeddings(埋め込み)とは、文章を数百〜数千次元の数値ベクトルに変換する技術です。意味が近い文章はベクトル空間上でも近い位置に来るという性質があり、2本の記事のベクトル同士の角度(コサイン類似度)を測れば、タグやキーワードの一致に頼らず「内容が似ているか」を数値化できます。共通の単語が少なくても文脈が近い記事同士を結びつけられるのが、キーワードマッチとの決定的な違いです。
採用したモデルはOpenAIのtext-embedding-3-small(1536次元)です。多言語対応なので日本語記事にもそのまま使え、料金は100万トークンあたり約0.02ドル。当サイトの全記事(約80本)を一から埋め込み直しても数円程度という規模感です。この用途では、性能よりコストと手軽さを優先して差し支えありません。
類似度の計算は言語グループ内に閉じて行います。日本語タグの記事は日本語記事の中から、英語タグの記事は英語記事の中から関連記事を選ぶ。両方のタグを持つ記事は両方のグループでランキングされます。日本語ページの関連記事に英語記事が混ざる、といった事故を構造的に防ぐためです。
結果をどこに置くか ― 記事参照メタフィールド
事前計算の結果は、各記事のメタフィールド(Shopifyのオブジェクトに任意の構造化データを持たせる仕組み)に保存します。ここで効いてくるのが、記事参照リスト(list.article_reference)という型です。関連記事のタイトルや日付をJSONで複製して保存するのではなく、記事そのものへの参照(ID)のリストとして保存します。この違いは運用上、決定的です。
- 情報が古くならない ― 表示時に参照先の記事から最新のタイトル・公開日を取得するので、後からタイトルを直しても関連記事欄に古いタイトルが残らない。
- 非公開になった記事は自動で消える ― Storefront APIは公開中の記事しか解決しないため、参照先が非公開化されるとリストから黙って抜ける。リンク切れの心配がない。
- 並び順が保たれる ― 参照リストは書き込んだ順序を保持するので、「関連度の高い順」がそのまま表示順になる。
メタフィールドは記事ごとに3つ使っています。日本語向けランキングと英語向けランキング(いずれもストアフロントから読める公開設定)、そして計算済みembeddingベクトルのキャッシュ(非公開、後述の差分実行用)です。
オフラインパイプラインの中身
計算を担うのは、依存ライブラリなしの単一のNode.jsスクリプトです。処理は4ステップ。
ポイントは2ステップ目の差分実行です。記事ごとに「タイトル+本文」のハッシュ値をembeddingキャッシュと一緒に保存しておき、前回から変わっていない記事は埋め込みAPIを呼ばずキャッシュを再利用します。定常運用では、埋め込みが走るのは新規・更新記事だけ。それでいてランキング自体は毎回全記事で計算し直します。新しい記事が1本増えると、既存記事の関連記事リストも変わりうるからです。
いつ再計算するか ― webhookがないのでcron
理想は「記事が公開されたら即再計算」ですが、Shopifyは(執筆時点で)ブログ記事の作成・更新を通知するwebhookを提供していません。webhookの購読可能トピック一覧に記事系のトピックが存在しないのです。そこで再計算はGitHub Actionsのスケジュール実行(毎日1回、日本時間の早朝)に載せ、加えて手動トリガーも用意しました。急ぎで反映したいときはボタンひとつで回せます。
「公開から最大1日、関連記事に反映されない」ことになりますが、レコメンドの鮮度としては十分です。この割り切りができるのも、関連記事という機能の性質(多少古くても壊れはしない)によります。
ストアフロント側は「読むだけ」(Liquidテーマでも可)
表示側(当サイトの場合はHydrogen)の実装は拍子抜けするほど薄くなります。記事ページのデータ取得クエリに、参照メタフィールドの解決を数行足すだけ。Storefront APIは参照先の記事のタイトル・公開日・ハンドルを同じ1クエリの中で返してくれるので、追加のリクエストもキャッシュ層も要りません。あとは現在のロケールに応じて日本語用・英語用のリストを選び、日付とタイトルを並べるだけです。
なお、これはHydrogen(ヘッドレス)専用のノウハウではありません。通常のLiquidテーマでも、記事のメタフィールドはLiquidから直接参照でき、参照リストは記事オブジェクトの配列として解決されるので、セクションやスニペットで同じ関連記事欄を実装できます。「事前計算+メタフィールド」という構成自体は、フロントエンドが何であるかを問いません。
メタフィールドがまだ書き込まれていない記事では、関連記事セクションはそもそも描画されません。仕組みが止まってもサイトは何も壊れない、という点も運用上は重要です。
動かしてみて
初回の本番実行では、公開中の約80記事に対して182件のメタフィールドが書き込まれ、日英両ロケールで意図通りの表示になりました(日本語のみの記事が英語ページの関連記事に現れることもありません)。以後は日次のバッチが差分だけを処理しています。
定量評価はこれからですが、タグ運用も編集作業も一切増やさずに、全記事へ一括で「意味的な関連記事」が付いたことがこの構成の成果です。
まとめ ― 記事に限らない、応用の効くパターン
今回の構成を一般化すると、「重い計算はオフラインで済ませ、結果はメタフィールドに保存し、表示時は参照を解決するだけ」というパターンです。
- 類似度・ランキング・スコアリングなど、リクエストのたびに計算したくない処理に広く応用できる。
- 参照型メタフィールドを使えば、鮮度・非公開時の後始末・並び順をShopify側が面倒みてくれる。
- webhookがないイベントは、冪等なバッチ+cron+手動トリガーで補える。
Shopifyのメタフィールド(とりわけ参照型)は、こうした「計算済みデータの置き場」として非常に優秀です。参照型は記事だけでなく商品・コレクション・ページにも同じ要領で定義できるので、特集ページと記事の相互リンク、関連商品、ランキング、パーソナライズの種データなど、応用先は多いはずです。当サイトでは今後、コラム以外のブログ(ニュースやイベント)への展開や、編集者が特定記事を手動で差し込めるオーバーライドも視野に入れています。
参考・出典
- Vector embeddings(OpenAI)
- New embedding models and API updates(OpenAI)
- Metafields ― カスタムデータの概要(Shopify.dev)
- メタフィールドの型一覧(Shopify.dev)
- metafieldsSet mutation(Shopify Admin API)
- WebhookSubscriptionTopic enum(Shopify Admin API)
- Events that trigger workflows: schedule(GitHub Docs)
本コラムは当サイトでの実装(2026年7月時点)に基づいています。Shopifyの提供機能(メタフィールドの型、webhookのトピック等)やOpenAIの料金は今後変わる可能性があります。