Benutzer-Werkzeuge

Webseiten-Werkzeuge


ki:oracle_vector_for_data_compare

Oracle Datenbank 23ai - Mit Vectoren in der Oracle Datenbank Daten vergleichen - Demo Applikation für die Suche nach Farben

Ansatz

Ein Vector ist ideal um Daten zu vergleichen und zu klassifizieren.

Auf komplexen Modellen ist das aber nicht immer einfach nachzuvollziehen.

Die Vektorisierung und das Vergleichen von Vektoren sind zwei komplett unterschiedliche Dinge, kann auch einfach ein eigener Vector Algorithmus erstellt werden.

Um hier ein besseres Verständnis für die Möglichkeiten der Vectoren in der Oracle Datenbank zu erlernen, wird hier eine einfache Demo Applikation zur Suche nach Farben zu implementiert.

Mit diese einfachen Vektor Mengen kann nun mit dem Taschenrechner nachrechnet werden um die Vector Distanzen (Ähnlichkeitsmaßstäbe) besser zu verstehen.

Der Case

Ein Anwender kann in einen APEX Color Picker eine Farbe wählen und nach allen zu dieser Farbe ähnlichen Farben suchen.

Zum Beispiel um Produkte wie Kleidung oder Autos nach Farben zu suchen.

Wie:

So soll in diesem kleinen Beispiel nach Auto Farben gesucht werden, Kunden sucht über einen Hex Color Picker eine Farbe, wie f20707 und in der Suche werden alle Fahrzeuge mit einer ähnlichen Farbe eines ähnlichen Types angezeigt in dem wir einen Farb / Typ Vector definieren.

Der Vector besteht z.B. aus [ Farbanteil R [0 .. bis 256] , Farbanteil G [0 .. bis 256], Farbanteil R [B .. bis 256], Hersteller [0 - x ], Fahrzeug Typ [ 1 … 10 ] ].

Hersteller und Fahrzeug Typ werden nach Ähnlichkeit in der Wertemenge sortiert, wie BMW 1, VW 2, Mercedes 3, Citrön 5 , Ferrari 80, Bently 999 usw.. Typen wie Stufenheck =1, Kombi 2, Transporter 10, Pickup 20, LKW 99, Kettenbagger 999, um hier wieder Ähnlichkeiten zu identifizieren.

Schon bei diesem einfachen Beispiel wird deutlich das die Definition des Vectors entscheidend auch für die später Ähnlichkeitssuche ist.

Model Bildung

Im ersten Schritt wird eine Farbe in einem Vector dargestellt.

Daten Darstellung - Variante RGB

In der Datenbank liegen die Farben im RGB Format vor und werden in einen Vector umgesetzt.

Der Vector wird im eine Spalte vom Datentyp Vector gespeichert.

Model:

[ 
   Farbanteil R [0 .. bis 256] 
,  Farbanteil G [0 .. bis 256]
,  Farbanteil R [0 .. bis 256]
]

Nun kann mit den verschieden Ähnlichkeitsmaß Methoden auf den Daten nach den passende Farben sortiert werden.

Nach dem ersten Vergleichstest fällt auf, das wir hier eine zu technische Darstellung von Farben verwenden, die technische Darstellung von RGB korreliert nicht ganz mit unseren Sehgewohnheiten.

Daten Darstellung - Variante HSV/HSB

Nach dem ersten Test hat sich das HSV/HSB (Farbton, Sättigung, Wert/Helligkeit) Farbformat als praktischer erwiesen als das RGB-Modell mit den drei unabhängige Kanäle (Rot, Grün, Blau).

Model:

 
[
  H (Hue): Farbton (0–360 Grad, ähnlich wie bei HSV).
, S (Saturation): Sättigung (0–100 %, 0 = Grau, 100 = volle Farbe).
, L (Lightness): Helligkeit (0–100 %, 0 = Schwarz, 50 = volle Farbe, 100 = Weiß).
]

Umsetzung

