This is the
third post in our series on Oracle AI Vector Search and builds on the examples
and data used in the two previous posts. The first was getting
started with AI Vector search, the second was using HNSW
vector index. In those posts we explored how AI Vector search allows you to
find the similar content based on semantic representation or meaning rather
than the unstructured data raw values
In the first
post, we performed exhaustive similarity searches, comparing every item in
the dataset to find the closest matches. In contrast, the second
post used an In-Memory Neighbor Graph (HNSW) vector index to perform
approximate similarity searches, which we found to be much faster than an
exhaustive similarity search. Although very fast, an HNSW vector index is an
in-memory only index and can require a lot of memory for large datasets. In
practice, too much memory for some very large datasets.
In this post,
we will explore how to use an Inverted File Flat (IVF) partition-based index,
which is a type of Neighbor Partition vector index. This is a storage-based
index as opposed to the HNSW vector index, which is an in-memory index. The IVF
vector index also uses a different search technique than an HNSW index. It is
designed to enhance search efficiency by narrowing the search area through the
use of neighbor partitions or clusters.
The dataset
size determines the number of partitions in the index. The center of each
partition, or the centroid, represents the average vector for each partition.
It is also called the center of gravity of the partition. By default, the
number of partitions and their corresponding centroids is set to the square
root of the dataset’s size. However, this can be adjusted by specifying the
NEIGHBOR PARTITIONS parameter during index creation. The centroids conceptually
partition the vector space.
For a query
vector, the search algorithm identifies the number of nearest centroids, where
the default number is the square root of the total number of centroids. This
can be adjusted by setting the NEIGHBOR PARTITION PROBES parameter. The higher
the number of nearest centroids, the more accurate the search, but that
accuracy comes at a cost. The more centroids selected, the more work that needs
to be performed. Once the number of partitions is determined, they are
thoroughly scanned for the top nearest vectors to the vector specified by the
query.
More
information about how IVF indexes work are available
in the docs.
To create IVF
indexes on CASE_EMBEDDINGS vector column in the table VECTOR_SEARCH_DEMO ,the
following statement can be used.
demo@ADB26AI> create
vector index ivf_demo
2 on VECTOR_SEARCH_DEMO( CASE_EMBEDDINGS )
3 organization neighbor partitions
4* distance cosine ;
2 on VECTOR_SEARCH_DEMO( CASE_EMBEDDINGS )
3 organization neighbor partitions
4* distance cosine ;
Vector INDEX created.

