Skip to content

クエリ時に精度を選択できるベクトル検索エンジンを構築した方法

image from slack
Raufs Dunamalijevs
2025年10月28日 · 34分で読む

TL;DR
ClickHouse に浮動小数点数をビットプレーンとして保存するカラム型 QBit を追加しました。これにより、ベクトル検索時に読み出すビット数を選択できるようになり、データを変更することなく再現率とパフォーマンスを調整できます。

ベクトル検索はいまや、あらゆる場所で利用されています。楽曲のレコメンドや、外部知識を取得して回答の精度を高める大規模言語モデル向け検索拡張生成(RAG)を支えており、Google 検索でも一定の範囲でベクトル検索が活用されています。ベクトル検索に特化した専用データベースも数多く構築されています。しかし、そうしたシステムは構造化データの保存やクエリ実行には適していないことが珍しくありません。その結果、完全な専用ベクトルストアよりも、アドホックなベクトル機能を備えた一般的なデータベースを好むユーザーがよく見られます。

ClickHouse では、総当たり(ブルートフォース)のベクトル検索がすでに数年前からサポートされています。さらに最近では、高速なベクトル検索の現在のデファクトスタンダードである HNSW をはじめとする近似最近傍(ANN)検索の手法を追加しました。また、量子化のアプローチを再検討し、新しいデータ型である QBit を開発しました。

ベクトル検索の手法にはそれぞれ、再現率、精度、パフォーマンスのトレードオフを決定づけるパラメータが存在します。通常、これらは事前に決定しなければなりません。設定を誤ると多くの時間とリソースが無駄になり、後から方針を変更するのは大きな負担となります。

QBit を使えば、事前の決定は不要です。クエリ実行時に精度と速度のトレードオフを直接調整でき、状況に応じて最適なバランスを探索できます。

ベクトル検索の基本

まずは基本から始めましょう。ベクトル検索は、データセットの中から最も類似したドキュメント(テキスト、画像、楽曲など)を見つけるために使われます。最初に、すべての項目を埋め込みモデルによって高次元ベクトル(浮動小数点数の配列)へと変換します。これらの埋め込みは、データの意味を捉えています。ベクトル間の距離を比較することで、2 つの項目が意味的にどれほど近いかを確認できます。

簡単な例を見てみましょう。果物と動物の埋め込みがあるとします。lemon(レモン)に最も近いのはどれだと思いますか? 🍋

Diagram 4.jpg

apple(リンゴ)です!この例は少し奇妙に思えるかもしれません。レモンはオレンジや、同じ黄色であるバナナのほうが概念的に近いと感じるはずです。それでも、これはサイズ 5 の比較的小さな埋め込みに対して総当たり検索を実行した実際の結果です。

CREATE TABLE fruit_animal 
ENGINE = MergeTree 
ORDER BY word 
AS SELECT * 
FROM VALUES(
  'word String, vec Array(Float64)',
  ('apple', [-0.99105519, 1.28887844, -0.43526649, -0.98520696, 0.66154391]),
  ('banana', [-0.69372815, 0.25587061, -0.88226235, -2.54593015, 0.05300475]),
  ('orange', [0.93338752, 2.06571317, -0.54612565, -1.51625717, 0.69775337]),
  ('dog', [0.72138876, 1.55757105, 2.10953259, -0.33961248, -0.62217325]),
  ('horse', [-0.61435682, 0.48542571, 1.21091247, -0.62530446, -1.33082533])
);
SELECT word, L2Distance(
  vec, [-0.88693672, 1.31532824, -0.51182908, -0.99652702, 0.59907770]
) AS distance
FROM fruit_animal 
ORDER BY distance 
LIMIT 5;
┌─word───┬────────────distance─┐
1. │ apple  │ 0.14639757188169716 │
2. │ banana │  1.9989613690076786 │
3. │ orange │   2.039041552613732 │
4. │ horse  │  2.7555776805484813 │
5. │ dog    │   3.382295083120104 │
   └────────┴─────────────────────┘

次元数の高い埋め込みを用いれば、より複雑な関係性を表現でき、より豊かな結果を得られます。ただ、horse(馬)と dog(犬)がリストの下位に来ている点については、納得していただけるのではないでしょうか。