Die Element der Lösung:

  1. Tabelle für die Daten mit einer Vector Spalte
  2. PL/SQL Funktion um die vorliegenden RGB Werte in HSV zu konvertieren
  3. PL/SQL Routine um Test Daten zu erzeugen
  4. APEX APP um die Daten zu durchsuchen und die verschieden Ähnlichkeits-Maßstäbe zu testen
  5. Indexierung mit den beiden möglichen Index Typen
  6. Qualität der Index Suche gegenüber der der Full Scan Analyse auf der Tabelle

Bestimmt gibt es noch ganz andere Lösungen für das Thema, mit dem Demo lässt sich aber gut verständlich die Welt der Oracle Vectoren erkunden da sich bei so kleine Vectoren einiges mit dem Taschenrechner nachvollziehen lässt.


Eine Entwicklungsumgebung vorbereiten

User in der Datenbank anlegen

User mit entsprechenden Rollen für die weitern Test Cases anlegen als SYS im der PDB:

sqlplus sys@//10.10.10.118:1521/freepdb1 AS sysdba
 
CREATE USER GPI IDENTIFIED BY MYSecretPWD
DEFAULT TABLESPACE USERS
TEMPORARY TABLESPACE TEMP;
 
ALTER USER GPI QUOTA UNLIMITED ON USERS;
 
-- normal Developer rights
GRANT CONNECT TO GPI;
GRANT DB_DEVELOPER_ROLE TO GPI;
GRANT SELECT_CATALOG_ROLE TO GPI;
 
-- AI Features
GRANT CREATE MINING MODEL TO GPI;
-- data Exchange for MODEL and Test Data
GRANT READ ON DIRECTORY DATA_EXCHANGE TO GPI;
GRANT WRITE ON DIRECTORY DATA_EXCHANGE TO GPI;
 
-- Oracle Text Test Case
GRANT CTXAPP TO GPI;
 
-- Analyse Vector Index
GRANT SELECT ON VECSYS.VECTOR$INDEX$BUILD$ TO GPI;
GRANT SELECT ON VECSYS.VECTOR$INDEX TO GPI;
 
ALTER USER GPI DEFAULT ROLE CONNECT, DB_DEVELOPER_ROLE, SELECT_CATALOG_ROLE, CTXAPP;

Das Datenmodell für die Speicherung der Daten

Tabelle anlegen:

DROP SEQUENCE color_search_seq;
DROP TABLE color_search;
 
CREATE SEQUENCE color_search_seq;
 
CREATE TABLE color_search (
 
  ID         NUMBER(8)  NOT NULL CONSTRAINT COLOR_SEARCH_PK PRIMARY KEY
, RGB_COLOR  varchar2(6)
, COLOR_VECTOR VECTOR(3 , FLOAT32 , DENSE) 
 
);

Unser Vector kann aus aus 3 Elementen mit dem Datentyp FLOAT32 ( 32-bit floating-point ) bestehen und enthält keine leeren Elemente.

Hilfsroutine Routine um RGB in HSV zu wandeln

CREATE OR REPLACE FUNCTION rgb_to_hsv_vector(
    p_r IN NUMBER,
    p_g IN NUMBER,
    p_b IN NUMBER
) 
RETURN VECTOR 
 IS
    v_max_val NUMBER;
    v_min_val NUMBER;
    v_delta   NUMBER;
 
    v_h       NUMBER;
    v_s       NUMBER;
    v_v       NUMBER;
 
    V_r       NUMBER;
    V_g       NUMBER;
    V_b       NUMBER;    
 
    v_return  VECTOR;
    v_result_string VARCHAR2(64);
 
