ベクトル検索は、ベクトル表現に基づいてデータセット内の類似ベクトルやデータポイントを検索する方法です。Pinecone、Milvus、Qdrant、Weaviateなどの専用のベクトルデータベースとは異なり、MyScaleDBはオープンソースのSQL互換データベースであるClickHouseをベースにしています。
Structured Query Language(SQL)は、リレーショナルデータベースの管理に効果的なツールです。MyScaleDBは、SQLとベクトルのパワーを組み合わせて、複雑なAI関連の問いに取り組むための強力な手法を提供します。ユーザーは、構造化データとベクトル埋め込み(データ)に対して従来のSQLクエリとベクトルクエリを実行し、複雑なクエリを処理し、高次元データを統一的かつ効率的に分析することができます。
このブログでは、まず最も人気のある高度なSQLテクニックについて説明します。次に、MyScaleDBが複雑なSQLクエリをベクトル検索と結合して単一のクエリで実行し、ClickHouseと共にクエリの実行を最適化し、データをより迅速かつ効率的に取得する方法を例示します。
# 複雑なクエリのための高度なSQLテクニック
シンプルなSQLクエリは、通常、1つのテーブルからデータを取得する単純なコマンドです。複雑なSQLクエリは、複数のテーブルからデータを取得し、複数の条件で結果セットを制限することで、標準的な要求を超えます。
複雑なクエリには、次のような特徴があります:
- 共通テーブル式(CTE)
- サブクエリ
- 多くのテーブルを結合し、異なる結合タイプを使用する
# 共通テーブル式(CTE)
共通テーブル式(CTE)は、メインクエリ内のサブクエリに与える名前です。これを行う主な理由は、クエリを簡素化して読みやすくし、デバッグしやすくするためです。パフォーマンスの向上にも寄与することがありますが、主に読みやすさと簡素化に関わります。
特定の製品を購入した顧客の平均年齢を求めたい場合を考えてみましょう。顧客の名前、年齢、および購入した製品の情報を含む顧客データのテーブルがあるとします。
以下は、CTEを使用してこの計算を実行する例です:
WITH product_customers AS (
SELECT name, age
FROM customer_data
WHERE product = 'widget'
)
SELECT AVG(age) AS avg_age
FROM product_customers;
このクエリでは、CTEという一時的な名前付き結果セット(サブクエリ)を使用しています。CTEの名前は「product_customers」です。これは、「customer_data」テーブルから「widget」という製品を購入した顧客の名前と年齢の列を取得する「SELECT」ステートメントを使用して作成されます。
サブクエリをクエリの先頭に移動し、名前を付けることで、クエリの動作が理解しやすくなります。サブクエリがサンプル埋め込みベクトルを選択する場合は、「target_vector_embed」といった名前を付けることができます。メインクエリでこれを参照すると、この名前が表示され、何を指しているのかがわかります。
また、長いクエリで同じロジックを複数の場所で必要とする場合にも役立ちます。クエリの先頭で定義し、メインクエリ全体で複数回参照することができます。
したがって、サブクエリがある場合は、CTEを使用してクエリの読みやすさを向上させることを検討してください。
# サブクエリ
サブクエリは、別のクエリ内に埋め込まれた単純なSQLコマンドです。クエリをネストすることで、結果セットに含まれるデータに対してより大きな制限を設定することができます。
サブクエリは、クエリ内のいくつかの場所で使用することができますが、最も簡単なのは「FROM」ステートメントから始めることです。基本的なサブクエリの例を示します:
SELECT sub.*
FROM (
SELECT *
FROM table
WHERE conditions
) sub
WHERE sub.column_1 = 'MyScaleDB';
上記のクエリを実行する際に何が起こるかを見てみましょう:
まず、データベースは「内部クエリ」(括弧内の部分)を実行します。これを独立して実行すると、他のクエリと同様に結果セットが生成されます。内部クエリが実行された後、外部クエリが実行され、内部クエリの結果を基にしてテーブルが作成されます。
サブクエリには名前が必要であり、通常のテーブルにエイリアスを追加する方法と同じように、括弧の後に追加されます。このクエリでは、名前「sub」を使用しています。
# 条件付きロジックでのサブクエリの使用
サブクエリは、条件付きロジック(WHERE
、JOIN
/ON
、またはCASE
と組み合わせて)で使用することができます。次のクエリは、データセット内の指定されたエントリと同じ日付のエントリをすべて返します:
SELECT *
FROM table
WHERE Date = (SELECT Date
FROM table
WHERE id='00001');
このクエリは、サブクエリの結果が1つのセルであるため動作します。ほとんどの条件付きロジックは、1つのセルの結果を含むサブクエリで動作します。ただし、IN
は、内部クエリに複数の結果が含まれる場合にのみ動作する条件付きロジックのタイプです:
SELECT *
FROM table
WHERE Date IN (SELECT Date
FROM table
ORDER BY Date
LIMIT 5);
条件付きステートメント内でサブクエリを記述する際には、エイリアスを含めないように注意してください。これは、サブクエリがテーブルではなく個々の値(またはIN
句の場合は値のセット)として扱われるためです。
# テーブルの結合
結合は、各テーブルに共通の値を使用して、1つまたは複数のテーブルから列を結合して新しいテーブルを作成します。結合の種類は次のとおりです:
INNER JOIN
:一致するレコードのみが返されます。LEFT JOIN
:左側のテーブルのすべてのレコードと右側のテーブルの一致するレコードが返されます。RIGHT JOIN
:右側のテーブルのすべてのレコードと左側のテーブルの一致するレコードが返されます。FULL JOIN
:左側または右側のテーブルのいずれかに一致するレコードがある場合、両方のテーブルのすべてのレコードが返されます。CROSS JOIN
:テーブル全体の直積を生成します。結合キーが指定されていないため、すべての組み合わせが生成されます。
# MyScaleDBでの複雑なSQLとベクトルクエリの使用
SQLベクトルデータベースであるMyScaleDBには、複雑なSQLとベクトルクエリをサポートするいくつかの機能があります。MyScaleDBの複雑なクエリの機能を示すいくつかの例を見てみましょう。
# 共通テーブル式(CTE)
MyScaleDBはCTEをサポートし、WITH
句で定義されたコードをSELECT
クエリの残りの部分に置き換えます。名前付きサブクエリは、現在のクエリと子クエリのコンテキストのどこでもテーブルオブジェクトが許可される場所に含めることができます。
ベクトル検索は、データをベクトルとして表現する検索方法です。画像検索、ビデオ検索、テキスト検索などのアプリケーションでよく使用されます。MyScaleDBでは、distance()
関数を使用してベクトル検索を実行します。指定されたベクトルと指定された列内のすべてのベクトルデータとの距離を計算し、トップの候補を返します。
場合によっては、指定されたベクトルが別のテーブルから取得される場合や、指定されたベクトルの次元が大きく、表現が不便な場合には、CTEやサブクエリを使用することができます。
例えば、photo
という名前のベクトルテーブルがあり、写真ライブラリの画像に関連するメタデータ情報をid
、photo_id
、photo_embed
の列で保存しているとします。
次の例では、CTEで選択結果をターゲットベクトルとして扱い、ベクトル検索を実行しています:
WITH target_photo_embed AS (
SELECT photo_embed
FROM photos
LIMIT 1)
SELECT id, photo_id, distance(photo_embed, target_photo_embed) as dist
FROM photos
ORDER BY dist
LIMIT 10;
# 結合とサブクエリ
結合のサポートは限定的であり、回避策としてサブクエリを使用することをお勧めします。MyScaleDBでは、ベクトル検索はベクトル列を持つテーブル上のベクトルインデックスに基づいています。distance()
関数はSELECT
句に表示されますが、その値は結合後ではなく、テーブル上のベクトル検索時に計算されます。結合結果は期待される結果とは異なる場合があります。
以下は、可能な回避策です:
ベクトルテーブルを利用したサブクエリ内で
distance()...WHERE...ORDER BY...LIMIT
クエリパターンを使用し、ベクトルテーブル上で期待される結果を得ることができます。サブクエリを
WHERE
句で使用して結合を書き換えることもできます。
例えば、別のテーブルphoto_meta
があり、写真ライブラリの画像に関する情報をphoto_id
、photo_author
、year
、title
の列で保存しているとします。次の例では、画像のコレクションから2023年に撮影された関連する写真を取得しています:
SELECT t1.photo_id, distance(t1.photo_embed,[0.0269, 0.0316,...]) as dist
FROM photos t1
JOIN photo_meta t2 ON t1.photo_id = t2.photo_id
WHERE t2.year = 2023
ORDER BY dist
LIMIT 5;
上記のクエリを実行すると、次のような結果が得られます:
まず、MyScaleDBはテーブルphotos
上でベクトル検索を実行し、トップ5の関連レコードの必要な列photo_id
とdistance()
関数の値を取得します:
SELECT photo_id, distance(photo_embed,[0.0269, 0.0316,...]) as dist
FROM photos
ORDER BY dist
LIMIT 5;
次に、ベクトルテーブルの結果を基にしてjoin
が実行されます:
SELECT t1.photo_id, t1.dist
FROM (<<ベクトルテーブルの結果がここに入る>>)t1
JOIN photo_meta t2 ON t1.photo_id = t2.photo_id
WHERE t2.year = 2023;
ベクトル検索は写真が撮影された年を考慮しないため、結果は正しくない場合があります。正しい結果を得るためには、サブクエリを使用して結合クエリを書き換える必要があります:
SELECT t1.photo_id, t1.dist
FROM (
SELECT photo_id, distance(photo_embed,[0.0269, 0.0316,...]) as dist
FROM photos
WHERE photo_id IN (
SELECT t1.photo_id
FROM photos t1 JOIN photo_meta t2 ON t1.photo_id = t2.photo_id
WHERE t2.year = 2023)
ORDER BY dist
LIMIT 5
) t1
ORDER BY dist
LIMIT 5;
# データ分析の改善
CTE、サブクエリ、結合などの高度なSQLテクニックを使用すると、より正確かつ効率的に複雑なデータ分析や操作を行うことができます。MyScaleDBは、SQLとベクトルのパワーを組み合わせて、複雑なAI関連の問いに取り組むための強力な手法を提供します。MyScaleDBを使用すると、構造化データとベクトルデータ上で従来のSQLクエリとベクトルクエリを効率的に実行し、複雑なクエリに対応し、高次元データを統一的かつ効率的に分析することができます。
詳細については、X(Twitter) (opens new window)でフォローするか、Discord (opens new window)コミュニティに参加してください。一緒にデータとAIの未来を築きましょう!