Inverted File Flatベクトル索引のパーティション化スキーム

Inverted File Flatベクトル索引は、パーティション表のグローバル索引とローカル索引の両方をサポートします。デフォルトでは、IVF索引は重心によってグローバルにパーティション化されます。

グローバルIVF索引は、次の2つの表で構成されます:

  • VECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROIDSと呼ばれるもの。識別された重心ベクトルおよび関連するIDのリストが含まれています。

  • VECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROID_PARTITIONSと呼ばれるもの。重心IDでリスト・パーティション化されています。各パーティションには、そのパーティションの対応する重心IDと密接に関連する(クラスタ)実表のベクトルが含まれています。

次の図にこれを示します。

この構造は、まず問合せベクトルに最も近い重心を識別し、次に対応する重心IDを使用して不要なパーティションを除外することによって、索引の検索を高速化するために使用されます。

ただし、実表が一部のリレーショナル・データでパーティション化されており、問合せが実表のパーティション・キーでフィルタ処理されている場合、グローバルIVF索引は実表のパーティション・キーから完全に独立しているため、最適ではありません。たとえば、ベクトル化された写真に似たカリフォルニア州の上位10軒の家を検索する場合、写真自体はおそらくカリフォルニア州とは無関係です。問合せでは、実表が州別にパーティション化されているため、カリフォルニアに対応するパーティションのみを検索できることがメリットとなりますが、その問合せではカリフォルニアにない可能性がある画像も確認する必要があります。

このようなタイプの問合せをさらに高速化するには、ローカルIVF索引を作成できます。索引のローカルという用語は、実表のパーティションまたはサブパーティションと索引のパーティションの間の1対1の関係を指します。ベクトル・プールが有効な場合、IVF索引を持つ実表に対するローカルIVF索引の作成およびDML操作が高速化される可能性があります。ベクトル・プールは、SGAに格納されている新しいメモリー領域です。ベクトル・プールの詳細は、トピック「ベクトル・プールのサイズ設定」を参照してください。

これを次の図に示します。実表には3つのパーティションがあります。作成されたローカルIVF索引は、次の2つの内部表で構成されます:

  • 1つ目はVECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROIDSと呼ばれ、実表のパーティションIDによってリスト・パーティション化されるため、実表と等価パーティション化されます。各パーティションには、対応する識別された重心ベクトルおよび関連するIDのリストが含まれています。

  • 2つ目はVECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROID_PARTITIONSと呼ばれ、実表のパーティションIDによってリスト・パーティション化され、重心IDによってリスト・サブパーティション化されます。この表も実表と等価パーティション化されており、各サブパーティションには、そのサブパーティションの対応する重心IDと密接に関連している(クラスタ)実表ベクトルが含まれています。

ベクトル化された写真に似ているカリフォルニア州の上位10軒の家を検索する最初の例に戻ります。問合せでは、実表とCentroids表(カリフォルニア)の両方が州別にパーティション化されているため、それらをパーティション・プルーニングできることがメリットとなります。さらに、最も近い重心がそのパーティションで識別されると、問合せでは、他の重心サブパーティションをスキャンせずに、Centroidパーティション表の対応する重心クラスタ・サブパーティションをスキャンするだけで済みます。

もう1つの可能性は、実表をコンポジット・パーティション化することです。そのケースに対応するグラフィック表現を次に示します。Centroids表は、実表のサブパーティションに従ってリスト・パーティション化されます。Centroids表の各パーティションには、対応する実表サブパーティションにあるすべての重心ベクトルが含まれています。Centroidパーティション表は、実表のサブパーティションIDによってリスト・パーティション化され、さらに重心IDによってサブパーティション化されます。

ノート:

ローカルIVF索引は、パーティション化された実表に対してのみ作成できます。

ローカルIVF索引は、通常のローカル索引で使用されるすべてのシステム・カタログ表およびビューを継承します。vecsys.vector$index表のフラグ(idx_spare2)は、索引がローカル・ベクトル索引またはグローバル・ベクトル索引のいずれであるかを示します。

ローカルIVF索引を使用すると、次のような利点があります:

  • 簡易なパーティション管理操作(PMOP):

    たとえば、表パーティションの削除には、対応する索引パーティションの削除のみが含まれます。

  • 柔軟な索引付けスキーム:

    たとえば、特定の索引パーティションにUNUSABLEのマークを付けて、部分索引付けによる特定の表パーティションの索引付けを回避します。

ノート:

ユーザー問合せで、パーティション・プルーニングの利点を活用して、ローカルIVF索引の可能性を最大限に活用するには、問合せが次の条件を満たしている必要があります:

  • 実表は、単一の列によって[サブ]パーティション化されます。

  • 条件は[sub]partitition_key CMP定数の形式です。ここで、CMPは次のいずれかです:

    =, >, >=, <, <=, IN

  • partition_key条件は、他の非パーティション条件とANDされます。

パーティション管理操作(PMOP)およびIVF索引

ローカルIVF索引に対して使用可能なPMOPと制限事項を次に示します:

  • ALTER TABLE TRUNCATE [sub]partition <partition_name>

    ALTER TABLE DROP [sub]partition <partition_name>

    これらの操作は、すべてのパーティション・スキーム(RANGEHASHLIST)でサポートされています。ただし、対応するすべてのIVF索引パーティションは、操作後にUNUSABLEとしてマークされます。

  • ALTER TABLE ADD [sub]partition <partition_name>

    実表がRANGEまたはLISTによってパーティション化されている場合、この操作はサポートされます。ただし、対応するすべてのIVF索引は、操作後にUNUSABLEとしてマークされます。表がHASHによってパーティション化されていて、実表にローカルIVF索引がある場合、この操作は失敗します。

  • ALTER TABLE SPLIT/MERGE/MOVE/EXCHANGE/COALESCEなど、実表に対する他のすべてのPMOP操作はサポートされません。

    変更対象の表にローカルIVF索引がある場合、これらのALTER TABLE文は失敗します。

  • ローカルIVF索引に対するALTER INDEXはサポートされていません。

ローカルIVFベクトル索引の試験使用

