AI Vector Search #1 - 기본 기능
AI Vector Search #2 - HNSW 벡터 인덱스
AI Vector Search #3 - IVF 벡터 인덱스
Oracle 23ai에 AI Vector Search 기능이 추가되었습니다. AI Vector Search는 AI 워크로드를 위해 설계되었으며 키워드가 아닌 의미론에 기반하여 데이터를 조회합니다. 이 글에서는 AI Vector Search의 기본 기능에 대해 간단히 살펴보겠습니다. ML을 사용한 벡터 생성과 관련된 내용은 Oracle AI Vector Search User's Guide를 참고하세요.
테스트 버전은 아래와 같습니다.
-- 1 SELECT version_full FROM product_component_version; VERSION_FULL ------------ 23.4.0.24.05 1 row selected.
테스트를 위해 아래와 같이 테이블을 생성하겠습니다. 생성한 벡터 값은 단순한 3x3 배열입니다. JSON_ARRAY 함수는 배열 형식의 JSON 값을 생성하고, TO_VECTOR 함수는 문자 값을 벡터 값으로 변환합니다. 참고로 TO_VECTOR 함수를 생략해도 암시적 데이터 변환(JSON -> VARCHAR2 -> VECTOR)에 의해 테이블이 정상적으로 생성됩니다.
-- 2 DROP TABLE t1 PURGE; CREATE TABLE t1 (c1, c2, c3, CONSTRAINT t1_pk PRIMARY KEY (c1, c2)) AS SELECT a.c1, b.c1, TO_VECTOR (JSON_ARRAY (a.c1, b.c1)) FROM (SELECT ROWNUM AS c1 FROM XMLTABLE ('1 to 3')) a , (SELECT ROWNUM AS c1 FROM XMLTABLE ('1 to 3')) b;
벡터 테이터 타입은 Oracle 23ai에 추가된 새로운 기본 데이터 타입으로 데이터를 LOB 타입으로 저장하는 것으로 보입니다.
-- 3-1 SELECT data_type, data_length, vector_info FROM user_tab_columns WHERE table_name = 'T1' AND column_name = 'C3'; DATA_TYPE DATA_LENGTH VECTOR_INFO --------- ----------- ----------- VECTOR 8200 VECTOR(*,*) 1 row selected. -- 3-2 SELECT segment_name, index_name, format, value_based, max_inline FROM user_lobs WHERE table_name = 'T1'; SEGMENT_NAME INDEX_NAME FORMAT VALUE_BASED MAX_INLINE ------------------------- ------------------------ -------------- ----------- ---------- SYS_LOB0000089887C00003$$ SYS_IL0000089887C00003$$ ENDIAN NEUTRAL YES 8000 1 row selected.
아래 쿼리는 VECTOR_DISTANCE 함수로 벡터 간의 거리를 계산합니다. VECTOR_DISTANCE 함수는 세 번째 매개변수에 다양한 메트릭을 지정할 수 있습니다. VECTOR_DISTANCE 함수 외에도 다수의 Vector 함수를 사용할 수 있습니다.
-- 4 SELECT c1, c2, c3 , VECTOR_DISTANCE (c3, '[1,1]', COSINE ) AS cosine -- COSINE_DISTANCE , VECTOR_DISTANCE (c3, '[1,1]', DOT ) AS dot -- INNER_PRODUCT , VECTOR_DISTANCE (c3, '[1,1]', EUCLIDEAN ) AS euclidean -- L2_DISTANCE , VECTOR_DISTANCE (c3, '[1,1]', EUCLIDEAN_SQUARED) AS euclidean_squared -- L2_SQUARED , VECTOR_DISTANCE (c3, '[1,1]', HAMMING ) AS hamming , VECTOR_DISTANCE (c3, '[1,1]', MANHATTAN ) AS manhattan -- L1_DISTANCE FROM t1; C1 C2 C3 COSINE DOT EUCLIDEAN EUCLIDEAN_SQUARED HAMMING MANHATTAN -- -- ------------------- ---------- --------- ---------- ----------------- -------- --------- 1 1 [1.0E+000,1.0E+000] -1.19E-007 -2.0E+000 0 0 0 0 1 2 [1.0E+000,2.0E+000] 5.132E-002 -3.0E+000 1.0E+000 1.0E+000 1.0E+000 1.0E+000 1 3 [1.0E+000,3.0E+000] 1.056E-001 -4.0E+000 2.0E+000 4.0E+000 1.0E+000 2.0E+000 2 1 [2.0E+000,1.0E+000] 5.132E-002 -3.0E+000 1.0E+000 1.0E+000 1.0E+000 1.0E+000 2 2 [2.0E+000,2.0E+000] -1.19E-007 -4.0E+000 1.414E+000 2.0E+000 2.0E+000 2.0E+000 2 3 [2.0E+000,3.0E+000] 1.942E-002 -5.0E+000 2.236E+000 5.0E+000 2.0E+000 3.0E+000 3 1 [3.0E+000,1.0E+000] 1.056E-001 -4.0E+000 2.0E+000 4.0E+000 1.0E+000 2.0E+000 3 2 [3.0E+000,2.0E+000] 1.942E-002 -5.0E+000 2.236E+000 5.0E+000 2.0E+000 3.0E+000 3 3 [3.0E+000,3.0E+000] -1.19E-007 -6.0E+000 2.828E+000 8.0E+000 2.0E+000 4.0E+000 9 rows selected.
아래 쿼리의 함수는 VECTOR_DISTANCE 함수의 축약 함수 (shorthand function)입니다.
-- 5 SELECT c1, c2, c3 , COSINE_DISTANCE (c3, '[1,1]') AS cosine , INNER_PRODUCT (c3, '[1,1]') * -1 AS dot , L2_DISTANCE (c3, '[1,1]') AS euclidean , L1_DISTANCE (c3, '[1,1]') AS manhattan FROM t1; C1 C2 C3 COSINE DOT EUCLIDEAN MANHATTAN -- -- ------------------- ---------- --------- ---------- --------- 1 1 [1.0E+000,1.0E+000] -1.19E-007 -2.0E+000 0 0 1 2 [1.0E+000,2.0E+000] 5.132E-002 -3.0E+000 1.0E+000 1.0E+000 1 3 [1.0E+000,3.0E+000] 1.056E-001 -4.0E+000 2.0E+000 2.0E+000 2 1 [2.0E+000,1.0E+000] 5.132E-002 -3.0E+000 1.0E+000 1.0E+000 2 2 [2.0E+000,2.0E+000] -1.19E-007 -4.0E+000 1.414E+000 2.0E+000 2 3 [2.0E+000,3.0E+000] 1.942E-002 -5.0E+000 2.236E+000 3.0E+000 3 1 [3.0E+000,1.0E+000] 1.056E-001 -4.0E+000 2.0E+000 2.0E+000 3 2 [3.0E+000,2.0E+000] 1.942E-002 -5.0E+000 2.236E+000 3.0E+000 3 3 [3.0E+000,3.0E+000] -1.19E-007 -6.0E+000 2.828E+000 4.0E+000 9 rows selected.
아래 쿼리는 축약 연산자(shorthand operator)로 벡터 간의 거리를 계산합니다.
-- 6 SELECT c1, c2, c3 , c3 <=> '[1,1]' AS cosine , c3 <#> '[1,1]' AS dot , c3 <-> '[1,1]' AS euclidean FROM t1; C1 C2 C3 COSINE DOT EUCLIDEAN -- -- ------------------- ---------- --------- ---------- 1 1 [1.0E+000,1.0E+000] -1.19E-007 -2.0E+000 0 1 2 [1.0E+000,2.0E+000] 5.132E-002 -3.0E+000 1.0E+000 1 3 [1.0E+000,3.0E+000] 1.056E-001 -4.0E+000 2.0E+000 2 1 [2.0E+000,1.0E+000] 5.132E-002 -3.0E+000 1.0E+000 2 2 [2.0E+000,2.0E+000] -1.19E-007 -4.0E+000 1.414E+000 2 3 [2.0E+000,3.0E+000] 1.942E-002 -5.0E+000 2.236E+000 3 1 [3.0E+000,1.0E+000] 1.056E-001 -4.0E+000 2.0E+000 3 2 [3.0E+000,2.0E+000] 1.942E-002 -5.0E+000 2.236E+000 3 3 [3.0E+000,3.0E+000] -1.19E-007 -6.0E+000 2.828E+000 9 rows selected.
VECTOR_DISTANCE 함수로 데이터를 정렬하는 경우 ROW LIMITING 절의 FETCH 절에 EXACT 또는 APPROX 키워드를 기술할 수 있습니다. 기본값은 EXACT이며, APPROX는 벡터 인덱스를 통한 Approximate Similarity Search에 사용합니다.
FETCH [ EXACT | APPROX | APPROXIMATE ] { FIRST | NEXT }
아래 쿼리는 [1,1] 벡터에 가까운 5개의 벡터를 조회합니다. Column Projection Information 항목에서 VECTOR 함수에 의해 문자값이 벡터값으로 변환되는 것을 확인할 수 있습니다. VECTOR 함수는 TO_VECTOR 함수의 synonym입니다.
-- 7 SELECT c1, c2, c3, VECTOR_DISTANCE (c3, '[1,1]', EUCLIDEAN) AS euclidean FROM t1 WHERE (c1, c2) != (1, 1) ORDER BY VECTOR_DISTANCE (c3, '[1,1]', EUCLIDEAN) FETCH EXACT FIRST 5 ROWS ONLY; C1 C2 C3 EUCLIDEAN -- -- ------------------- ---------- 1 2 [1.0E+000,2.0E+000] 1.0E+000 2 1 [2.0E+000,1.0E+000] 1.0E+000 2 2 [2.0E+000,2.0E+000] 1.414E+000 1 3 [1.0E+000,3.0E+000] 2.0E+000 3 1 [3.0E+000,1.0E+000] 2.0E+000 5 rows selected. -------------------------------------------------------------------- | Id | Operation | Name | Starts | A-Rows | Buffers | -------------------------------------------------------------------- | 0 | SELECT STATEMENT | | 1 | 5 | 3 | |* 1 | COUNT STOPKEY | | 1 | 5 | 3 | | 2 | VIEW | | 1 | 5 | 3 | |* 3 | SORT ORDER BY STOPKEY| | 1 | 5 | 3 | |* 4 | TABLE ACCESS FULL | T1 | 1 | 8 | 3 | -------------------------------------------------------------------- Predicate Information (identified by operation id): --------------------------------------------------- 1 - filter(ROWNUM<=5) 3 - filter(ROWNUM<=5) 4 - filter(("C2"<>1 OR "C1"<>1)) Column Projection Information (identified by operation id): ----------------------------------------------------------- 1 - "from$_subquery$_002"."C1"[NUMBER,22], "from$_subquery$_002"."C2"[NUMBER,22], "from$_subquery$_002"."C3"[VECTOR,8200], "from$_subquery$_002"."EUCLIDEAN"[BINARY_DOUBLE,8] 2 - "from$_subquery$_002"."C1"[NUMBER,22], "from$_subquery$_002"."C2"[NUMBER,22], "from$_subquery$_002"."C3"[VECTOR,8200], "from$_subquery$_002"."EUCLIDEAN"[BINARY_DOUBLE,8] 3 - (#keys=1) VECTOR_DISTANCE("C3" /*+ LOB_BY_VALUE */ , VECTOR('[1,1]', *, * /*+ USEBLOBPCW_QVCGMD */ ), EUCLIDEAN)[8], "C1"[NUMBER,22], "C2"[NUMBER,22], "C3" /*+ LOB_BY_VALUE */ [VECTOR,8200] 4 - "C1"[NUMBER,22], "C2"[NUMBER,22], "C3" /*+ LOB_BY_VALUE */ [VECTOR,8200], VECTOR_DISTANCE("C3" /*+ LOB_BY_VALUE */ , VECTOR('[1,1]', *, * /*+ USEBLOBPCW_QVCGMD */ ), EUCLIDEAN)[8]