Semantic Search on Bank Support Tickets Inside Oracle AI Database 26ai: In-Database AI, Measured

 



Tested on: Oracle AI Database 26ai (23.26.4.1.0) on Oracle Autonomous AI Database, in-database ONNX model ALL_MINILM_L12_V2 | Level: Intermediate

Customers rarely use the words a support team expects. "Someone took my card" means the same as "my debit card is missing", but a keyword search will not find one from the other. I loaded an AI embedding model directly into Oracle AI Database 26ai and ran semantic search over 2,000 fictional bank support tickets, with no external AI service involved. For five of six customer questions worded unlike any ticket, at least 8 of the top 10 results were the right kind of ticket. Embedding ran at about 73 tickets per second, and a search took under 1 ms with an HNSW index. The sixth question failed completely, and the reason why is the most useful lesson in this post.

Results at a glance




StepMeasured
Download and load the ONNX model into the database23.7 s
Embed 2,000 tickets inside the database27.4 s (about 73 tickets/s)
Embed one customer question15.8 ms
Top-10 search, exact scan1.55 ms
Build HNSW vector index1.8 s
Top-10 search, HNSW index0.82 ms
Questions answered correctly (at least 8 of top 10)5 of 6

Why semantic search, and why inside the database

An embedding model turns a piece of text into a vector, a list of numbers that represents its meaning. Texts with similar meaning get vectors that are close together, even when they share no words. Searching by vector distance finds tickets about the same problem, however the customer phrased it.

Oracle AI Database 26ai can run such a model inside the database in ONNX format. Embeddings are generated with SQL, next to the data, so customer text never leaves the database to reach an external AI service. For a bank, that is a significant data-protection advantage.

Step 1: load the model

Oracle publishes a prebuilt version of the all-MiniLM-L12-v2 sentence model for the database. On Autonomous Database it is downloaded into DATA_PUMP_DIR and then loaded:

DECLARE
  l_file VARCHAR2(100)  := 'all_MiniLM_L12_v2.onnx';
  l_uri  VARCHAR2(1000) := '<Oracle model bucket URL>/' || 'all_MiniLM_L12_v2.onnx';
BEGIN
  DBMS_CLOUD.GET_OBJECT(credential_name => NULL,
                        directory_name  => 'DATA_PUMP_DIR',
                        object_uri      => l_uri);
  DBMS_VECTOR.LOAD_ONNX_MODEL(directory  => 'DATA_PUMP_DIR',
                              file_name  => l_file,
                              model_name => 'ALL_MINILM_L12_V2');
END;
/

The download URL is in Oracle's blog post "Use our prebuilt ONNX model now available for embedding generation in Oracle Database 23ai". Loading took 23.7 seconds, and the model appears like any other mining model:

MODEL_NAME        MINING_FUNCTION ALGORITHM
----------------- --------------- ---------
ALL_MINILM_L12_V2 EMBEDDING       ONNX

DIMENSIONS
----------
       384

Step 2: tickets and embeddings

I generated 2,000 fictional tickets across eight categories: lost card, failed transfer, login and OTP, ATM cash, loan EMI, fees, KYC and statements. Each category has six different wordings, for example "Lost ATM card, please deactivate it" and "My wallet with the bank card was taken".

CREATE TABLE sem_tickets (
  ticket_id   NUMBER PRIMARY KEY,
  category    VARCHAR2(20),
  ticket_text VARCHAR2(400),
  embedding   VECTOR(384, FLOAT32)
);

UPDATE sem_tickets
SET    embedding = VECTOR_EMBEDDING(ALL_MINILM_L12_V2 USING ticket_text AS data);

One UPDATE embedded all 2,000 tickets in 27.4 seconds, about 73 tickets per second on this sandbox. Embedding a single customer question took 15.8 ms.

Step 3: keyword vs semantic

I wrote six customer questions on purpose so that none of them uses the wording of any ticket. Keyword search took one obvious word from each question, such as "took", "mortgage" or "security".