近似最近傍(ANN)

厳密なベクトル検索は強力ですが低速であり、したがってコストがかかります。多くのアプリケーションでは、ある程度の柔軟性が許容されます。たとえば、Eminem を聴いた後に Snoop Dogg や Tupac がレコメンドされるのは問題ありません。しかし、次の提案がこれになってしまったら、何かが致命的に間違っています。

そこで役立つのが近似最近傍(ANN)の技術です。完全な精度を犠牲にする代わりに、より高速かつ低コストな検索を実現します。代表的なアプローチとして、量子化HNSW の 2 つが挙げられます。

まずは両者を簡単に確認し、その中で QBit がどのような位置づけにあるのかを見ていきましょう。

量子化

格納されているベクトルが Float64 型であり、そのパフォーマンスに満足できていないとします。当然生じる疑問は、「データをより小さな型にダウンキャストしたらどうなるか?」という点です。

数値が小さくなればデータサイズも小さくなり、データが小さくなれば距離計算も高速化されます。ClickHouse のベクトル化クエリ実行エンジンは、1 回の演算につきプロセッサのレジスタにより多くの値を収められるため、スループットが直接向上します。さらに、ディスクから読み出すバイト数が減ることで I/O 負荷も軽減されます。このアプローチは量子化として知られています。

量子化を行う際は、データの格納方法を決める必要があります。選択肢は次の 2 つです。

  1. 元のカラムと並行して量子化されたコピーを保持する。
  2. (挿入時にダウンキャストすることで)元の値を完全に置き換える。

1 つ目の選択肢はストレージ使用量が 2 倍になりますが、いつでも完全な精度に戻せるため安全です。2 つ目の選択肢は容量と I/O を節約できますが、後戻りはできません。後になって量子化が粗すぎて結果の精度が落ちていると気づいても、やり直す手段はありません。

階層型ナビゲーブルスモールワールド(HNSW)

すべての候補を走査することなく最近傍を見つけられるように設計されたデータ構造は数多く存在します。これらはインデックスと呼ばれます。その中でも HNSW は、しばしば決定版と見なされています。

Diagram 1.jpg

HNSW は、ノード(ベクトル)の複数レイヤーで構成されます。各ノードは 1 つ以上のレイヤーにランダムに割り当てられ、上位レイヤーに現れる確率は指数関数的に減少します。

検索を実行する際は、最上位レイヤーのノードから開始し、最も近い近傍に向かって貪欲に進んでいきます。それ以上近いノードが見つからなくなると、次の密なレイヤーへと降りて処理を続けます。上位レイヤーが長距離の接続を提供することで局所最適解に陥るのを防ぎ、下位レイヤーが高精度を担保します。

この階層構造により、HNSW はノード数に対して対数オーダーの検索計算量を実現します。総当たり検索や量子化ベースの手法で使われる線形走査と比べてはるかに高速です。

最大のボトルネックはメモリです。ClickHouse は HNSW の実装として usearch を採用していますが、これは分割に対応していないインメモリのデータ構造です。そのため、データセットが大きくなるほど比例して多くの RAM が必要になります。インデックス構築前にデータを量子化することでフットプリントを抑えられますが、量子化レベル自体を含め、事前に多くの HNSW パラメータを決定しなければならない点は変わりません。まさにこの融通の利かなさを解消するために設計されたのが QBit です。

量子化ビット(QBit)

QBit は、浮動小数点数がビットとして表現される仕組みを活用し、BFloat16Float32Float64 の値を格納できる新しいデータ構造です。各数値をひとかたまりとして保存するのではなく、QBit は値をビットプレーンへと分割します。つまり、すべての 1 ビット目、すべての 2 ビット目、すべての 3 ビット目、というようにグループ化して保持します。

検索の実行時、ClickHouse はユーザーが指定した精度までデータを再構成するために必要なサブカラムだけを読み出すことができます。

Updated Diagram 2.jpg

このアプローチにより、従来の量子化が抱えていた大きな制約が解消されます。データを重複して保持する必要も、値が意味をなさなくなるリスクを負う必要もありません。また、QBit はインメモリインデックスを維持するのではなく保存されたデータを直接扱うため、HNSW のような RAM のボトルネックも回避できます。