This statement
will create a global partitioned IVF vector index and will result in the
creation of two internal tables:
demo@ADB26AI> select
table_name
2 from user_tables
3* where table_name like 'VECTOR$IVF_DEMO%';
TABLE_NAME
_________________________________________________________________
VECTOR$IVF_DEMO$4040231_4231331_0$IVF_FLAT_CENTROIDS
VECTOR$IVF_DEMO$4040231_4231331_0$IVF_FLAT_CENTROID_PARTITIONS
These tables are of the format:
IVF indexes do
need some memory, either from the vector pool if it has been defined or the
shared pool, to speed up index creation and during DML operations on the base
table. Let’s query the Vector Pool and see how much memory our new index uses.
2 from user_tables
3* where table_name like 'VECTOR$IVF_DEMO%';
TABLE_NAME
_________________________________________________________________
VECTOR$IVF_DEMO$4040231_4231331_0$IVF_FLAT_CENTROIDS
VECTOR$IVF_DEMO$4040231_4231331_0$IVF_FLAT_CENTROID_PARTITIONS
These tables are of the format:
- VECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROIDS, containing the list of identified centroid vectors and associated ids.
- VECTOR$<base table name>_IVF_IDX$<object info>$IVF_FLAT_CENTROID_PARTITIONS, which is list-partitioned on the centroid ids. Each partition contains the base table vectors closely related (cluster) to the corresponding centroid id for that partition.
Details of the pool can be displayed by querying the view V$VECTOR_MEMORY_POOL:
POOL ALLOC_BYTES USED_BYTES POPULATE_STATUS CON_ID
____________ ______________ _____________ __________________ _________
1MB POOL 70479593 76546048 OUT OF MEMORY 37
64KB POOL 17619898 1310720 DONE 37
2 , used_bytes, num_vectors, index_dimensions
3 from v$vector_index
4* where index_name ='IVF_DEMO';
INDEX_NAME INDEX_ORGANIZATION ALLOCATED_BYTES USED_BYTES NUM_VECTORS INDEX_DIMENSIONS
_____________ ______________________ __________________ _____________ ______________ ___________________
IVF_DEMO NEIGHBOR PARTITIONS 2097152 80768 1427029 384
2 from (
3 select case_primary_type
4 , case_description
5 , vector_distance(case_embeddings , vector_embedding( MY_DEMO_MODEL using 'LARCENY' as data ) , cosine ) vd
6 from vector_search_demo t
7 order by vd
8 fetch approx first 10 rows only with target accuracy 90 )
9 group by case_primary_type , case_description ,vd
10 order by vd
11* fetch first 15 rows only;
CASE_PRIMARY_TYPE CASE_DESCRIPTION VD
____________________ _________________________________ ______________________
OTHER OFFENSE OTHER CRIME INVOLVING PROPERTY 0.38452393962513975
PLAN_TABLE_OUTPUT
---------------------------------------
SQL_ID 2p9222n5fnzg7, child number 1
-------------------------------------
select case_primary_type , case_description , vd from ( select
case_primary_type , case_description ,
vector_distance(case_embeddings , vector_embedding( MY_DEMO_MODEL using
'LARCENY' as data ) , cosine ) vd from vector_search_demo t order
by vd fetch approx first 10 rows only with target accuracy 90 )
group by case_primary_type , case_description ,vd order by vd fetch
first 15 rows only
Plan hash value: 1724078458
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| Id | Operation | Name | Starts | E-Rows | A-Rows | A-Time | Buffers | Reads |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| 0 | SELECT STATEMENT | | 1 | | 1 |00:00:00.32 | 4977 | 3 |
| 1 | RESULT CACHE | d2jdkwfk05fmrfw35q2m0zwf4c | 1 | | 1 |00:00:00.32 | 4977 | 3 |
|* 2 | COUNT STOPKEY | | 1 | | 1 |00:00:00.32 | 4977 | 3 |
| 3 | VIEW | | 1 | 10 | 1 |00:00:00.32 | 4977 | 3 |
|* 4 | SORT GROUP BY STOPKEY | | 1 | 10 | 1 |00:00:00.32 | 4977 | 3 |
| 5 | VIEW | | 1 | 10 | 10 |00:00:00.32 | 4977 | 3 |
| 6 | VIEW | | 1 | 10 | 10 |00:00:00.32 | 4977 | 3 |
| 7 | NESTED LOOPS | | 1 | 10 | 10 |00:00:00.32 | 4977 | 3 |
| 8 | VIEW | VW_IVPSR_F17F1C9B | 1 | 10 | 10 |00:00:00.32 | 4962 | 3 |
|* 9 | COUNT STOPKEY | | 1 | | 10 |00:00:00.32 | 4962 | 3 |
| 10 | VIEW | VW_IVPSJ_578B79F1 | 1 | 169K| 10 |00:00:00.32 | 4962 | 3 |
|* 11 | SORT ORDER BY STOPKEY | | 1 | 169K| 10 |00:00:00.32 | 4962 | 3 |
|* 12 | HASH JOIN | | 1 | 169K| 1603 |00:00:00.32 | 4962 | 3 |
| 13 | PART JOIN FILTER CREATE | :BF0000 | 1 | 7 | 7 |00:00:00.22 | 22 | 0 |
| 14 | VIEW | VW_IVCR_B5B87E67 | 1 | 7 | 7 |00:00:00.22 | 22 | 0 |
|* 15 | COUNT STOPKEY | | 1 | | 7 |00:00:00.22 | 22 | 0 |
| 16 | VIEW | VW_IVCN_9A1D2119 | 1 | 59 | 7 |00:00:00.22 | 22 | 0 |
|* 17 | SORT ORDER BY STOPKEY | | 1 | 59 | 7 |00:00:00.22 | 22 | 0 |
| 18 | TABLE ACCESS STORAGE FULL| VECTOR$IVF_DEMO$4040231_4271572_0$IVF_FLAT_CENTROIDS | 1 | 59 | 59 |00:00:00.01 | 22 | 0 |
| 19 | PARTITION LIST JOIN-FILTER | | 1 | 1427K| 1603 |00:00:00.10 | 4940 | 3 |
| 20 | TABLE ACCESS STORAGE FULL | VECTOR$IVF_DEMO$4040231_4271572_0$IVF_FLAT_CENTROID_PARTITIONS | 7 | 1427K| 1603 |00:00:00.10 | 4940 | 3 |
| 21 | TABLE ACCESS BY USER ROWID | VECTOR_SEARCH_DEMO | 10 | 1 | 10 |00:00:00.01 | 15 | 0 |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
2 - filter(ROWNUM<=15)
4 - filter(ROWNUM<=15)
9 - filter(ROWNUM<=10)
11 - filter(ROWNUM<=10)
12 - access("VW_IVCR_B5B87E67"."CENTROID_ID"="VTIX_CNPART"."CENTROID_ID")
15 - filter(ROWNUM<=7)
17 - filter(ROWNUM<=7)