adm_ai_vector_api
Native Oracle AI Vector Search backend (Oracle 23ai / 26ai+).
Alternative to adm_ai_qdrant_api: stores embeddings in the database using the native VECTOR datatype and searches with VECTOR_DISTANCE, instead of an external Qdrant server. Selected per RAG collection via config_json.vector_store = ‘ORACLE’.
Each ORACLE-backed collection gets its own table adm_ai_rag_vec_<rag_collection_id>
with a fixed VECTOR(<dims>, FLOAT32) column and a vector index, so collections with
different embedding dimensions can coexist.
All vector SQL is dynamic (object names are per-collection), so this package COMPILES on every Oracle version; it only raises at runtime if invoked on a pre-23ai database. No VECTOR datatype appears in this spec, so it parses everywhere.
The index is configuration, not a constant
Section titled “The index is configuration, not a constant”How the index is built comes from the collection’s config_json.vector_index section
(see the RAG configuration guide). Everything in it is optional; the resolved defaults
are IVF at target accuracy 95, unpartitioned, no quantization.
apply_index_config is the single reconcile step: it compares that desired
configuration against what adm_ai_rag_vector_stores says was last applied and
rebuilds only what differs. It is idempotent, so a release migration that needs to
change index settings does nothing more than loop over the collections and call it.
begin adm_context_api.system_login; for c in (select rag_collection_id from adm_ai_rag_collections) loop adm_ai_vector_api.apply_index_config(p_rag_collection_id => c.rag_collection_id); commit; end loop;end;The commit in that loop is required. None of the DDL here is transactional - it
commits on its own - but the row apply_index_config writes to
adm_ai_rag_vector_stores afterwards is ordinary DML, and nothing in this package may
commit it for you. Roll that transaction back and the store is left recorded as
PENDING while its index sits there perfectly healthy, and every later reconcile will
dutifully drop and rebuild an index that was never wrong. Commit after calling.
r_store_status_type
Section titled “r_store_status_type”The state of one collection’s vector store, as last applied by apply_index_config. A NULL table_name means no store has been provisioned for the collection.
Definition:
type r_store_status_type is record ( rag_collection_id number, table_name varchar2(128 char), dimensions number, distance_metric varchar2(30 char), index_type varchar2(20 char), index_status varchar2(20 char), partition_count number, applied_date timestamp with local time zone, last_error varchar2(4000 char));Fields:
| Name | Type | Description |
|---|---|---|
rag_collection_id | number | - |
table_name | varchar2(128 char) | - |
dimensions | number | - |
distance_metric | varchar2(30 char) | - |
index_type | varchar2(20 char) | - |
index_status | varchar2(20 char) | - |
partition_count | number | - |
applied_date | timestamp with local time zone | - |
last_error | varchar2(4000 char) | - |
Functions and Procedures
Section titled “Functions and Procedures”create_collection_store
Section titled “create_collection_store”Create the per-collection vector store table and bring its index in line with the collection configuration. Idempotent: an already-correct store is left untouched.
Signature:
procedure create_collection_store ( p_rag_collection_id in number, p_dimensions in number, p_distance in varchar2 default 'Cosine');Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
p_dimensions | in | number | Number of dimensions of the embedding vectors |
p_distance | in | varchar2 default 'Cosine' | Distance metric (‘Cosine’, ‘Euclidean’ or ‘Dot’); default ‘Cosine’ |
apply_index_config
Section titled “apply_index_config”Reconcile a collection’s vector store with its stored configuration.
Reads config_json.vector_index, compares it against adm_ai_rag_vector_stores and
the data dictionary, and does the least work that makes them agree: nothing at all,
a drop-and-recreate of the index, or a rebuild of the store table when the hash
partitioning changed. The outcome (including a failed index build, which used to be
swallowed) is recorded in adm_ai_rag_vector_stores.
Refuses to run when embedding.dimensions no longer matches the store: the VECTOR
column’s dimension count cannot be altered, and dropping the embeddings to rebuild at
a new width is not a decision this procedure may take on its own.
Signature:
procedure apply_index_config ( p_rag_collection_id in number, p_force in boolean default false);Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
p_force | in | boolean default false | Rebuild the index even when the configuration has not changed |
get_store_status
Section titled “get_store_status”What was last applied to a collection’s vector store. Use it to find out whether the index actually exists - a build can fail (an HNSW index needs VECTOR_MEMORY_SIZE > 0) and searches then silently fall back to an exact scan.
Signature:
function get_store_status ( p_rag_collection_id in number) return r_store_status_type;Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
Returns: r_store_status_type - The recorded store state; table_name is NULL when there is no store
drop_collection_store
Section titled “drop_collection_store”Drop the per-collection vector store table. Safe to call if it does not exist.
Signature:
procedure drop_collection_store ( p_rag_collection_id in number);Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
upsert_points
Section titled “upsert_points”Upsert (merge) embedding vectors for a batch of chunks into the collection store.
Signature:
procedure upsert_points ( p_rag_collection_id in number, p_chunk_ids in apex_t_number, p_file_ids in apex_t_number, p_vectors in json_array_t);Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
p_chunk_ids | in | apex_t_number | Array of chunk IDs (parallel to p_file_ids and p_vectors) |
p_file_ids | in | apex_t_number | Array of owning rag_collection_file_ids (the hash partition key) |
p_vectors | in | json_array_t | JSON array of vectors (each element is a JSON array of numbers) |
delete_points
Section titled “delete_points”Delete every vector belonging to the given collection files from the collection store, which is what a REMOVE job does when a file leaves a collection.
rag_collection_file_id is the store’s hash partition key, so the delete is partition-local. Safe to call when the store does not exist, or with an empty list: both do nothing rather than deleting everything.
Signature:
procedure delete_points ( p_rag_collection_id in number, p_file_ids in apex_t_number);Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
p_file_ids | in | apex_t_number | Owning rag_collection_file_ids whose vectors are to be deleted |
search_similar
Section titled “search_similar”Search for similar vectors in the collection store. Returns the same JSON shape as
adm_ai_qdrant_api.search_similar: a JSON array of objects { “id”:
The three accuracy parameters are the query-side counterpart of the index’s build-time target accuracy. Pass none of them to search at the accuracy the index was built for. They are mutually exclusive: p_target_accuracy wins over the two internal parameters.
Signature:
function search_similar ( p_rag_collection_id in number, p_vector in json_array_t, p_limit in number default 10, p_score_threshold in number default 0.5, p_distance in varchar2 default 'Cosine', p_target_accuracy in number default null, p_efsearch in number default null, p_probes in number default null, p_file_ids in apex_t_number default null) return json_array_t;Parameters:
| Name | Direction | Type | Description |
|---|---|---|---|
p_rag_collection_id | in | number | ID of the RAG collection |
p_vector | in | json_array_t | Query vector (JSON array of numbers) |
p_limit | in | number default 10 | Maximum number of results to return |
p_score_threshold | in | number default 0.5 | Minimum similarity score (results below are dropped) |
p_distance | in | varchar2 default 'Cosine' | Distance metric (‘Cosine’, ‘Euclidean’ or ‘Dot’); default ‘Cosine’ |
p_target_accuracy | in | number default null | Target accuracy percentage (1..100) for this query |
p_efsearch | in | number default null | HNSW candidates to consider for this query (1..65535) |
p_probes | in | number default null | IVF neighbor partitions to probe for this query |
p_file_ids | in | apex_t_number default null | Restrict the search to the chunks of these rag_collection_file_ids; |
null (the default) searches the whole collection. An empty collection returns no rows rather than searching everything, because "restrict to nothing" must not read as "restrict to anything". A restricted search is always EXACT: an approximate index scan filters after it has picked its candidates, so it can return far fewer rows than asked for - or none - when the predicate is narrow, which is exactly the case here. One document's chunks are few, so exact costs little. |Returns: json_array_t - JSON array of { id, score } objects, highest score first