何よりも、事前の決定が不要になります。クエリ実行時に精度とパフォーマンスを動的に調整できるため、余計な手間をかけずに精度と速度のバランスを探索できます。

QBit はベクトル検索を高速化しますが、その計算量は依然として O(n) です。言い換えれば、「データセットが十分に小さく、HNSW インデックスが RAM に無理なく収まるのであれば、依然として HNSW が最も高速な選択肢である」ということです。

項目総当たりHNSWQBit
精度完全非常に高い柔軟
速度低速高速柔軟
その他量子化時:容量増か不可逆な精度低下の二者択一インデックスがメモリに収まる必要があり構築も必要計算量は依然としてレコード数に依存(O(N))

QBit の詳細

先ほどのおなじみの例を、今度は QBit の環境で改めて見てみましょう。

CREATE TABLE fruit_animal
(
    word String,
    vec QBit(Float64, 5)
)
ENGINE = MergeTree
ORDER BY word;

INSERT INTO fruit_animal VALUES
('apple',  [...]),
('banana', [...]),
('orange', [...]),
('dog',    [...]),
('horse',  [...]);

続いてクエリを実行します。

SELECT 
  word, 
  L2DistanceTransposed(vec, [...], 16) AS distance 
FROM fruit_animal 
ORDER BY distance;
┌─word───┬────────────distance─┐
1. │ apple  │ 0.14639757188169716 │
2. │ banana │   1.998961369007679 │
3. │ orange │   2.039041552613732 │
4. │ cat    │   2.752802631487914 │
5. │ horse  │  2.7555776805484813 │
6. │ dog    │   3.382295083120104 │
   └────────┴─────────────────────┘

QBit に対する操作は、大きく 2 つの部分に分かれます。

  1. データ型自体:作成とデータの取り込み。
  2. 距離計算。

それぞれを詳しく見ていきましょう。

データ型

Diagram 5.jpg

データが QBit カラムに挿入されると、すべての 1 ビット目が揃い、すべての 2 ビット目が揃うように転置されます。これらをグループと呼びます。

各グループは個別の FixedString(N) カラムに格納されます。これはメモリ上に区切りなしで連続して配置される N バイトの固定長文字列です。こうして作られたすべてのグループが 1 つの Tuple にまとめられ、これが QBit の内部構造を形成します。

8 個の Float64 要素からなるベクトルの場合、各グループには 8 ビットが含まれます。Float64 は 64 ビットなので、最終的に(各ビットに対して 1 つずつ)64 個のグループができます。したがって、QBit(Float64, 8) の内部レイアウトは 64 個の FixedString(1) カラムからなる Tuple のようになります。

元のベクトルの長さが 8 で割り切れない場合は、見えない要素でパディングされ、8 に揃えられます。これにより、バイト単位で厳密に動作する FixedString との互換性が保たれます。たとえば上の図では、ベクトルに 5 個の Float64 の値が含まれています。これに 3 つのゼロがパディングされて 8×Float64 となり、64 個の FixedString(1) からなる Tuple に転置されます。また、76 個の BFloat16 要素から始める場合は 80 個の BFloat16 にパディングされ、16 個の FixedString(10) からなる Tuple に転置されます。

距離計算

SELECT 
  word, 
  L2DistanceTransposed(vec, [...], 16) AS distance 
FROM fruit_animal 
ORDER BY distance;

I/O の最適化

距離を計算する前に、必要なデータをディスクから読み出し、逆転置(ビットグループ化された表現から完全なベクトルへ復元)する必要があります。QBit は精度レベルごとにビット転置して値を保存しているため、ClickHouse は目的の精度まで数値を再構成するために必要な上位ビットプレーンだけを読み出すことができます。

上記のクエリでは、精度レベルとして 16 を指定しています。Float64 は 64 ビットなので、最初の 16 ビットプレーンだけを読み出し、データの 75% をスキップします。

Diagram 3.jpg

読み出し後、ロードされたビットプレーンから各数値の上位部分のみを再構成し、読み出されなかったビットはゼロのままにしておきます。

Diagram 6.jpg

計算の最適化

