Use Oracle Agent Memory Hybrid Search
Semantic search helps find related information even when queries use different words. Keyword search helps find exact identifiers, names, and phrases that semantic search might miss.
This article explains how to use Oracle Agent Memory hybrid search with Oracle Database.
Hybrid search helps Oracle Agent Memory find records by both meaning and exact text. It combines Oracle-managed text search with vector-based ranking, so a query can match identifiers such as issue codes, product names, and aliases while still benefiting from semantic retrieval.
In this guide, you will:
- configure an Oracle-backed client to use
SearchStrategy.HYBRID - configure keyword-only search with
SearchStrategy.KEYWORD - understand which search strategies can share the same managed schema
- add a memory that uses its own text for search
- store identifiers and aliases in memory text so users can search for them later
- search those memories by exact identifier or natural-language phrase
Note: Use hybrid search when neither semantic search nor keyword search alone provides reliable retrieval. Hybrid search is most useful when records include both descriptive content and exact terms that users need to find.
Hint: For package setup, see Get Started with Agent Memory. If you need a local Oracle database for this example, follow Run Oracle AI Database Locally.
Configure an Oracle Hybrid Search Client
Create an Oracle Agent Memory client with hybrid search enabled. The client stores records in Oracle Database and asks Oracle to use a managed hybrid vector index for search.
Use SchemaPolicy.CREATE_IF_NECESSARY when you first enable hybrid search.
This lets the SDK add the managed search columns and create the hybrid index if
they do not already exist.
Use SearchStrategy.HYBRID when you want Oracle to combine keyword and
vector ranking. Hybrid search requires an OracleDBEmbedder as the client’s
main embedder so the store and Oracle-managed hybrid vector index share
the same in-database model.
If you want text matching only, use SearchStrategy.KEYWORD instead. The
next section shows that setup.
Important: This guide requires oracleagentmemory 26.6.0 or newer.
If your managed schema was created by an older release, start the
application once with SchemaPolicy.CREATE_IF_NECESSARY. This upgrades
supported older released schemas in place and adds the search objects
required by the selected strategy.
That first upgrade may perform managed DDL and data rewrites, so treat it
as a planned migration step instead of a cheap normal startup.
After the schema is ready, you can switch back to
SchemaPolicy.REQUIRE_EXISTING for normal startup.
Development or partially updated schemas that already claim the current release shape are not completed in place; recreate them instead.
If you use SchemaPolicy.REQUIRE_EXISTING before the schema is upgraded,
client creation fails and tells you which managed search objects are
missing.
After a schema is initialized or upgraded for keyword or hybrid search,
do not reopen it with SearchStrategy.VECTOR unless you recreate the
schema or run an embedding backfill. Rows written by keyword or hybrid
clients may not contain local embeddings, so vector search could otherwise
miss records.
Warning: Creating the hybrid index for an existing schema can take time. Oracle must
scan existing stored search text and build the managed
hybrid-index text/vector state from the configured in-database model.
SchemaPolicy.CREATE_IF_NECESSARY waits for that DDL to finish before
client startup returns, so run the first hybrid upgrade as a planned
migration or maintenance operation for large schemas.
Note: When the SDK creates a managed hybrid vector index, it also creates a
DBMS_VECTOR_CHAIN vectorizer preference named by the managed schema.
The preference stores the vectorizer configuration from the configured
OracleDBEmbedder model and is expected to be lightweight metadata.
The generated preference name is deterministic for the managed schema and
follows the configured table-name prefix when it fits Oracle Text’s
preference-name limit. You can inspect preferences with Oracle Text views
such as CTX_USER_PREFERENCES and CTX_USER_PREFERENCE_VALUES.
Note: This example uses OracleDBEmbedder. Oracle uses that embedder’s
in-database model when it creates the hybrid index, so the main embedder
and the hybrid index share one DB model.
The example also uses SearchIndexSyncMode.ON_COMMIT. This keeps the
hybrid index current after each committed write, so newly added memories
are searchable immediately. Use SearchIndexSyncMode.MANUAL when you
plan to run search-index sync yourself, or SearchIndexSyncMode.AUTO
when you want Oracle to refresh the hybrid index in the background and can
tolerate search results lagging behind recent writes. This setting applies
to ongoing maintenance after the initial search index exists; it does not
make the first index build asynchronous.
import oracledb
from oracleagentmemory.core import (
MemoryExtractionConfig,
OracleAgentMemory,
SchemaPolicy,
SearchIndexSyncMode,
SearchStrategy,
)
from oracleagentmemory.core.embedders import OracleDBEmbedder
db_pool = oracledb.SessionPool(
user="YOUR DB USER",
password="YOUR DB PASSWORD",
dsn="YOUR DB CONNECT STRING",
)
db_embedder = OracleDBEmbedder(
connection=db_pool,
model="YOUR_DB_EMBEDDING_MODEL",
embedding_dimension=384,
)
memory = OracleAgentMemory(
connection=db_pool,
embedder=db_embedder,
memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
search_strategy=SearchStrategy.HYBRID,
search_index_sync=SearchIndexSyncMode.ON_COMMIT,
)
| API Reference: OracleAgentMemory | OracleDBEmbedder | SchemaPolicy | SearchStrategy | SearchIndexSyncMode |
Use Keyword Search Only
Use SearchStrategy.KEYWORD when you want search to match stored words,
identifiers, aliases, product names, or short phrases, and you do not want
vector ranking. Keyword search reads the same stored search text used by
hybrid search, but it does not use vector fusion.
Keyword search does not need a Python embedder. If the SDK needs to create
search objects for a new keyword schema, it creates an Oracle Text index over
stored search text. SearchIndexSyncMode.ON_COMMIT and
SearchIndexSyncMode.MANUAL control keyword text-index refresh.
keyword_memory = OracleAgentMemory(
connection=db_pool,
memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
search_strategy=SearchStrategy.KEYWORD,
)
The same add_memory() and search() calls shown below work with
SearchStrategy.KEYWORD. The difference is ranking: keyword search returns
records based on text matching only, while hybrid search combines text matching
with vector ranking.
| API Reference: OracleAgentMemory | SearchStrategy |
Use Compatible Search Strategies
The first time the SDK creates or upgrades the managed schema, it records how stored retrieval data is prepared for search. The recorded mode is checked every time a DB client starts. This prevents a client from using a strategy that could silently miss records.
If the requested strategy is compatible with the schema but does not match the recorded mode, the SDK emits a warning. The client can still start, but the warning helps you notice the difference and confirm that it is intentional.
SearchStrategy.VECTORuses locally stored embeddings. Do not open a keyword or hybrid schema withSearchStrategy.VECTORunless you recreate the schema or run an embedding backfill, because text-based clients may have written rows without local embeddings.SearchStrategy.KEYWORDuses stored search text only. It can create or use a keyword schema. It can also open an existing hybrid schema and use the text-only branch of the hybrid index. It does not change a hybrid schema back to keyword mode.SearchStrategy.HYBRIDuses stored search text with Oracle’s managed hybrid vector index. It can create a hybrid schema, open an existing hybrid schema, or upgrade a keyword schema whenSchemaPolicy.CREATE_IF_NECESSARYis used. Hybrid mode requires the client to use anOracleDBEmbedderas its main embedder.
Warning: The first creation of the hybrid index over existing data can be
long-running because Oracle builds the managed hybrid-index state from
stored search text. SearchIndexSyncMode controls ongoing index
maintenance after the index exists; it does not make the first build
asynchronous.
Use SchemaPolicy.CREATE_IF_NECESSARY when you intentionally move a schema
from vector to keyword or hybrid, or from keyword to hybrid. Use
SchemaPolicy.REQUIRE_EXISTING after the schema is ready and you want
startup to validate the schema without changing database objects.
| API Reference: SchemaPolicy | SearchStrategy |
Store a Searchable Memory
Start with a normal memory. With the OracleAgentMemory.add_memory() API,
Oracle uses the memory content itself as the searchable text. This is the
simplest path and is usually enough when users search for words or phrases that
already appear in the memory.
user_id = "user_123"
memory.add_memory(
"The user calls the Milan outage the renewal blocker.",
user_id=user_id,
)
API Reference: OracleAgentMemory
Store Identifiers Users May Search For
When users may search by an exact issue code, invoice number, product name, or alias, include that text in the memory you store. Hybrid search can then match the exact text and still use vector ranking for natural-language queries.
Keep the memory readable. A short sentence that includes the important identifier is often enough. In this example, the memories include issue and request identifiers that users are likely to type later.
memory.add_memory(
"The follow-up fix for the Milan outage is the edge-cluster retry patch, "
"tracked as ORA-27102.",
user_id=user_id,
)
memory.add_memory(
"The renewal request INV-48291 stays attached to the Milan blocker ORA-27102.",
user_id=user_id,
)
API Reference: OracleAgentMemory
Search by Identifier or Phrase
Use the normal search() API. Hybrid search runs behind the same Oracle
Agent Memory search interface, so you can keep using scopes, result limits, and
record type filters as usual.
The first query searches for an exact issue code stored in the memory text. The second query searches for a natural-language phrase from the same set of memories.
for query in ["ORA-27102", "renewal blocker"]:
print(f"\nSearch results for {query!r}:")
results = memory.search(
query=query,
user_id=user_id,
max_results=5,
record_types=["memory"],
)
print_search_results(results)
Note: Search result order can vary with your stored data, hybrid-index configuration, and Oracle scoring behavior. In tests or demos, check that the expected records are returned rather than relying on one exact ranking.
| API Reference: OracleAgentMemory | OracleSearchResult |
Conclusion
In this guide, you enabled Oracle-managed hybrid search, saw when to use keyword-only search, stored a regular memory, included searchable identifiers in memory text, and queried memories by both exact identifier and natural-language phrase.
After learning how to enable hybrid search in Oracle DB, you may now proceed to Stores and Schema.
Full Code
#Copyright © 2026 Oracle and/or its affiliates.
#This software is under the Apache License 2.0
#(LICENSE-APACHE or http://www.apache.org/licenses/LICENSE-2.0) or Universal Permissive License
#(UPL) 1.0 (LICENSE-UPL or https://oss.oracle.com/licenses/upl), at your option.
#Oracle Agent Memory Code Example - Oracle Hybrid Search
#-------------------------------------------------------
##Configure an Oracle hybrid search client
import oracledb
from oracleagentmemory.core import (
MemoryExtractionConfig,
OracleAgentMemory,
SchemaPolicy,
SearchIndexSyncMode,
SearchStrategy,
)
from oracleagentmemory.core.embedders import OracleDBEmbedder
db_pool = oracledb.SessionPool(
user="YOUR DB USER",
password="YOUR DB PASSWORD",
dsn="YOUR DB CONNECT STRING",
)
db_embedder = OracleDBEmbedder(
connection=db_pool,
model="YOUR_DB_EMBEDDING_MODEL",
embedding_dimension=384,
)
memory = OracleAgentMemory(
connection=db_pool,
embedder=db_embedder,
memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
search_strategy=SearchStrategy.HYBRID,
search_index_sync=SearchIndexSyncMode.ON_COMMIT,
)
##Configure an Oracle keyword search client
keyword_memory = OracleAgentMemory(
connection=db_pool,
memory_extraction_config=MemoryExtractionConfig(extract_memories=False),
schema_policy=SchemaPolicy.CREATE_IF_NECESSARY,
search_strategy=SearchStrategy.KEYWORD,
)
def print_search_results(results: list) -> None:
for result in results:
print(f"- [{result.record.record_type}] {result.content}")
##Store a basic hybrid search memory
user_id = "user_123"
memory.add_memory(
"The user calls the Milan outage the renewal blocker.",
user_id=user_id,
)
##Store identifiers users may search for
memory.add_memory(
"The follow-up fix for the Milan outage is the edge-cluster retry patch, "
"tracked as ORA-27102.",
user_id=user_id,
)
memory.add_memory(
"The renewal request INV-48291 stays attached to the Milan blocker ORA-27102.",
user_id=user_id,
)
##Search hybrid records by identifier or phrase
for query in ["ORA-27102", "renewal blocker"]:
print(f"\nSearch results for {query!r}:")
results = memory.search(
query=query,
user_id=user_id,
max_results=5,
record_types=["memory"],
)
print_search_results(results)