次のコードを使用して、LOCAL IVF索引の試験使用を開始できます。これはシナリオではなく、独自のテスト・シナリオの開始に役立つ一連のSQLコマンドです。

  1. 選択したパーティション・スキームを使用して、実表を作成します:

    RANGEパーティション化:

    DROP TABLE sales_data PURGE;
    
    
    CREATE TABLE sales_data
    (
        product_id NUMBER,
        customer_id NUMBER,
        sale_date DATE,
        amount_sold NUMBER,
        vec vector(8),
        region VARCHAR2(20)
    )
    PARTITION BY RANGE (product_id)
    (
        PARTITION sales_1 VALUES LESS THAN (100),
        PARTITION sales_2 VALUES LESS THAN (200),
        PARTITION sales_3 VALUES LESS THAN (300),
        PARTITION sales_4 VALUES LESS THAN (400),
        PARTITION sales_5 VALUES LESS THAN (500),
        PARTITION sales_6 VALUES LESS THAN (600),
        PARTITION sales_7 VALUES LESS THAN (700),
        PARTITION sales_8 VALUES LESS THAN (800),
        PARTITION sales_9 VALUES LESS THAN (900),
        PARTITION sales_10 VALUES LESS THAN (1000),
        PARTITION sales_default VALUES LESS THAN (1000000)
    );

    LISTパーティション化:

    DROP TABLE sales_data PURGE;
    
    CREATE TABLE sales_data
    (
        product_id   NUMBER,
        customer_id  NUMBER,
        sale_date    DATE,
        amount_sold  NUMBER,
        vec          VECTOR(8),
        region       VARCHAR2(20)
    )
    PARTITION BY LIST (region)
    (
        PARTITION RegionA_Partition VALUES ('RegionA1','RegionA2','RegionA3','RegionA4','RegionA5'),
        PARTITION RegionB_Partition VALUES ('RegionB1','RegionB2','RegionB3','RegionB4','RegionB5'),
        PARTITION RegionC_Partition VALUES ('RegionC1','RegionC2','RegionC3','RegionC4','RegionC5'),
        PARTITION RegionD_Partition VALUES ('RegionD1','RegionD2','RegionD3','RegionD4','RegionD5'),
        PARTITION RegionE_Partition VALUES ('RegionE1','RegionE2','RegionE3','RegionE4','RegionE5'),
        PARTITION RegionF_Partition VALUES ('RegionF1','RegionF2','RegionF3','RegionF4','RegionF5'),
        PARTITION RegionG_Partition VALUES ('RegionG1','RegionG2','RegionG3','RegionG4','RegionG5'),
        PARTITION RegionH_Partition VALUES ('RegionH1','RegionH2','RegionH3','RegionH4','RegionH5'),
        PARTITION RegionI_Partition VALUES ('RegionI1','RegionI2','RegionI3','RegionI4','RegionI5'),
        PARTITION RegionJ_Partition VALUES ('RegionJ1','RegionJ2','RegionJ3','RegionJ4','RegionJ5'),
        PARTITION Other_Region_Partition VALUES (DEFAULT)
    );

    HASHパーティション化:

    DROP TABLE sales_data PURGE;
    
    CREATE TABLE sales_data
    (
        product_id   NUMBER,
        customer_id  NUMBER,
        sale_date    DATE,
        amount_sold  NUMBER,
        vec          VECTOR(8),
        region       VARCHAR2(20)
    )
    PARTITION BY HASH (product_id)
    PARTITIONS 10;
  2. 次のプロシージャを使用して、SALES_DATA表にデータをランダムに挿入します:
    CREATE OR REPLACE PROCEDURE insert_sales_data(numRows IN INTEGER, maxProductId IN INTEGER) AS
      TYPE vec_array IS VARRAY(8) OF NUMBER;
    BEGIN
      DBMS_RANDOM.INITIALIZE(100);
        FOR i IN 1..numRows LOOP
          INSERT INTO sales_data (product_id, customer_id, sale_date, amount_sold, vec, region)
            VALUES (round(DBMS_RANDOM.VALUE(1, MaxProductId)),    -- Random product_id between 1 and 1000
                    round(DBMS_RANDOM.VALUE(1, 10000)),   -- Random customer_id between 1 and 10000
                    (DATE '2024-05-10' - DBMS_RANDOM.VALUE(1, 1460)), -- Random sale_date within the last 4 years
                    DBMS_RANDOM.VALUE(10, 10000),  -- Random amount_sold between 10 and 1000
                    '[' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) || ',' ||
                        to_char(DBMS_RANDOM.VALUE(0, 1000)) ||
                    ']',
                    CASE MOD(i, 10)
                        WHEN 0 THEN 'RegionA' || MOD(i,5)
                        WHEN 1 THEN 'RegionB' || MOD(i,5)
                        WHEN 2 THEN 'RegionC' || MOD(i,5)
                        WHEN 3 THEN 'RegionD' || MOD(i,5)
                        WHEN 4 THEN 'RegionE' || MOD(i,5)
                        WHEN 5 THEN 'RegionF' || MOD(i,5)
                        WHEN 6 THEN 'RegionG' || MOD(i,5)
                        WHEN 7 THEN 'RegionH' || MOD(i,5)
                        WHEN 8 THEN 'RegionI' || MOD(i,5)
                        ELSE        'RegionJ' || MOD(i,5)
                    END);
    
            IF MOD(i, 10000) = 0 THEN
                COMMIT;
            END IF;
        END LOOP;
        COMMIT;
    END insert_sales_data;
    /
    
    EXEC insert_sales_data(20000, 501);
  3. SALES_DATA表のVEC列にLOCAL IVF索引を作成します:
    CREATE VECTOR INDEX vidxivf ON sales_data(vec) 
    ORGANIZATION NEIGHBOR PARTITIONS 
    WITH TARGET ACCURACY 95 
    DISTANCE EUCLIDEAN PARAMETERS(TYPE IVF, NEIGHBOR PARTITION 20) LOCAL;
  4. PMOPコマンドの実行前後にすべての索引パーティションの状態を確認します:
    SELECT INDEX_NAME, PARTITION_NAME, STATUS 
    FROM USER_IND_PARTITIONS 
    WHERE index_name LIKE upper('vidxivf') 
    ORDER BY 1, 2;
  5. 次のALTER TABLEコマンドをテストして、サポートされるものとサポートされないものを確認します:

    表がRANGEパーティションの場合:

    ALTER TABLE sales_data ADD PARTITION sales_1000000 VALUES LESS THAN (2000000);
    
    ALTER TABLE sales_data
    SPLIT PARTITION sales_2
    AT (150)
    INTO (
          PARTITION sales_21,
          PARTITION sales_22
    );
    
    ALTER TABLE sales_data DROP PARTITION sales_3;
    表がLISTパーティションの場合:
    ALTER TABLE sales_data 
    SPLIT PARTITION RegionE_Partition VALUES ('RegionE1', 'RegionE2', 'RegionE3') 
    INTO 
      ( PARTITION RegionE1_Partition,
        PARTITION RegionE2_Partition
      );
    
    ALTER TABLE sales_data DROP PARTITION RegionB_Partition;

    表がHASHパーティションの場合:

    ALTER TABLE sales_data ADD PARTITION;
    
    SELECT partition_name FROM user_tab_partitions WHERE table_name='SALES_DATA';
    
    ALTER TABLE sales_data COALESCE PARTITION;