Float32BFloat16 などのより小さな型にキャストすれば、この未使用部分を排除できるのではないかと考えるかもしれません。確かに可能ですが、すべての行に対して明示的なキャストを適用するとコストがかさみます。そうする代わりに、参照ベクトルだけをダウンキャストし、QBit データはよりビット幅の狭い値が含まれているものとして扱う(一部のカラムの存在を「忘れる」)ことができます。なぜなら、そのレイアウトはそうした型の切り捨て版と一致することが多いためです。ただし、常にそうとは限りません!

Diagram 7.jpg

まずは、元データが Float32 であり、選択された精度が 16 ビット以下という単純なケースから見てみましょう。BFloat16 は、Float32 を半分に切り捨てたものです。符号ビットと 8 ビットの指数部は同じまま保持し、23 ビットの仮数部のうち上位 7 ビットのみを残します。このため、QBit カラムから最初の 16 ビットプレーンを読み出すと、事実上 BFloat16 値のレイアウトが再現されます。したがってこのケースでは、参照ベクトル(QBit 内のすべてのデータと比較されるベクトル)を BFloat16 に安全に変換し(実際にそうしています)、QBit データを最初からその形式で格納されていたものとして扱えます。

一方、Float64 は話が異なります。11 ビットの指数部と 52 ビットの仮数部を使用しているため、単にビット数が 2 倍になった Float32 というわけではありません。構造も指数のバイアスもまったく異なります。Float64Float32 のようなより小さな形式にダウンキャストするには、各値を最も近い表現可能な Float32丸めるという、実際の IEEE-754 変換処理が必要になります。この丸め処理は計算負荷が高く、単純なビットのスライスや並べ替えで代替することはできません。

これは精度が 16 以下のときも同様です。Float64 から BFloat16 への変換は、実質的に一度 Float32 に変換してから BFloat16 へ切り捨てる処理と同じになります。そのため、この場合もビットレベルの工夫では解決できません。

ベクトル化の実装

ベクトル化とは

通常の量子化カラムと QBit カラムの主なパフォーマンス上の違いは、検索時にビットグループ化されたデータをベクトル形式へと逆転置する必要がある点です。これを効率的に実行することが極めて重要になります。ClickHouse にはベクトル化クエリ実行エンジンが備わっているため、それを活かさない手はありません。ベクトル化の詳細については、ClickHouse のこちらのブログ記事をご覧ください。

要約すると、ベクトル化とは SIMD(Single-Instruction-Multiple-Data)レジスタを使用して、CPU が単一の命令で複数の値を処理できるようにする仕組みです。この用語は、SIMD 命令がデータの小さなまとまり(ベクトル)に対して動作することに由来しています。これらのベクトル内の個々の要素は固定長であり、一般にレーン(lane)と呼ばれます。

アルゴリズムをベクトル化する一般的なアプローチには次の 2 つがあります。

  1. 自動ベクトル化:コンパイラが具体的な SIMD 命令を自動的に判断できるようにアルゴリズムを記述します。コンパイラがこれを行えるのは非常にシンプルで直線的な関数に限られるため、通常そのような記述を実現するには、こちらのようにシステムのアーキテクチャ全体を自動ベクトル化アルゴリズムに合わせて綿密に設計する必要があります。

  2. 組み込み関数(Intrinsics):コンパイラが CPU 命令に直接マッピングする特殊な関数である明示的な組み込み関数を使ってアルゴリズムを記述します。これらはプラットフォームに依存しますが、完全な制御が可能です。

基本アルゴリズム

SIMD による逆転置は、コンパイラが自動ベクトル化するには複雑すぎるため、私たちは 2 つ目のアプローチを採用しました。その手順を順を追って説明します。まずはアルゴリズムの背後にある考え方を見てから、それがベクトル化の世界にどう組み込まれるかを確認しましょう。

Diagram 8.jpg

Diagram 9.jpg

Diagram 10.jpg

Diagram 11.jpg

QBit のすべての FixedString カラム(Float64 の場合は 64 個)をループします。各カラム内では FixedString の各バイトを走査し、各バイト内では各ビットを走査します。

