RAG・検索基盤

直積量子化とは|1件512バイトを4バイトにしたら、再現率は8.8%だった

直積量子化とはどういう仕組みなのか区画の数で何が変わるのかこの再現率で何に使うのか

ベクトルの容量を大きく削る手法に、次元を区画に分けて、区画ごとに代表点の番号だけを持つやり方があります。直積量子化と呼ばれます。

20,000件で測ったところ、1件512バイトが4バイトになりました。元の0.8%です。ただしそのまま検索すると再現率は8.8%でした。

この記事の要点

  • 直積量子化は次元を区画に分け、代表点の番号で持つ手法
  • 4区画なら1件4バイト、元の0.8%
  • ただし並べ直しなしの再現率は8.8%
  • 16区画に増やすと31.3%だが容量は4倍

1件512バイトを4バイトにしたら、再現率は8.8%だった

区画の数を変えて実際に測りました。4区画で1件4バイト・再現率8.8%、16区画で16バイト・31.3%です。

直積量子化がどこまで容量を削れるのかを、実装して測りました。用意したのは64次元のベクトル20,000件です。

区画ごとの代表点づくりも検索も本当に実行しています。並べ直しは入れていないので、再現率は候補をそのまま結果にした場合の数字です。

javascript
function searchPQ(ix, q) {
  // 区画ごとに、問い合わせと各代表点の距離をあらかじめ表にしておく
  const table = [];
  for (let p = 0; p < ix.m; p++) {
    const row = new Float64Array(ix.kc);
    for (let c = 0; c < ix.kc; c++) {
      let s = 0;
      for (let d = 0; d < ix.sub; d++) { const t = q[p * ix.sub + d] - ix.books[p][c][d]; s += t * t; }
      row[c] = s;
    }
    table.push(row);
  }
  // 各件は、区画ごとの番号を引いて足すだけ
  const cand = [];
  for (let i = 0; i < N; i++) {
    let s = 0;
    for (let p = 0; p < ix.m; p++) s += table[p][ix.codes[i][p]];
    cand.push({ i, d: s });
  }
  return topK(cand, K);
}
text
登録 20,000件(64次元)・上位10件・問い合わせ 200回
元の大きさ 1件あたり 512 バイト

区画数  1区画の次元  代表点の数  1件の大きさ  全体   再現率   元に対する比  1回あたり
   4区画       16次元        256個          4B  0.08 MB     8.8%          0.8%       3952 μs
   8区画        8次元        256個          8B  0.15 MB    16.5%          1.6%       3982 μs
  16区画        4次元        256個         16B  0.31 MB    31.3%          3.1%       4199 μs

参考: 元のまま持つと全体で 9.8 MB、全探索は1回 5245 マイクロ秒

容量の削り方が桁違いです。9.8MBが0.08MB。ただし再現率は8.8%で、正解の10件のうち1件も取れていない問い合わせが多数あります。

なぜここまで小さくなるのか

各区画を代表点の番号だけで持つためです。16次元ぶんの値が、1バイトの番号1つに置き換わります

16次元は元の形式で128バイトです。それが1バイトになるので、128分の1になります。4区画で1件4バイトという数字は、そこから出ています。

区画を増やすと戻る

区画を増やすと、1区画あたりの次元が減って粗さがやわらぎます。4区画8.8%、8区画16.5%、16区画31.3%と上がっていきます。

ただし容量も比例します。16区画では1件16バイト、元の3.1%です。削りたい量と、許せる粗さの両方から決めることになります

この規模では速くならない

所要時間を見てください。全探索の5245マイクロ秒に対して3952マイクロ秒で、1.3倍程度にとどまります。

距離の表を先に作る工夫で1件あたりの計算は軽くなりますが、全件を見る点は変わりません。この手法の効き目は速さではなく容量にあります。

容量は桁違いに減る。ただし再現率も落ちる。

再現率(%)31.304区画8区画16区画再現率元に対する容量の比並べ直しなしでの実測。元のまま持つと1件512バイト・全体9.8MB。
図1 ── 区画数ごとの、1件あたりの大きさと再現率
出典pgvector/pgvector README2026-08-18 確認
Use binary quantization for indexes (with re-ranking for search)
原文pgvector/pgvector README この内容の有効期限2027-02-18

直積量子化とはどういう仕組みなのか

次元を区画に分け、区画ごとに代表点の一覧を作り、各ベクトルを代表点の番号の並びとして持ちます。

直積量子化は、ベクトルの次元をいくつかの区画に分け、区画ごとに代表点の番号だけを持つ手法です。

