1. Home
  2. Knowledge Base
  3. Oracle 26ai
  4. Oracle Database 23ai New Feature – DBMS_SEARCH

Oracle Database 23ai New Feature – DBMS_SEARCH

One of the new features in Oracle Database 23ai is a new PL/SQL interface called DBMS_SEARCH.

DBMS_SEARCH builds on existing Oracle Text functionality to create an index using multiple schema objects (both tables as well as views) as data sources for the index – so search across the entire database domain as opposed to a single table.

A DBMS_SEARCH index is basically a type of Oracle Text index designed for JSON data.

We can use both Oracle Text CONTAINS clause as well as JSON-specific JSON_TEXTCONTAINS for conducting search against the index.

Official documents also refer to it as “Ubiquitous database search”.

We can use the CREATE_INDEX procedure of DBMS_SEARCH to create a search index.

For example:

exec DBMS_SEARCH.CREATE_INDEX(index_name=>’PERSON_INDX’);

The index is automatically maintained as data in the base table(s) or view(s) change.

Let us look at an example of using the 23ai DBMS_SEARCH package.

Create the demo users
SQL> create user TIGER identified by Oracle_4U;

User created.

SQL> grant dba to tiger;

Grant succeeded.


SQL> create user SCOTT identified by Oracle_4U;

User created.

SQL> grant dba to scott;

Grant succeeded.
Create the demo tables
SQL>  create table tiger.person (person_id number, person_name varchar2(20), description varchar2(4000));

Table created.

SQL> create table scott.person (person_id number, person_name varchar2(20), description varchar2(4000));

Table created.

SQL> alter table tiger.person add constraint pk_person primary key (person_id);

Table altered.

SQL> alter table scott.person add constraint pk_person primary key (person_id);

Table altered.
Load demo data
SQL> insert into scott.person values (1,'GAVIN','THIS IS GAVIN IN SCOTT.PERSON TABLE');

1 row created.

SQL> insert into scott.person values (2,'SOORMA','THIS IS SOORMA IN SCOTT.PERSON TABLE');

SQL> commit;

Commit complete.

SQL> insert into tiger.person values (1,'GAVIN','THIS IS GAVIN IN TIGER.PERSON TABLE');

1 row created.

SQL> insert into tiger.person values (2,'SOORMA','THIS IS SOORMA IN TIGER.PERSON TABLE');

1 row created.

SQL> COMMIT;

Commit complete.
Create the index using DBMS_SEARCH.CREATE_INDEX

SQL> BEGIN
DBMS_SEARCH.CREATE_INDEX('PERSON_INDX');
END;
/

PL/SQL procedure successfully completed.


SQL> select object_name,object_type from user_objects where object_name='PERSON_INDX';

OBJECT_NAME OBJECT_TYPE
------------------------------ -----------------------
PERSON_INDX TABLE
PERSON_INDX TABLE PARTITION
PERSON_INDX TABLE PARTITION
PERSON_INDX TABLE PARTITION
PERSON_INDX INDEX
PERSON_INDX INDEX PARTITION
PERSON_INDX INDEX PARTITION
PERSON_INDX INDEX PARTITION

8 rows selected.

Note: a table with the same name as the index is also created.

The table is created with two JSON columns DATA and METADATA.

The METADATA column uniquely identifies each row of a particular data source, using the OWNER, SOURCE, and KEY JSON values.

SQL> desc PERSON_INDX
Name Null? Type
----------------------------------------- -------- ----------------------------
METADATA NOT NULL JSON
DATA JSON
OWNER VARCHAR2(128)
SOURCE VARCHAR2(128)
KEY VARCHAR2(1024)

SQL> select index_type,owner,ityp_owner,table_name from dba_indexes where index_name='PERSON_INDX';

INDEX_TYPE OWNER ITYP_OWNER TABLE_NAME
--------------------------- -------------------- ------------------------------ ------------
DOMAIN SCOTT CTXSYS PERSON_INDX
Add data sources to the index

The ADD_SOURCE procedure of DBMS_SEARCH adds the tables to the earlier created index as data sources.

SQL> BEGIN
DBMS_SEARCH.ADD_SOURCE('PERSON_INDX', 'SCOTT.PERSON');
DBMS_SEARCH.ADD_SOURCE('PERSON_INDX', 'TIGER.PERSON');
END;
/

PL/SQL procedure successfully completed.
Check the indexed data

Data added from the source tables is not stored in the PERSON_INDX table.

Only metadata is stored in a binary JSON column.

To view the data in human-readable format we can use the JSON_SERIALIZE function along with DBMS_SEARCH.GET_DOCUMENT procedure.