ビットが 0 の場合、書き込み先(destination)の対応する位置にゼロマスクを適用します。ビットが 1 の場合は、バイト内の位置に応じたマスクを適用します。たとえば、1 ビット目を処理している場合のマスクは 10000000 であり、2 ビット目なら 01000000 となります。適用する演算は論理 OR であり、ソースからのビットを書き込み先バイトにマージします。

ベクトル化されたアルゴリズム

現代の CPU で広く普及している命令セットである AVX-512 を使用した 2 回目のイテレーション(上記のステップ 3 と 4)を見てみましょう。この例では、2 つ目の FixedString(1) グループを展開しており、ここでの各ビットは、結果として得られる 8 つの Float64 値の2 ビット目を構成します。

Diagram 12.jpg

SIMD を扱う際は、レーン単位で考えると理解しやすくなります。AVX-512 は 512 ビットレジスタで動作し、これは 8 つの 64 ビットレーンに相当します。データのレイアウトを視覚化するために、固定長文字列をこれらのレーンにマッピングしてみましょう。

Diagram 13.jpg

Float642 番目のビットを展開しているため、ビットマスクは 2 番目のビットが立った状態になります。
このマスクを各レーンに適用します。

Diagram 14.jpg

書き込み先(dst)には、前のイテレーションの結果がすでに含まれています。ここに 2 ビット目もマージする処理を進めます。

Diagram 15.jpg

ここからが興味深い部分です。マスクがすべて 1 であれば、新しいビットを書き込み先に単純に OR 演算します(このケースを upd と呼びます)。マスクがすべて 0 であれば、書き込み先は変更されません。実際には、マスクの各ビットによって更新するレーンが決まります。マスクが 1 の位置では upd の値を取り、0 の位置では古い値をそのまま保持します。幸いなことに、AVX-512 にはまさにこれを行う組み込み関数が用意されています。マスクビットに基づいて upddst のいずれかを選択し、レーン内で要素を条件付きでマージしてくれます。

Diagram 16.jpg

これだけで、1 回のイテレーションで 8 つの値を展開できました!

データの準備が整ったので、距離を計算できます。計算には、ほぼすべてのハードウェアでベクトル化された距離計算を実行できる優れたライブラリである SimSimd を使用しています。

ベンチマーク

Float32 埋め込みとして表現された約 2,900 万件のコメントを含む HackerNews データセットでベンチマークを実施しました。1 つの新しいコメント(その埋め込みを使用)を検索する速度を測定し、10 件の新しいコメントに基づいて再現率を算出しました。

ここでの*再現率(Recall)*は、検索された上位 k 件(今回は k = 20)の中に含まれる真の最近傍の割合です。*粒度(Granularity)*は、読み出すビットグループの数を示します。

Diagram 17.jpg

良好な再現率を維持しながら、約 2 倍の高速化を達成しました。さらに重要なのは、ワークロードに合わせて速度と精度のバランスを直接制御できるようになった点です。

なお、Float64 の再現率の結果は割り引いて考える必要があります。これらの埋め込みは単に Float32 をアップキャストしたものであるため、Float64 の下位ビットには情報がほとんど含まれておらず、それらを削除しても本来ほど再現率に影響が出なかったためです。ただし、高速化の数値自体はどちらのケースでも十分に信頼できます。

ですが、ベンチマークばかりでは退屈です。少し面白いことを試してみましょう!

応用例

テーブルを作成し、DBpedia のデータをダウンロードします。これには、Float32 埋め込みとして表現された 100 万件の Wikipedia 記事が含まれています。ここで、QBit カラムを追加します。

set allow_experimental_qbit_type = 1;
ALTER TABLE dbpedia ADD COLUMN qbit QBit(Float32, 1536);
ALTER TABLE dbpedia UPDATE qbit = vector WHERE 1;

まずは総当たり検索から始めましょう。宇宙に関連するすべての検索用語(Moon, Apollo 11, Space Shuttle, Astronaut, Rocket)に最も関連性の高い概念を探します。技術的に表現すると次のようになります。

5 つの概念それぞれについて、意味的に類似した上位 1,000 件のエントリを検索します。それらの結果のうち少なくとも 3 つに出現するエントリを抽出し、一致した概念の数と、それらのいずれかへの最小距離(元の用語自体は除く)によってランク付けして返します。