作るときの手順

  1. 次元を区画に分ける。64次元を4区画なら、16次元ずつ
  2. 区画ごとに代表点を作る。登録データから256個ずつ
  3. 各ベクトルを番号に置き換える。区画ごとに最も近い代表点の番号
  4. 元の値を捨てる。並べ直せなくなる

4番目は避けてください。元の値がなければ、後で正確に並べ直せません

検索では、問い合わせと各代表点の距離を先に表にしておきます。4区画で256個なら、1,024回の計算で表ができます。

あとは各件について、区画ごとの番号で表を引いて足すだけです。1件あたり4回の足し算で距離が出ます。

他の削り方との違い

各次元を粗く丸める方法もあります。そちらはバイナリ量子化の記事で扱っており、8ビットで容量12.5%・再現率94.8%でした。

pgvectorでは、表そのものの型を精度の低いものに変える手も案内されています。削り方はいくつもあり、削れる量と落ちる精度が違います

余談 代表点の質が結果を決める

実装してみて分かったのは、区画ごとの代表点をどう作るかで再現率が大きく動くことでした。今回は登録データから素朴に作っています。実際の製品では、この学習の作り込みが性能差になっていると考えています。

出典pgvector/pgvector README2026-08-18 確認
Use the halfvec type instead of vector for tables
原文pgvector/pgvector README この内容の有効期限2027-02-18

この再現率で何に使うのか

候補を粗く絞る段に使います。最終の順位は、残った候補を元の値で計算し直して決めます。

直積量子化の再現率8.8%という数字を見て、使えないと結論するのは早計です。この手法は、最終結果を出すためのものではありません

2段構えの前段

使い方は2段になります。小さくした値で候補を数百件まで粗く絞り、その候補だけを元の値で計算し直して並べます

pgvectorでも、並べ直しと組み合わせることで、規模が大きくても索引を記憶上に保つ使い方が案内されています。前段は速さと容量、後段は正確さを担います。

上位10件で測ると低く見える

前の節の8.8%は、上位10件だけを見た数字です。候補生成として使うなら、見るのは上位数百件になります。

その範囲に正解が入っていれば、並べ直しで拾えます。測るべき指標が、用途によって変わるということです。

そもそも要るかどうか

前提として、この手法が要るのは容量が問題になってからです。20,000件で9.8MBなら、削る必要はありません。

件数が増えて記憶上に載らなくなったときに、初めて選択肢に入ります。載っているうちは、精度を落とす理由がありません。

前段として使う。最終の順位は元の値で決める。

充足 2 / 4容量が記憶上に載らない規模になっている20,000件で9.8MBなら削る必要はない。載らなくなってから使う元の値で並べ直す工程を入れられるそのままの再現率は8.8%。前段としてしか成立しない上位10件の再現率だけで判断している候補生成として使うなら、見るのは上位数百件になる検索を速くする目的で使うこの規模では全探索の1.3倍にとどまった。効くのは容量のほう20,000件での実測にもとづく。4区画で1件4バイト・元の0.8%、再現率8.8%だった。
図2 ── 直積量子化を採用するときの点検項目
出典pgvector/pgvector README2026-08-18 確認
Use binary quantization with re-ranking to keep indexes in-memory at scale.
原文pgvector/pgvector README この内容の有効期限2027-02-18

よくある質問

なぜそこまで小さくなるのですか
各区画を代表点の番号1バイトで表すためです。64次元を4区画に分ければ、1件が4バイトになります。
再現率8.8%では使えないのでは
そのまま最終結果にすると使えません。粗く候補を絞り、残った候補だけを元の値で並べ直す使い方が前提になります。
区画を増やせばよいのですか
再現率は上がりますが容量も比例して増えます。この計測では4区画8.8%、16区画31.3%で、容量は4バイトから16バイトになりました。
検索は速くなりますか
この計測では全探索の1.3倍程度でした。件数が2万件では差が出ません。効くのは、容量が減って記憶上に載る規模になってからです。

まとめ

  • 直積量子化は区画ごとに代表点の番号だけを持つ手法
  • 1件512バイトが4バイト、元の0.8%になった
  • そのままの再現率は8.8%、16区画でも31.3%
  • 使い道は候補生成で、並べ直しと組み合わせる

今日から始められること

  1. 今のベクトルが全体で何MBあるかを数える
  2. 記憶上に載らない規模なら、区画数ごとの容量を計算する
  3. その設定での再現率を自分のデータで測る
  4. 並べ直しの工程を入れられるか確かめてから採用する

実務で組んだ直積量子化のワークフローには、値段が付きます

同じ課題を持つ会社にとって、動いている設定は「作る時間」を買えるということです。ServiceDockは自作のワークフローやテンプレートを出品できるマーケットプレイスです。手数料や出品の流れは出品者向けページにまとまっています。

出品の仕組みを見る