すべてのプロダクト
Search
ドキュメントセンター

AnalyticDB:FLOAT2データ型を使用してベクトルストレージを圧縮する

最終更新日:Sep 24, 2024

このトピックでは、半精度浮動小数点形式 (FLOAT2) タイプの圧縮列と関連する操作について説明します。 従来のベクトル検索システムは、画像、オーディオファイル、およびテキストを、大量のストレージを消費する高次元浮動小数点配列に変換する。 ストレージ使用量を削減し、コストを削減するために、AnalyticDB for PostgreSQLはFLOAT2データ型を提供します。

FLOAT2データ型

FLOAT2は、2バイト (16ビット) を占有し、4バイト (32ビット) を占有するFLOAT4データを格納するバイナリ浮動小数点データ型である。 IEEE 754標準で定義されているbinary16形式は、次の形式レイアウトを持ちます。

  • 符号ビット: 1ビット。

  • 指数幅: 5ビット。

  • 重要な精度: 11ビット (明示的に格納された10) 。

フォーマットを次の図に示します。float2数据类型このフォーマットは、指数フィールドがすべてゼロで記憶されない限り、値1の暗黙のリードビットを有すると仮定される。 この場合、メモリフォーマットには10ビットの仮数部しか現れないが、合計精度は11ビットである。 IEEE 754規格では、10ビットの仮数部は、11ビットの仮数部精度 (log10(211) ≒ 3.311桁) を必要とする。

0 01111 0000000000 = 1
0 01111 0000000001 = 1 + 2-10 = 1.0009765625 (smallest number greater than 1)
1 10000 0000000000 = -2

0 11110 1111111111 = 65504 (max half precision)

0 00001 0000000000 = 2-14 ≈ 6.10352 × 10-5 (smallest positive normal number)
0 00000 1111111111 = 2-14 - 2-24 ≈ 6.09756 × 10-5 (greatest subnormal number)
0 00000 0000000001 = 2-24 ≈ 5.96046 × 10-8 (smallest positive subnormal number)

0 00000 0000000000 = 0
1 00000 0000000000 = -0

0 11111 0000000000 = infinity
1 11111 0000000000 = -infinity

0 01101 0101010101 = 0.333251953125 ≈ 1/3

デフォルトでは、仮数部のビット数が奇数であるため、1/3は同様の方法で倍精度を切り捨てます。

データをFLOAT2型とFLOAT4型の間で変換するには、システムはビットをシフトし、基数を15〜127に変換します。 たとえば、データをFLOAT2からFLOAT4に変換するには、システムは次の操作を実行します。

  1. 符号ビットを16ビット左にシフトする。

  2. 112を加算して基数を15から127に変換し、13ビット左にシフトして指数を右に揃えます。

  3. 13ビットだけ左にシフトすることによって、仮数部を左に整列させる。

説明

データをFLOAT4からFLOAT2に変換するために、逆の演算が実行される。

浮動小数点データ圧縮は、クエリおよび計算中に精度の損失を引き起こす。 ある程度の精度損失は許容されます。

FLOAT4データ型と比較して、FLOAT2データ型は4バイトのデータを2バイトに圧縮し、ディスク容量の半分を占めます。 ベクトル列の圧縮率は0.5です。

FLOAT2データとして保存される値は、-65519.99から65519.99の範囲でなければなりません。 値が65519より大きい場合、システムはInfinityを表示します。 値が-65519未満の場合、システムは-Infinityと表示します。 ベクトルは、ベクトル検索の前に0〜1の範囲に正規化する必要があります。 そうでなければ、計算されたベクトル距離は、FLOAT2値の範囲を超え、不正確になる。