クエリが長いため、完全なクエリは Pastila で確認できます。結果は以下のとおりです。

Row 1:
──────
title:                Apollo program
text:                 The Apollo program, also known as Project Apollo, was the third United States human spaceflight program carried out by the National Aeronautics and Space Administration (NASA), which accomplished landing the first humans on the Moon from 1969 to 1972. First conceived during Dwight D. Eisenhower's administration as a three-man spacecraft to follow the one-man Project Mercury which put the first Americans in space, Apollo was later dedicated to President John F.
num_concepts_matched: 4
min_distance:         0.82420665
avg_distance:         1.0207901149988174

Row 2:
──────
title:                Apollo 8
text:                 Apollo 8, the second human spaceflight mission in the United States Apollo space program, was launched on December 21, 1968, and became the first manned spacecraft to leave Earth orbit, reach the Earth's Moon, orbit it and return safely to Earth.
num_concepts_matched: 4
min_distance:         0.8285278
avg_distance:         1.0357224345207214

Row 3:
──────
title:                Lunar Orbiter 1
text:                 The Lunar Orbiter 1 robotic (unmanned) spacecraft, part of the Lunar Orbiter Program, was the first American spacecraft to orbit the Moon.  It was designed primarily to photograph smooth areas of the lunar surface for selection and verification of safe landing sites for the Surveyor and Apollo missions. It was also equipped to collect selenodetic, radiation intensity, and micrometeoroid impact data.The spacecraft was placed in an Earth parking orbit on August 10, 1966 at 19:31 (UTC).
num_concepts_matched: 4
min_distance:         0.94581836
avg_distance:         1.0584313124418259

Row 4:
──────
title:                Apollo (spacecraft)
text:                 The Apollo spacecraft was composed of three parts designed to accomplish the American Apollo program's goal of landing astronauts on the Moon by the end of the 1960s and returning them safely to Earth.  The expendable (single-use) spacecraft consisted of a combined Command/Service Module (CSM) and a Lunar Module (LM).
num_concepts_matched: 4
min_distance:         0.9643517
avg_distance:         1.0367188602685928

Row 5:
──────
title:                Surveyor 1
text:                 Surveyor 1 was the first lunar soft-lander in the unmanned  Surveyor program of the National Aeronautics and Space Administration (NASA, United States). This lunar soft-lander gathered data about the lunar surface that would be needed for the manned Apollo Moon landings that began in 1969.
num_concepts_matched: 4
min_distance:         0.9738264
avg_distance:         1.0988530814647675

Row 6:
──────
title:                Spaceflight
text:                 Spaceflight (also written space flight) is ballistic flight into or through outer space. Spaceflight can occur with spacecraft with or without humans on board. Examples of human spaceflight include the Russian Soyuz program, the U.S. Space shuttle program, as well as the ongoing International Space Station. Examples of unmanned spaceflight include space probes that leave Earth orbit, as well as satellites in orbit around Earth, such as communications satellites.
num_concepts_matched: 4
min_distance:         0.9831049
avg_distance:         1.060678943991661

Row 7:
──────
title:                Skylab
text:                 Skylab was a space station launched and operated by NASA and was the United States' first space station. Skylab orbited the Earth from 1973 to 1979, and included a workshop, a solar observatory, and other systems. It was launched unmanned by a modified Saturn V rocket, with a weight of 169,950 pounds (77 t).  Three manned missions to the station, conducted between 1973 and 1974 using the Apollo Command/Service Module (CSM) atop the smaller Saturn IB, each delivered a three-astronaut crew.
num_concepts_matched: 4
min_distance:         0.99155205
avg_distance:         1.0769911855459213

Row 8:
──────
title:                Orbital spaceflight
text:                 An orbital spaceflight (or orbital flight) is a spaceflight in which a spacecraft is placed on a trajectory where it could remain in space for at least one orbit. To do this around the Earth, it must be on a free trajectory which has an altitude at perigee (altitude at closest approach) above 100 kilometers (62 mi) (this is, by at least one convention, the boundary of space).  To remain in orbit at this altitude requires an orbital speed of ~7.8 km/s.
num_concepts_matched: 4
min_distance:         1.0075209
avg_distance:         1.085978478193283