BEGIN
 
    -- Normalisiere RGB-Werte auf den Bereich [0, 1]
    v_r := p_r / 255.0;
    v_g := p_g / 255.0;
    v_b := p_b / 255.0;
 
    -- Berechne max, min und delta
    v_max_val := GREATEST(v_r, v_g, v_b);
    v_min_val := LEAST(v_r, v_g, v_b);
    v_delta := v_max_val - v_min_val;
 
    -- Berechne Hue (H)
    IF v_delta = 0 THEN
        v_h := 0;
    ELSIF v_max_val = v_r THEN
        v_h := 60 * (MOD( (v_g - v_b) / v_delta , 6));
    ELSIF v_max_val = v_g THEN
        v_h := 60 * (((v_b - v_r) / v_delta) + 2);
    ELSIF v_max_val = v_b THEN
        v_h := 60 * (((v_r - v_g) / v_delta) + 4);
    END IF;
 
    -- Berechne Saturation (S)
    IF v_max_val = 0 THEN
        v_s := 0;
    ELSE
        v_s := v_delta / v_max_val;
    END IF;
 
    -- Berechne Value (V)
    v_v := v_max_val;
 
    -- Gib das Ergebnis als Vector zurück
    v_result_string:='['||ABS(v_h)||','||ROUND(v_s*100,2)||','||ROUND(v_v*100,2)||']';
    DBMS_OUTPUT.put_line ('-- debug '||v_result_string);
 
    v_return:= TO_VECTOR(v_result_string);
 
    RETURN  v_return;    
END;
/

Test daten erzeugen

Testdaten Routine anlegen:

SET serveroutput ON
DROP PROCEDURE fillColorSearchTab;
CREATE OR REPLACE PROCEDURE fillColorSearchTab (p_num_records NUMBER)
IS
 
 v_r      PLS_INTEGER;
 v_g      PLS_INTEGER;
 v_b      PLS_INTEGER;
 
 v_cnt    PLS_INTEGER;
 
 v_color  VARCHAR2(256);
 v_vector VECTOR(3 , FLOAT32);
 
BEGIN
 
  v_cnt:=0;
 
  WHILE v_cnt < p_num_records
  LOOP
        -- erzeuge Zufallszahlen für die Farbkomponenten
        v_r:=FLOOR(DBMS_RANDOM.VALUE(0, 256));
        v_g:=FLOOR(DBMS_RANDOM.VALUE(0, 256));
        v_b:=FLOOR(DBMS_RANDOM.VALUE(0, 256));
        -- in RGB HEX Werte umwandlen
        -- so können wir später die Farbe direkt im Browser in einem Grid darstellen
        v_color:= LPAD(TRIM((LOWER(TO_CHAR(v_r, 'XX'))) ),2,'0')|| LPAD(TRIM(LOWER(TO_CHAR(v_g, 'XX'))),2,'0')||LPAD(TRIM(LOWER(TO_CHAR(v_b, 'XX'))),2,'0');
        -- RGB in HSV Vector wandeln
        v_vector:=rgb_to_hsv_vector(v_r,v_g,v_b);
 
       INSERT INTO color_search(ID, RGB_COLOR, COLOR_VECTOR)
         VALUES (
                   color_search_seq.NEXTVAL -- ID
                 , v_color                  -- RGB_COLOR
                 , v_vector                 -- COLOR_VECTOR
         );
 
       IF MOD(v_cnt,1000) = 0  THEN
         COMMIT;
       END IF;  
 
      v_cnt:=v_cnt+1;
 
    END LOOP;
 
    COMMIT;
 
END fillColorSearchTab;
/

Testdaten erzeugen:

truncate TABLE color_search;
 
BEGIN
   fillColorSearchTab(50);
END;
/

Vector Abfragen

Bei der Abfrage auf Vectoren geht es immer um das Ähnlichkeitsmaß:

COLUMN v_L1_DISTANCE       format 999G990D0999 heading "Vector Distance|L1 or MANHATTAN"
COLUMN v_L2_DISTANCE       format 999G990D0999 heading "Vector Distance|L2 or EUCLIDEAN"
COLUMN v_COSINE_DISTANCE   format 999G990D0999 heading "Vector Distance|COSINE"
COLUMN v_INNER_PRODUCT     format 999G990D0999 heading "Vector Distance|INNER_PRODUCT"
COLUMN v_HAMMING_DISTANCE  format 999G990D0999 heading "Vector Distance|HAMMING"
COLUMN v_JACCARD_DISTANCE  format 999G990D0999 heading "Vector Distance|JACCARD"
 
VARIABLE query_vector CLOB
 
-- schwarz
BEGIN
    :query_vector := '[0,0,100]';  