FLOAT2とFLOAT4の間の変換は、パフォーマンスのオーバーヘッドを引き起こします。 2つの変換アルゴリズムを使用して、FLOAT2配列のデータ型を変換できます。

  • Cプログラムを使用して、配列内のFLOAT2要素を変換します。 一度に変換される要素は1つだけです。

  • Advanced Vector Extensions (AVX) およびStreaming SIMD Extensions 2 (SSE2) をサポートするハードウェアの場合は、ハードウェア固有のインターフェイスと関数を使用します。 4つのFLOAT2要素を同時に変換することができます。

クエリではインデックスなどのトラバースメソッドを使用するため、変換できるエントリは少数です。

FLOAT2データを格納するテーブルを作成する

FLOAT2は内部データ型です。 システムは、複数のデータ型および関連する演算子間の変換を管理する。 この場合、FLOAT2は、プリミティブデータ型として処理される。

構文:

CREATE TABLE [TABLE_NAME]
(  
    C1 INT,  
    C2 FLOAT2[],  
    C3 VARCHAR(20),  
    PRIMARY KEY(C1)
) DISTRIBUTED BY(C1);
説明

C2列は、FLOAT2ベクトルを格納する。

例:

FACE_TABLEという名前のテーブルを作成します。 FLOAT2ベクトルを格納する列としてC2列を指定します。

CREATE TABLE FACE_TABLE (  
    C1 INT PRIMARY KEY,  
    C2 FLOAT2[],  
    C3 VARCHAR(20)
) DISTRIBUTED BY (C1);

データの挿入

次のいずれかの方法を使用して、FLOAT2配列をテーブルに挿入できます。 FLOAT2配列を明示的に定義し、sql1で説明するようにテーブルに挿入できます。 FLOAT4配列を定義することもでき、システムはそれをFLOAT2配列に変換し、sql2およびsql3で説明されているように配列をテーブルに挿入します。

例:

FACE_TABLEテーブルに3つのエントリを挿入します。

sql1 = INSERT INTO FACE_TABLE (C1, C2, C3)
    VALUES (1, ARRAY[1.3, 2.4, 5.6]::FLOAT2[], 'name1');

sql2 = INSERT INTO FACE_TABLE (c1, c2, c3) 
    VALUES (2, ARRAY [3.4, 6.1, 7.6]::REAL[], 'name2');

sql3 = INSERT INTO FACE_TABLE (c1, c2, c3) 
    VALUES (3, ARRAY [9.5, 1.2, 0.6]::FLOAT4[],'name3');

クエリデータ

FLOAT2データは、クエリ中にデータ精度の損失をもたらします。 たとえば、挿入された値1.3は1.2998としてクエリされ、挿入された値5.6は5.60156としてクエリされます。 このレベルの精度損失は、ベクトル検索では無視することができる。

例:

SELECT * FROM FACE_TABLE; 
c1  | c2                        | c3 
----+---------------------------+-------
 1  | {1.2998,2.40039,5.60156}  | name1
 2  | {3.40039,6.10156,7.60156} | name2
 3  | {9.5,1.2002,0.600098}     | name3

FLOAT2テーブルのデータ圧縮

次のステートメントは、FLOAT4ベクトルを格納するテーブルと、FLOAT2ベクトルを格納するテーブルを作成します。 2つのテーブルのサイズを比較します。

--CREATE TABLE 
CREATE TABLE TAB1(A FLOAT4[]);
CREATE TABLE TAB2(A FLOAT2[]);

--INSERT DATA 
INSERT INTO TAB1 
SELECT GEN_RAND_F2_ARR (1, 1024) FROM GENERATE_SERIES (1,10000);
INSERT INTO TAB2 
SELECT GEN_RAND_F2_ARR (1, 1024) FROM GENERATE_SERIES (1,10000);

--QUERY SIZE
SELECT PG_SIZE_PRETTY (PG_RELATION_SIZE('tab1'));
 PG_SIZE_PRETTY 
----------------
 45 MB(1 row)

SELECT PG_SIZE_PRETTY (PG_RELATION_SIZE('tab2')); 
 PG_SIZE_PRETTY
----------------
 21 MB(1 row)