Row 9:
───────
title:                Dragon (spacecraft)
text:                 Dragon is a partially reusable spacecraft developed by SpaceX, an American private space transportation company based in Hawthorne, California. Dragon is launched into space by the SpaceX Falcon 9 two-stage-to-orbit launch vehicle, and SpaceX is developing a crewed version called the Dragon V2.During its maiden flight in December 2010, Dragon became the first commercially built and operated spacecraft to be recovered successfully from orbit.
num_concepts_matched: 4
min_distance:         1.0222818
avg_distance:         1.0942841172218323

Row 10:
───────
title:                Space capsule
text:                 A space capsule is an often manned spacecraft which has a simple shape for the main section, without any wings or other features to create lift during atmospheric reentry.Capsules have been used in most of the manned space programs to date, including the world's first manned spacecraft Vostok and Mercury, as well as in later Soviet Voskhod, Soyuz, Zond/L1, L3, TKS, US Gemini, Apollo Command Module, Chinese Shenzhou and US, Russian and Indian manned spacecraft currently being developed.
num_concepts_matched: 4
min_distance:         1.0262821
avg_distance:         1.0882147550582886

総当たり検索で実行すると、完璧な結果(Apollo、Lunar Orbiter、Surveyor など)が得られます。
しかし、リソース消費量は相当なものです。

10 rows in set. Elapsed: 1.157 sec. Processed 10.00 million rows, 32.76 GB (8.64 million rows/s., 28.32 GB/s.)
Peak memory usage: 6.05 GiB.

これは厳密に制御されたベンチマークではなく、個人のマシンでクエリを実行した結果にすぎません。では、同じクエリを精度 5(符号 1 ビット、指数部 4 ビット、仮数部なし)の QBit で試してみましょう。クエリは Pastila にあります。

Row 1:
──────
title:                Apollo 8
text:                 Apollo 8, the second human spaceflight mission in the United States Apollo space program, was launched on December 21, 1968, and became the first manned spacecraft to leave Earth orbit, reach the Earth's Moon, orbit it and return safely to Earth.
num_concepts_matched: 4
min_distance:         0.9924246668815613
avg_distance:         0.9929515272378922

Row 2:
──────
title:                Apollo program
text:                 The Apollo program, also known as Project Apollo, was the third United States human spaceflight program carried out by the National Aeronautics and Space Administration (NASA), which accomplished landing the first humans on the Moon from 1969 to 1972. First conceived during Dwight D. Eisenhower's administration as a three-man spacecraft to follow the one-man Project Mercury which put the first Americans in space, Apollo was later dedicated to President John F.
num_concepts_matched: 4
min_distance:         0.9924481511116028
avg_distance:         0.9929344654083252

Row 3:
──────
title:                Apollo 5
text:                 Apollo 5 was the first unmanned flight of the Apollo Lunar Module (LM), which would later carry astronauts to the lunar surface. It lifted off on January 22, 1968, with a Saturn IB rocket on an Earth-orbital flight.
num_concepts_matched: 4
min_distance:         0.9925317764282227
avg_distance:         0.9930042922496796

Row 4:
──────
title:                Apollo (spacecraft)
text:                 The Apollo spacecraft was composed of three parts designed to accomplish the American Apollo program's goal of landing astronauts on the Moon by the end of the 1960s and returning them safely to Earth.  The expendable (single-use) spacecraft consisted of a combined Command/Service Module (CSM) and a Lunar Module (LM).
num_concepts_matched: 4
min_distance:         0.9926576018333435
avg_distance:         0.9928816854953766

Row 5:
──────
title:                Lunar Orbiter 1
text:                 The Lunar Orbiter 1 robotic (unmanned) spacecraft, part of the Lunar Orbiter Program, was the first American spacecraft to orbit the Moon.  It was designed primarily to photograph smooth areas of the lunar surface for selection and verification of safe landing sites for the Surveyor and Apollo missions. It was also equipped to collect selenodetic, radiation intensity, and micrometeoroid impact data.The spacecraft was placed in an Earth parking orbit on August 10, 1966 at 19:31 (UTC).
num_concepts_matched: 4
min_distance:         0.9926905632019043
avg_distance:         0.9929626882076263