SELECT category
FROM   sem_tickets
ORDER  BY VECTOR_DISTANCE(embedding, :question_vector, COSINE)
FETCH  EXACT FIRST 10 ROWS ONLY;
QUESTION                                     KEYWORD_HITS  SEMANTIC_CORRECT_OF_10
-------------------------------------------- ------------  ----------------------
someone took my card                                    0                      10
I paid a friend but he never got the money              0                       8
the security code text message is not coming            0                      10
the cash point kept my money                            0                      10
monthly repayment amount for my mortgage                0                      10
the bank took extra money without telling me            0                       0

Keyword search found nothing for any question. To be fair to it, that is by design: I chose questions worded differently from every ticket, which is exactly where keyword search is weakest. Semantic search, by contrast, found the right category for five of six questions. The top match for "someone took my card" was a ticket that shares almost no words with it (duplicate row removed):

TICKET_TEXT                                      CATEGORY   DISTANCE
------------------------------------------------ ---------- --------
My wallet with the bank card was taken. Thanks.  CARD_LOST     0.28
I think someone stole my credit card. Thanks.    CARD_LOST     0.28

The miss: when words outweigh meaning

The question "the bank took extra money without telling me" is about a fee. Every one of its top five results was a lost-card ticket (trimmed):

CATEGORY   TICKET_TEXT                                                     DISTANCE
---------- --------------------------------------------------------------- --------
CARD_LOST  My wallet with the bank card was taken. Happened yesterday...      0.417
CARD_LOST  My wallet with the bank card was taken. Customer called twice.     0.428

The model latched onto the shared words "bank" and "took/taken" instead of the meaning, an unexpected charge. The transfer question showed a milder version of the same effect. Its top result was an ATM ticket at distance 0.513, against 0.514 for the correct transfer tickets: "money was deducted but did not arrive" describes both problems.

This is the practical lesson. A small, general-purpose embedding model is good at paraphrases but can still be pulled by overlapping words, especially in short texts. Before relying on it, test it with real customer phrasings, and consider:

  • A stronger or domain-tuned embedding model, loaded into the database the same way.
  • Hybrid search, combining keyword and vector relevance. Oracle AI Database also supports hybrid vector indexes for this.
  • Richer ticket text, such as the agent's resolution notes, which give the model more meaning to work with than a one-line complaint.
  • Showing several top results to the support agent instead of auto-routing on the first match.

Step 4: search speed

CREATE VECTOR INDEX sem_hnsw_idx ON sem_tickets (embedding)
  ORGANIZATION INMEMORY NEIGHBOR GRAPH
  DISTANCE COSINE
  WITH TARGET ACCURACY 95;

With 2,000 tickets, a top-10 search took 1.55 ms as an exact scan and 0.82 ms with the HNSW index, which built in 1.8 seconds. At this size both are fast. The bigger cost in a real request is embedding the question itself (15.8 ms), so for interactive search, plan capacity around the model, not just the index.

Things to know before using it

  • Embedding throughput sets your load time. At about 73 tickets per second on this sandbox, a million tickets would take hours. Embed in batches, and embed new tickets as they arrive.
  • Re-embed when you change the model. Vectors from different models cannot be compared, so a model upgrade means re-embedding the whole table.
  • Duplicates fill the top 10. My generated data repeats some ticket texts, so several top results were identical. Real data has more variety, but de-duplicating similar tickets makes results more useful.
  • The data stays in the database. No ticket text was sent to an external service, which keeps the data-protection review simple.

Clean-up

DROP TABLE sem_tickets PURGE;
DROP TABLE sem_queries PURGE;
EXEC DBMS_DATA_MINING.DROP_MODEL('ALL_MINILM_L12_V2')

Summary

Oracle AI Database 26ai ran an AI embedding model inside the database and turned 2,000 bank support tickets into searchable vectors in under half a minute, with no external AI service. Semantic search understood five of six customer questions that keyword search could not match at all, with searches well under 2 ms. The sixth question showed the limit: a small general model can be pulled by shared words like "bank" and "took". Test with real customer language, and add hybrid search or a stronger model where precision matters.

Lab design, testing and all results are my own, run on an Oracle LiveLabs sandbox. 

Tamilselvan Perumal is an Oracle ACE Apprentice and Senior DBA with 12+ years in banking databases, working on database performance and benchmarking. Connect on LinkedIn.