0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

楽天APIがJANを返さない問題を、横断マッチングの3段階で捌く

0
Posted at

楽天と Yahoo! の商品 API を横断して「同じ商品の最安はどこか」を出そうとすると、価格計算より前に「そもそも同じ商品をどう同定するか」で詰まります。JAN(商品のバーコード番号)で結べれば早いのですが、ここに非対称があります。

  • Yahoo! ショッピング: jan_code パラメータで JAN を正引きでき、レスポンスにも janCode が乗る。
  • 楽天 商品検索 API: JAN 専用パラメータが無い。keyword に JAN 文字列を投げる間接突合になり、JAN 自体は商品説明文(itemCaption)に紛れていることが多い。

つまり Yahoo! は信頼して JAN 確定に使えますが、楽天は「keyword=JAN で出たヒットが本当にその商品か」を後から確かめないと使えません。この前提でマッチングを確実性で 3 段階に分けた設計を共有します。

確実性で 3 段階に分ける

全件を JAN で突合しようとせず、確実に結べるものだけを最上段に置きます。下段ほど確証が弱いので、横断比較と通知の権利を絞ります。

方法 横断比較 通知
① JAN 突合 Yahoo! 正引き+楽天 keyword=JAN を確証スコアで判定 確定したものだけ 出す
② 名前ファジー一致 型番・容量・ブランドでスコア化→候補提示→ユーザー確認 確認後 確認済みのみ
③ マッチ不能 単一モール(URL 貼り付け等)として扱う しない 単一モールの値下げのみ

最小実装: 楽天ヒットの確証スコア

楽天の 1 ヒットごとに加点・減点してスコアを出し、閾値で 3 つに割ります。0.8 以上を確定、0.5 以上を要確認(通知不可)、それ未満は破棄です。

type Grade = "high" | "mid" | "low";

function janMatchScore(
  hit: { itemName: string; itemCaption: string; itemPrice: number },
  jan: string,
  range: { min: number; max: number } | null,
): { grade: Grade; score: number } {
  let s = 0;
  // (1) 名前か説明文に JAN 文字列を含む(最も直接的な証拠)
  if (hit.itemCaption.includes(jan) || hit.itemName.includes(jan)) s += 0.5;
  // (2) 製品検索 API の価格レンジ妥当性
  if (range) {
    const lo = range.min * 0.7; // 下振れ30%許容(型落ち・並行品)
    const hi = range.max * 1.5; // 上振れ50%許容(送料込・セット品)
    s += hit.itemPrice >= lo && hit.itemPrice <= hi ? 0.3 : -0.4;
  }
  // (3) 型番か容量が読み取れる
  if (/[a-z]+-?\d+/i.test(hit.itemName) || /\d+\s*(ml|g|枚|個)/i.test(hit.itemName)) s += 0.2;

  const score = Math.max(0, Math.min(1, s));
  const grade: Grade = score >= 0.8 ? "high" : score >= 0.5 ? "mid" : "low";
  return { grade, score };
}

確証の弱いヒットを確定扱いしないこと(=low を捨て、mid を通知させないこと)が、別商品を同一商品として束ねる「誤名寄せ」を防ぐ一番効く制御でした。

ハマりどころ

  • 製品検索 API(productCode=JAN)が 404 を返しがち。価格レンジが取れないヒットが多く、(2) のレンジ加点に頼り切れません。そこで横断相手(Yahoo! の同 JAN ヒット)の代表価格を基準に、楽天ヒットの名前に相手の型番トークン(英数混在 5 字以上=ほぼ一意)が含まれ、かつ価格が相手価格の ±40% 以内なら確定へ昇格、という確証を足しました。型番一致だけだと偶然衝突するので、価格バンドで弾きます。

  • ファジー段は自動確定しない。型番・容量・ブランドが一致してもスコアは確率でしかないので、候補提示までで止め、ユーザーが「同じ商品」と確認したものだけをマスタ化します。誤って結ばれた組はワンタップで除外(突合候補から永久に外す)。通知が発火するのは JAN 確定とユーザー確認済みだけにしています。

まとめ

JAN が揃わない前提でも、確実性で 3 段階に落とせば横断比較は成立します。確実に JAN で結べるものだけを確定層に置き、確証の弱いものは候補提示、結べないものは単一モール通知へ。無理に全件 JAN 突合しないことが誤名寄せを防ぎます。

ポイント還元込みの実質価格の計算、誤マッチ報告の蓄積、通知の発火条件まわりの運用知見は Aulvem 本家にまとめました → 楽天APIがJANを返さない問題と、横断マッチングの3段階

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?