Row 6:
──────
title:                Spaceflight
text:                 Spaceflight (also written space flight) is ballistic flight into or through outer space. Spaceflight can occur with spacecraft with or without humans on board. Examples of human spaceflight include the Russian Soyuz program, the U.S. Space shuttle program, as well as the ongoing International Space Station. Examples of unmanned spaceflight include space probes that leave Earth orbit, as well as satellites in orbit around Earth, such as communications satellites.
num_concepts_matched: 4
min_distance:         0.9927355647087097
avg_distance:         0.992923766374588

Row 7:
──────
title:                Surveyor 1
text:                 Surveyor 1 was the first lunar soft-lander in the unmanned  Surveyor program of the National Aeronautics and Space Administration (NASA, United States). This lunar soft-lander gathered data about the lunar surface that would be needed for the manned Apollo Moon landings that began in 1969.
num_concepts_matched: 4
min_distance:         0.9927787184715271
avg_distance:         0.9931300282478333

Row 8:
──────
title:                Orbital spaceflight
text:                 An orbital spaceflight (or orbital flight) is a spaceflight in which a spacecraft is placed on a trajectory where it could remain in space for at least one orbit. To do this around the Earth, it must be on a free trajectory which has an altitude at perigee (altitude at closest approach) above 100 kilometers (62 mi) (this is, by at least one convention, the boundary of space).  To remain in orbit at this altitude requires an orbital speed of ~7.8 km/s.
num_concepts_matched: 4
min_distance:         0.9927811026573181
avg_distance:         0.9929587244987488

Row 9:
───────
title:                DSE-Alpha
text:                 Deep Space Expedition Alpha (DSE-Alpha), is the name given to the mission proposed in 2005 to take the first space tourists to fly around the Moon. The mission is organized by Space Adventures Ltd., a commercial spaceflight company. The plans involve a modified Soyuz capsule docking with a booster rocket in Earth orbit which then sends the spacecraft on a free return circumlunar trajectory that circles around the Moon once.
num_concepts_matched: 4
min_distance:         0.9928749799728394
avg_distance:         0.9931814968585968

Row 10:
───────
title:                Luna programme
text:                 The Luna programme (from the Russian word Луна "Luna" meaning "Moon"), occasionally called Lunik or Lunnik by western media, was a series of robotic spacecraft missions sent to the Moon by the Soviet Union between 1959 and 1976. Fifteen were successful, each designed as either an orbiter or lander, and accomplished many firsts in space exploration.
num_concepts_matched: 4
min_distance:         0.9929065704345703
avg_distance:         0.9930566549301147

10 rows in set. Elapsed: 0.271 sec. Processed 8.46 million rows, 4.54 GB (31.19 million rows/s., 16.75 GB/s.)
Peak memory usage: 739.82 MiB.

結果はどうでしょうか?単に良いだけでなく、驚くほど良好です。仮数部を完全に削ぎ落とし、指数部も半分にした浮動小数点数が、依然として意味のある情報を保持しているというのは直感に反するかもしれません。QBit の背景にある重要な洞察は、重要度の低いビット、すなわちベクトルの全体的な向きにわずかしか寄与しないビットを無視しても、ベクトル検索は十分に機能するということです。

まとめ

ClickHouse は、ベクトル検索の距離計算に使用する浮動小数点数のビット数を制御できる新しいデータ型 QBit を構築しました。これにより、事前に決定を下すことなく、実行時に精度と速度のトレードオフを調整できるようになります。

実際には、これによって極めて高い精度を維持しながら、ベクトル検索クエリの I/O と計算時間の両方を削減できます。そして見てきたとおり、わずか 5 ビットでも月へ行くには十分です 🚀


この記事をシェア

  • Y Combinator icon
  • X icon
  • Bluesky icon
  • Facebook icon
  • LinkedIn icon

Subscribe to our newsletter

Stay informed on feature releases, product roadmap, support, and cloud offerings!

Aditya Chidurala, José Muñoz and Alex Francoeur · Sep 16, 2026
Amy Chen and Jan Mensch · Sep 15, 2026

Follow us

XBlueskySlackGithubTelegramMeetupRSS