END;
/
 
 
SELECT ID
    , RGB_COLOR
    , FROM_VECTOR(COLOR_VECTOR RETURNING VARCHAR2(100)) AS COLOR_VECTOR
    , vector_distance(COLOR_VECTOR, :query_vector, MANHATTAN)       AS  v_L1_DISTANCE
    , vector_distance(COLOR_VECTOR, :query_vector, EUCLIDEAN )      AS  v_L2_DISTANCE
    , vector_distance(COLOR_VECTOR, :query_vector, COSINE )         AS  v_COSINE_DISTANCE
    , vector_distance(COLOR_VECTOR, :query_vector, DOT)             AS  v_INNER_PRODUCT
    , vector_distance(COLOR_VECTOR, :query_vector, HAMMING )        AS  v_HAMMING_DISTANCE
    --, vector_distance(COLOR_VECTOR, :query_vector, JACCARD) as  v_JACCARD_DISTANCE
  FROM color_search;  
 
 ID RGB_CO COLOR_VECTOR                                        L1 OR MANHATTAN L2 OR EUCLIDEAN COSINE           INNER_PRODUCT         HAMMING        
--- ------ ------------------------------------------------------------------- --------------- --------------- --------------- ---------------
  2 e2eee2 [1.2E+002,5.03999996E+000,9.33300018E+001]                 131.7100        120.2909          0.3864   -9,333.0000            3.0000
  3 077f26 [1.355E+002,9.44899979E+001,4.97999992E+001]               280.1900        172.6518          0.7114   -4,980.0000            3.0000
  4 347af0 [2.17659576E+002,7.83300018E+001,9.41200027E+001]          301.8696        231.3998          0.6231   -9,412.0000            3.0000
  5 3f2234 [3.72413788E+001,4.60299988E+001,2.47099991E+001]          158.5614         95.7824          0.6149   -2,471.0000            3.0000
  6 8a9b91 [1.44705887E+002,1.09700003E+001,6.07799988E+001]          194.8959        150.3275          0.6137   -6,078.0000            3.0000
  7 5d3afa [2.509375E+002,7.68000031E+001,9.80400009E+001]            329.6975        262.4342          0.6500   -9,804.0000            3.0000
  8 96b231 [7.30232544E+001,7.24700012E+001,6.98000031E+001]          175.6933        107.2210          0.4386   -6,980.0005            3.0000
  9 e1f322 [6.51674652E+001,8.60100021E+001,9.52900009E+001]          155.8875        108.0125          0.3381   -9,529.0000            3.0000
 10 a7fad1 [1.5036145E+002,3.32000008E+001,9.80400009E+001]           185.5215        153.9956          0.4629   -9,804.0000            3.0000
 11 2f5426 [1.08260872E+002,5.47599983E+001,3.29399986E+001]          230.0809        138.6222          0.7380   -3,293.9998            3.0000                                                                                                         

Auf dieser Datenmenge können wir nun testen mit welchen Ähnlichkeitsmaß wir die sinnvollste Sortierung erreichen um die Fragen nach Ähnlichkeit zu sortieren.

In Folge wird dann die Treffermenge nach dem entsprechenden Distance Algorithmus sortiert, damit das wahrscheinlichste Ergebnis in der Treffermenge ganz oben steht.


Die wichtigsten Ähnlichkeitsmaße

COSINE_DISTANCE

Viel wird mit dem COSINE_DISTANCE - (Name in der Syntax von Oracle COSINE) gearbeitet

Misst die Ähnlichkeit der Richtungen der Vektoren, nicht deren absoluten Wert.

D.h. folgende Vektoren haben die gleiche Cosinus Distanz:

 '[ 0, 0, 0 ]'
 '[ 125, 125, 125 ]'
 '[ 256, 256, 256 ]'
 
=> 0

In unseren oberen Beispiel dazu wird dann schnell klar, das dieser Ähnlichkeitsmaße für folgende Aufgabe dann ungeeignet ist:

In einer Suche sollen ähnliche Farben über Ihren RGB Wert identifiziert werden:

  • der Vektor besteht aus [ Farbanteil R [0 .. bis 256] , Farbanteil G [0 .. bis 256], Farbanteil R [B .. bis 256]

⇒ Schwarz / Grau / Weiß ist dann vom Ähnlichkeitsmaße die gleiche Farbe

Bei Semantischen Analyse sieht das dann gleich ganz anders aus da hier die Richtung des Vektors in der Punktwolken Menge eines Satzes den entscheidenden Hinweis geben kann.

L2_DISTANCE - EUCLIDEAN

L2_DISTANCE - (Name in der Syntax von Oracle vector_distance EUCLIDEAN, als einzelne Methode L2_DISTANCE ) - Misst den direkten Abstand zwischen zwei Vektoren im Raum.

select   vector_distance('[ 0, 0, 0 ]','[ 125, 125, 125 ]', EUCLIDEAN) from dual;
216.50635094610965
 
 
select   vector_distance('[ 125, 125, 125 ]','[ 256, 256, 256 ]', EUCLIDEAN) from dual;
226.8986557915229
 
-- die Short Methode heißt dann wieder L2_DISTANCE!
 
select L2_DISTANCE('[ 0, 0, 0 ]','[ 256, 256, 256 ]')  from dual;
443.40500673763256

Rechnen wir das mal nach:

(a,b) =sqrt{     
    sum{i=1}{n}{ (A_i - B_i)2 }

   }

A=[125, 125, 125],B=[256, 256, 256] ⇒ EUCLIDEAN(A,B)≈226.90

A_1-B_1 = 125-256 = -131(-131)2 = 17161

A_2-B_2 = 125-256 = -131(-131)2 = 17161

A_3-B_3 = 125-256 = -131(-131)2 = 17161

17161+17161+17161=51483

sqrt{51483} = 226.8986557915

⇒ Schwarz / Grau / Weiß ist dann vom Ähnlichkeitsmaße dann mit einem gewissen Abstand, in Folge wird das als APEX App gebaut um das „graphisch“ anzuzeigen ob das so am Ende gehen könnte.


APEX APP

In einer einfachen APEX APP wird mit einem „Interactive Grid“ und einem Color Picker Item eine Suche durchgeführt. Über HTML Expressions werden die Farben „sichtbar“ dargestellt, um die Ergebnisse besser bewerten zu können.

Die Maske

 Suche nach Farben über Vectoren in der Oracle Datenbank

Query dahinter
SELECT   ID
       , RGB_COLOR 
       ,  COLOR_VECTOR 
       , JSON_ARRAY(COLOR_VECTOR returning varchar2) AS JCOLOR_VECTOR -- zeige Zahlen einfacher an
   --- 
     , vector_distance(COLOR_VECTOR, :P200_QUERY_VECTOR, MANHATTAN)       AS  v_L1_DISTANCE
     , vector_distance(COLOR_VECTOR, :P200_QUERY_VECTOR, EUCLIDEAN )      AS  v_L2_DISTANCE
     , vector_distance(COLOR_VECTOR, :P200_QUERY_VECTOR, COSINE )         AS  v_COSINE_DISTANCE
     , vector_distance(COLOR_VECTOR, :P200_QUERY_VECTOR, DOT)             AS  v_INNER_PRODUCT
     , vector_distance(COLOR_VECTOR, :P200_QUERY_VECTOR, HAMMING )        AS  v_HAMMING_DISTANCE
   ---
    , :P200_QUERY_VECTOR AS  QUERY_VECTOR
    , :P200_COLOR        AS  SEARCH_COLOR
 FROM color_search 

Java Script um den Farb-Picker Wert als HSV in die Suchbox zu schreiben

Funktion zum Wandeln:

function rgbToHsv(r, g, b) {
    // Normalisiere die RGB-Werte auf den Bereich [0, 1]
    r = r / 255;
    g = g / 255;
    b = b / 255;
 
    // Berechne max, min und delta
    const max = Math.max(r, g, b);
    const min = Math.min(r, g, b);
    const delta = max - min;
 
    let h, s, v;
 
    // Berechne Hue (H)
    if (delta === 0) {
        h = 0; // Graustufen (kein Farbton)
    } else if (max === r) {
        h = 60 * (((g - b) / delta) % 6);
    } else if (max === g) {
        h = 60 * (((b - r) / delta) + 2);
    } else if (max === b) {
        h = 60 * (((r - g) / delta) + 4);
    }
 
    // Stelle sicher, dass der Farbton im Bereich [0, 360) liegt
    if (h < 0) {
        h += 360;
    }
 
    // Berechne Saturation (S)
    if (max === 0) {
        s = 0;
    } else {
        s = delta / max;
    }
 
    // Berechne Value (V)
    v = max;
 
     // Gib das Ergebnis als Objekt zurück
    // Math.round(num * 100) / 100
     return {
         h: h          // Farbton (0–360 Grad)
       , s: Math.round(  ( s*100 ) * 1000)  / 1000    // Sättigung (0–1) in %
       , v: Math.round(  (v*100 ) * 1000) / 1000  // Wert/Helligkeit (0–1) in %
    };
}

OnChange Event Handler auf dem Color Picker Item P200_COLOR, das Ergebnis( der Such Vector) wird in das Item P200_QUERY_VECTOR geschrieben (mit dem Ergebnis kann das gesucht werden)

rgbString = apex.item('P200_COLOR').getValue();
 
// Step 1: Extract the numbers from the string using a regular expression
const rgbValues = rgbString.match(/\d+/g);
 
// Step 2: Convert the extracted strings to numbers
const r = parseInt(rgbValues[0], 10);
const g = parseInt(rgbValues[1], 10);
const b = parseInt(rgbValues[2], 10);
 
// Step 3: Create the Search vector 
const hsv = rgbToHsv(r, g, b);
 
//Debug
console.log(`H: ${hsv.h}, S: ${hsv.s}, V: ${hsv.v}`); 
 
const vectorString = '[' + hsv.h +',' + hsv.s +',' + hsv.v +']';
 
apex.item('P200_QUERY_VECTOR').setValue(vectorString);

Nun kann über den Button die Suche durchgeführt werden, je nach Sortierung des Ähnlichkeitsmaßstabes kann nun geprüft werden mit welchen Maßstab sich vernünftige Ergebnisse erzielen lassen.


Index Typen auf den Vector

Zwei Typen werden unterstützt:

  • IVF (Inverted File) Flat index - partitioned-based index - classifed as Neighbor Partition Vector Index
  • HNSW (Hierarchical Navigable Small Worlds) index -graph-based index - In-Memory Neighbor Graph Vector Index

siehe auch ⇒ https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/create-vector-index.html

IVF (Inverted File) Flat index

IVF (Inverted File) Flat index - partitioned-based index - classifed as Neighbor Partition Vector Index

Ein IVF (Inverted File) Flat Index ist ein Indexierungsverfahren, bei dem der Vektorraum in Cluster (Gruppen ähnlicher Vektoren) unterteilt wird, um die Suche nach den nächsten Nachbarn zu beschleunigen, indem nur die relevanten Cluster durchsucht werden, anstatt den gesamten Vektorraum.

HNSW (Hierarchical Navigable Small Worlds) index

HNSW (Hierarchical Navigable Small Worlds) index -graph-based index - In-Memory Neighbor Graph Vector Index

Effizienter Algorithmus für die annähernde k-Nächste-Nachbarn-Suche (k-NN) in hochdimensionalen Vektorräumen, der durch die Kombination von Hierarchien und Graphen eine schnelle und skalierbare Suche ermöglicht

Die annähernde k-Nächste-Nachbarn-Suche (k-NN) ist ein Algorithmus, der die k ähnlichsten Datenpunkte zu einem gegebenen Query-Punkt in einem Datensatz findet, wobei zugunsten von Geschwindigkeit und Skalierbarkeit eine geringe Genauigkeit in Kauf genommen wird.

Eine gute Erklärung findet sich hier ⇒ Hierarchical Navigable Small Worlds (HNSW) Explained ⇒ https://www.youtube.com/watch?v=77QH0Y2PYKg


Index auf den Vector Daten anlegen

Im ersten Test legen wir einen HNSW Index mit der L1 MANHATTAN DISTANCE an:

DROP INDEX idx_color_search_hnsw_idx ;
 
CREATE VECTOR INDEX idx_color_search_hnsw_idx 
    ON color_search (COLOR_VECTOR)
ORGANIZATION INMEMORY NEIGHBOR GRAPH
DISTANCE MANHATTAN
WITH TARGET ACCURACY 90 PARAMETERS (TYPE HNSW, neighbors 40, efconstruction 500);

Index verwenden

Index wird verwendet wenn:

  • Keyword APPROX notwendig
  • Gleicher Algorithmus für den Index und für die vector_distance Methode!

Abfrage und Plan Analyse:

EXPLAIN PLAN FOR
SELECT ID
      , RGB_COLOR
      , vector_distance(COLOR_VECTOR, :query_vector, MANHATTAN)         AS  L1_MANHATTAN_DISTANCE
 FROM color_search 
ORDER BY vector_distance(COLOR_VECTOR, :query_vector, MANHATTAN)     
FETCH APPROX FIRST 3 ROWS ONLY;
 
SELECT * FROM TABLE(DBMS_XPLAN.DISPLAY);
 
 
PLAN_TABLE_OUTPUT                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              
 
------------------------------------------------------------------------------------------------------------
| Id  | Operation                      | Name                      | ROWS  | Bytes | Cost (%CPU)| TIME     |
------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT               |                           |     3 |    72 |     2  (50)| 00:00:01 |
|*  1 |  COUNT STOPKEY                 |                           |       |       |            |          |
|   2 |   VIEW                         |                           |    35 |   840 |     2  (50)| 00:00:01 |
|*  3 |    SORT ORDER BY STOPKEY       |                           |    35 |   140K|     2  (50)| 00:00:01 |
|   4 |     TABLE ACCESS BY INDEX ROWID| COLOR_SEARCH              |    35 |   140K|     1   (0)| 00:00:01 |
|   5 |      VECTOR INDEX HNSW SCAN    | IDX_COLOR_SEARCH_HNSW_IDX |    35 |   140K|     1   (0)| 00:00:01 |
 
 

Wie das aber nun in APEX Verwenden?

In 24.2 gibt es dazu ein eine native Unterstützung ⇒ siehe https://blogs.oracle.com/apex/post/nextgen-data-search-integrating-ai-vector-search-into-search-configurations

Leider gibt es die noch nicht als podman Container (Stand 03.2025).


Vector Index Qualität

Findet der Index Lauf die gleichen Daten wie ein full Table Scan?

Wie heißt mein Index:

SELECT INDEX_NAME,INDEX_SUBTYPE,TABLE_NAME 
 FROM USER_INDEXES 
WHERE TABLE_NAME LIKE '%COLOR%' AND index_type = 'VECTOR';
 
INDEX_NAME                       INDEX_SUBTYPE                 TABLE_NAME                                                                                                                      
--------------------------------------------------------------------------------
IDX_COLOR_SEARCH_HNSW_IDX	INMEMORY_NEIGHBOR_GRAPH_HNSW	COLOR_SEARCH

Abfrage Qualität bewerten:

SET serveroutput ON
 
DECLARE
    v_qvector VECTOR; 
    v_report varchar2(128);
BEGIN 
    v_qvector := to_vector('[120,36.076,61.961]');
    v_report := dbms_vector.index_accuracy_query(
          OWNER_NAME => 'GPI' 
        , INDEX_NAME => 'IDX_COLOR_SEARCH_HNSW_IDX'
        , qv => v_qvector
        , top_K =>10 
        , target_accuracy =>90 );
    dbms_output.put_line(v_report); 
END; 
/
 
 
Accuracy achieved (100%) IS 10% higher than the Target Accuracy requested (90%)

Qualität unsere Vector Models

Wie lässt sich nun die Menge der Vektoren in so einer Tabelle bewerten?

Verteilung der Daten, gibt es Ausreißer etc.?

VECTOR_NORM

Eine Möglichkeit ist die Euclidean Norm des Vector zu betrachten.

Die euklidische Norm (auch bekannt als L²-Norm oder Euclidean Norm) eines Vektors ist ein Maß für die „Länge“ oder den „Abstand“ des Vektors im euklidischen Raum. (also von 0 aus)

Sie wird berechnet als die Quadratwurzel der Summe der quadrierten Komponenten des Vektors.

SELECT VECTOR_NORM(VECTOR('[2, 2]')) AS euclidean_norm ;
2.8284271247461903
 
SELECT  vector_distance(VECTOR('[2, 2]'), VECTOR('[0, 0]'), EUCLIDEAN );
2.8284271247461903

VECTOR_NORM(VECTOR('[2, 2]')) entspricht als der Distance vom 0 Punkt = vector_distance(VECTOR('[2, 2]'), VECTOR('[0, 0]'), EUCLIDEAN )

SELECT  vector_distance(VECTOR('[2, 2]'), VECTOR('[2, 2]'), EUCLIDEAN );
0.0
-- Abstand der beiden Vectoren im Raum
SELECT  vector_distance(VECTOR('[1, 1]'), VECTOR('[2, 2]'), EUCLIDEAN ) ;
1.4142135623730951

https://docs.oracle.com/en/database/oracle/oracle-database/23/sqlrf/vector_norm.html

Das kann zum Beispiel dazu benutzt werden um in den Daten die Vectoren mit starken Abweichungen zu identifizieren.

WITH norm_data AS ( 
SELECT id
      , VECTOR_NORM(COLOR_VECTOR) L2 
    FROM color_search
)
SELECT  MIN(L2) AS minL2
     ,  MAX(L2) AS maxL2 
     ,  STDDEV_POP(L2) AS stdL2     
     --
     , PERCENTILE_CONT(0.25) WITHIN GROUP (ORDER BY L2) AS q1
     , MEDIAN(L2) AS median
     , PERCENTILE_CONT(0.75) WITHIN GROUP (ORDER BY L2) AS q3
  FROM norm_data;

Bei unseren Test Daten sieht das sehr gleichverteilt aus.


Fazit

Mit einem eigenen Vector Typ lassen sich ganze neue Anwendungsfälle für die Oracle Daten sehr einfach umsetzten.

Da das Arbeiten mit dem Vectoren an sich auch nur rein Mathematik ist, lassen sich Ergebnisse bei einfachen Modell auch noch nachvollziehen.

Die Kunst liegt eher darin die zu analysierende Datenmenge ein einen passenden Vector zu wandeln, der sich dann am Ende auch noch wieder einigermaßen ähnlich auswerten lässt.

So können wir unscharfe Suchen implementieren, die Ähnlichkeitsmaßstäbe zwischen dem Such und Ergebnis Vector ist ja mehr eine Schätzfunktion als ein exakter Treffer.

D.h. diese Art der Datenverarbeitung eignet sich besonders für den Einsatz für den Vergleich von Mustern in Daten.

Anwendungsfälle

Ähnlichkeitssuche in Bildern

Reverse Image Search (z. B. Produktsuche per Foto).

Umsetzung:

  • Bilder werden als Vektoren (Embeddings) gespeichert (z. B. mit CNN-Modellen wie ResNet).
  • Suche nach ähnlichen Bildern über Vektorähnlichkeit (z. B. Kosinus-Ähnlichkeit).
Semantische Textsuche

Ein Vector kann auch mit Oracle Text kombiniert werden, siehe dazu ⇒ Oracle Datenbank 23ai - Hybrid Vector Search - Oracle Text und eine Model basierende AI Vector Index kombinieren um in Texten nach Zusammenhängen zu suchen.

Mustererkennung in Datenströmen

Zeitreihen werden in Vektoren umgewandelt (z. B. mittels Fourier-Transformation)

Ähnlichkeitssuche in Produktdaten

Siehe unser Farbdemo



Quellen

Diese Website verwendet Cookies. Durch die Nutzung der Website stimmen Sie dem Speichern von Cookies auf Ihrem Computer zu. Außerdem bestätigen Sie, dass Sie unsere Datenschutzbestimmungen gelesen und verstanden haben. Wenn Sie nicht einverstanden sind, verlassen Sie die Website.Weitere Information
"Autor: Gunther Pipperr"
ki/oracle_vector_for_data_compare.txt · Zuletzt geändert: 2025/04/16 12:37 von gpipperr