FLOAT2テーブルは21 MBのストレージを占有します。これは、FLOAT4テーブルが占有する45 MBのストレージの半分にすぎません。

FLOAT2データの圧縮と解凍のパフォーマンステスト

システムは、データを変換する2つの機能を提供する。 array_f16_to_f32関数はFLOAT2ベクトルをFLOAT4ベクトルに変換し、array_f32_to_f16関数はFLOAT4ベクトルをFLOAT2ベクトルに変換します。 テスト用の各ベクトルの長さは1,024次元であり、テストはAVXとSSE2をサポートするマシンで実行されます。

例:

--CREATE TABLE 
CREATE TABLE TAB1(A FLOAT4[]);
CREATE TABLE TAB2(A FLOAT2[]);

--INSERT TABLE
INSERT INTO TAB1 SELECT GEN_RAND_F2_ARR(1, 1024) FROM GENERATE_SERIES (1,10000);
INSERT INTO TAB2 SELECT GEN_RAND_F2_ARR(1, 1024) FROM GENERATE_SERIES (1,10000);

\TIMING
--query size
SELECT ARRAY_F32_TO_F16(a) FROM TAB1; 
    Time: 5998.832 ms (00:05.999)
SELECT ARRAY_F16_TO_F32(a) FROM TAB2;
    Time: 5507.388 ms (00:05.507) 

距離計算

このシステムは、FLOAT2データをFLOAT4データに変換して距離を計算するユークリッド距離計算方法を提供します。

例:

ユークリッド距離を計算します。

SELECT L2_DISTANCE(ARRAY[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]::FLOAT2[], 
    ARRAY[0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]::FLOAT2[]);

SELECT L2_DISTANCE(ARRAY[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]:: FLOAT4[], 
    ARRAY [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]:: FLOAT2[]);

SELECT L2_DISTANCE (ARRAY[1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0]:: FLOAT2[], 
    ARRAY [0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0]::FLOAT2[]);

ユースケース

セキュリティシステムは、捕捉された顔データを毎日スケジュールベースで顔テーブルに記憶し、顔画像に基づいて関連する監視データを取り出す。 次のセクションでは、ベクトル検索でFLOAT2データを使用する方法について説明します。

  1. 顔認識に関連するデータを格納するテーブルを作成します。

    CREATE TABLE FACE_TABLE (
      C1 INT PRIMARY KEY,
      C2 FLOAT2[],
      C3 VARCHAR(20)
    ) DISTRIBUTED BY(C1);
    説明
    • C1: 顔番号を格納する列。

    • C2: 顔ベクトルを格納する列。

    • C3: 顔の名前を格納する列。

  2. FACE_TABLEテーブルにベクトルインデックスを作成します。

    CREATE INDEX FACE_TABLE_IDX 
    ON FACE_TABLE 
    USING ANN(C2) WITH(dim=10);
  3. モニタリングデータをFACE_TABLEテーブルにインポートします。

    INSERT INTO FACE_TABLE (C1, C2, C3) 
    VALUES (1, ARRAY[1.3, 2.4, 5.6]::FLOAT2[], 'name1');
    
    INSERT INTO FACE_TABLE (c1, c2, c3) 
    VALUES (2, ARRAY[3.4, 6.1, 7.6]::REAL[], 'name2');
    
    INSERT INTO FACE_TABLE (c1, c2, c3) 
    VALUES (3, ARRAY[9.5, 1.2, 0.6]::FLOAT4[],'name3');
  4. 顔ベクトルに基づいてベクトル検索を実行します。

    SELECT * 
    FROM FACE_TABLE 
    ORDER BY C1 <-> ARRAY[2.81574,9.84361,8.07218]:: FLOAT2[] 
    LIMIT 10;
    説明

    ARRAY[2.81574,9.84361,8.07218]:: FLOAT2[] は、顔ベクトルを指定する。 システムは、基礎となるデータベースから関連情報を取り出す。