SQL> SELECT json_serialize(DBMS_SEARCH.GET_DOCUMENT('PERSON_INDX',metadata)) FROM person_indx;

JSON_SERIALIZE(DBMS_SEARCH.GET_DOCUMENT('PERSON_INDX',METADATA))
----------------------------------------------------------------------------------------------------------------
{"SCOTT":{"PERSON":{"PERSON_ID":1,"PERSON_NAME":"GAVIN","DESCRIPTION":"THIS IS GAVIN IN SCOTT.PERSON TABLE"}}}
{"SCOTT":{"PERSON":{"PERSON_ID":2,"PERSON_NAME":"SOORMA","DESCRIPTION":"THIS IS SOORMA IN SCOTT.PERSON TABLE"}}}
{"TIGER":{"PERSON":{"PERSON_ID":1,"PERSON_NAME":"GAVIN","DESCRIPTION":"THIS IS GAVIN IN TIGER.PERSON TABLE"}}}
{"TIGER":{"PERSON":{"PERSON_ID":2,"PERSON_NAME":"SOORMA","DESCRIPTION":"THIS IS SOORMA IN TIGER.PERSON TABLE"}}}


SQL> SELECT JSON_SERIALIZE(metadata) FROM PERSON_INDX;

JSON_SERIALIZE(METADATA)
---------------------------------------------------------------
{"OWNER":"SCOTT","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}
{"OWNER":"SCOTT","SOURCE":"PERSON","KEY":{"PERSON_ID":2}}
{"OWNER":"TIGER","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}
{"OWNER":"TIGER","SOURCE":"PERSON","KEY":{"PERSON_ID":2}}


SQL> SELECT json_serialize(DBMS_SEARCH.GET_DOCUMENT('PERSON_INDX', metadata) )
FROM person_indx p
WHERE p.metadata.OWNER = 'SCOTT'
AND p.metadata.SOURCE = 'PERSON'
AND p.metadata.KEY.PERSON_ID = 1;

JSON_SERIALIZE(DBMS_SEARCH.GET_DOCUMENT('PERSON_IDX',METADATA))
--------------------------------------------------------------------------------
{"SCOTT":{"PERSON":{"PERSON_ID":1,"PERSON_NAME":"GAVIN","DESCRIPTION":"THIS IS G
AVIN IN SCOTT.PERSON TABLE"}}}

SQL> col owner format a20
SQL> col source format a20
SQL> select p.metadata.OWNER, p.metadata.SOURCE, count(*)
from person_indx p
group by p.metadata.OWNER, p.metadata.SOURCE; 2 3

OWNER SOURCE COUNT(*)
-------------------- -------------------- ----------
"SCOTT" "PERSON" 2
"TIGER" "PERSON" 2
Execute queries against the indexed data

We can execute queries against the index using both the JSON_TEXTCONTAINS and CONTAINS operators

SQL> SELECT json_serialize(metadata) FROM person_indx
WHERE CONTAINS (data, 'GAVIN') > 0;

JSON_SERIALIZE(METADATA)
---------------------------------------------------------------
{"OWNER":"SCOTT","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}
{"OWNER":"TIGER","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}


SQL> SELECT json_serialize(metadata) FROM person_indx
WHERE CONTAINS (data, 'gavin') > 0;

JSON_SERIALIZE(METADATA)
---------------------------------------------------------------------
{"OWNER":"SCOTT","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}
{"OWNER":"TIGER","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}


SQL> select json_serialize(metadata) FROM person_indx
where JSON_TEXTCONTAINS (data, '$.SCOTT.PERSON', 'GAVIN');

JSON_SERIALIZE(METADATA)
--------------------------------------------------------------
{"OWNER":"SCOTT","SOURCE":"PERSON","KEY":{"PERSON_ID":1}}


SQL> SELECT json_serialize(DBMS_SEARCH.GET_DOCUMENT('PERSON_INDX',metadata)) FROM person_indx
WHERE CONTAINS (data, 'gavin') > 0;

JSON_SERIALIZE(DBMS_SEARCH.GET_DOCUMENT('PERSON_INDX',METADATA))
----------------------------------------------------------------------------------------------------------------
{"SCOTT":{"PERSON":{"PERSON_ID":1,"PERSON_NAME":"GAVIN","DESCRIPTION":"THIS IS GAVIN IN SCOTT.PERSON TABLE"}}}
{"TIGER":{"PERSON":{"PERSON_ID":1,"PERSON_NAME":"GAVIN","DESCRIPTION":"THIS IS GAVIN IN TIGER.PERSON TABLE"}}}
Updated on December 18, 2024

Was this article helpful?

Related Articles

Leave a Comment