[Oracle Cloud]Oracle Database 23aiを使ってJSON列の類似性検索してみた。(2024/10/25)

# はじめに

Oracle Database 23ai の AI Vector Search機能を使って類似性検索をすることができます。
今回は、リレーショナル表の複数の列値からJSONを生成し、JSON列をEmbeddingし類似性検索をする簡単なテストを実施してみました。
EmbeddingモデルにはOCI Generative AIサービスのcohere.embed-multilingual-v3.0モデルを使用しました。

# 作業ステップ

- 事前作業
- JSONデータのEmbedding
- 類似性検索

# 事前作業
- 作業用データベースユーザの作成
PDBにSYSDBA権限で接続し、データベースユーザを作成し、「DB_DEVELOPER_ROLE」、「create credential」権限を付与します。

```sql
$ export NLS_LANG=American_America.AL32UTF8
$ sqlplus / as sysdba

alter session set container=pdb1;
CREATE USER IRIS identified by <password> DEFAULT TABLESPACE USERS quota unlimited on USERS;
GRANT DB_DEVELOPER_ROLE, create credential to IRIS;
```

- ネットワークACLの設定
データベースユーザーにホストに対する接続権限を付与

```sql
BEGIN
 DBMS_NETWORK_ACL_ADMIN.APPEND_HOST_ACE(
 host => '*',
 ace => xs$ace_type(privilege_list => xs$name_list('connect'),
 principal_name => 'iris',
 principal_type => xs_acl.ptype_db));
END;
/
```

- サンプル表、データの作成
作成したデータベースユーザで表を作成し、データを格納します。
今回は [Iris Dataset](https://archive.ics.uci.edu/dataset/53/iris)：あやめ（花びら／がく片の長さと幅の4項目）の表形式データセットを使用しました。

```sql
CREATE TABLE "IRIS"."IRIS" 
   (	"SEPAL_LENGTH" NUMBER, 
	"SEPAL_WIDTH" NUMBER, 
	"PETAL_LENGTH" NUMBER, 
	"PETAL_WIDTH" NUMBER, 
	"CLASS" VARCHAR2(64 BYTE) 
   );
```

- credentialの作成
OCI Generative AIサービスを利用するための credentialを作成します。
OCI CLIの構成ファイル情報を使います。

    - OCIユーザ
    - OCIDテナンシー
    - OCIDコンパートメントOCID
    - pem形式の秘密鍵(ファイルの内容を使用)
    - API Keyフィンガープリント

```sql
exec dbms_vector.drop_credential('OCI_GENAI_CRED');
declare
  jo json_object_t;
begin
  jo := json_object_t();
  jo.put('user_ocid','ocid1.user.oc1..aaaaaaaa');
  jo.put('tenancy_ocid','ocid1.tenancy.oc1..aaaaaaaa');
  jo.put('compartment_ocid','ocid1.compartment.oc1..aaaaaaaa');
  jo.put('private_key','aaaaaaaa');
  jo.put('fingerprint','aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa:aa');
  dbms_output.put_line(jo.to_string);
  dbms_vector.create_credential(
    CREDENTIAL_NAME   => 'OCI_GENAI_CRED',
    PARAMS        => json(jo.to_string));
end;
/
```

- OCI Generative AI Serviceを呼び出して、Embeddingできるか確認

credentialが正しく作成されているか確認を兼ねてdbms_vector.utl_to_embeddingsファンクションでEmbeddingを実施します。Embeddingモデルに「cohere.embed-multilingual-v3.0」を使用してみます。

    - provider : ocigenai
    - credential_name : 作成した credential
    - url : OCI Generative AI Embedding のエンドポイントURL
    - model : 使用する Embedding モデル
    - utl_to_embeddinsの引数 ：Embeddingする文字列(CLOB)とJSON形式のパラメータ値

```sql
var embed_genai_params clob;
exec :embed_genai_params := '{"provider": "ocigenai", "credential_name": "OCI_GENAI_CRED", "url": "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/embedText", "model": "cohere.embed-multilingual-v3.0"}';
select et.* from dbms_vector.utl_to_embeddings('こんにちは', json(:embed_genai_params)) et;

COLUMN_VALUE
--------------------------------------------------------------------------------
{"embed_id":"1","embed_data":"こんにちは","embed_vector":"[0.0138
32092,0.054473877,-0.003616333,-0.030853
271,0.00843811,0.0101623535,-0.020050049
<以下略>
```



# JSONデータのEmbedding

## JSON列とVECTOR列の追加

JSONを格納するIRISJSON列とEmbedding結果を格納するIRISVECTOR列を追加

```sql
alter table iris add (IRISJSON JSON);
alter table iris add (IRISVECTOR vector);
```

## 既存の列データからJSONデータの生成
既存の列値をキーと値として持つ JSONデータを生成し、追加したJSON列に値を追加します。

```sql
update iris set irisjson =  JSON_OBJECT (
         KEY 'SEPAL-LENGTH' VALUE SEPAL_LENGTH ,
         KEY 'SEPAL-WIDTH' VALUE SEPAL_WIDTH  ,
         KEY 'PETAL-LENGTH' VALUE PETAL_LENGTH   ,
         KEY 'PETAL-WIDTH' VALUE PETAL_WIDTH  
       ) ;
commit;
```

## JSON列をEmbedding
JSON列の値をEmbeddingし、値を追加したVECTOR列に追加します。

```sql
var embed_genai_params clob;
exec :embed_genai_params := '{"provider": "ocigenai", "credential_name": "OCI_GENAI_CRED", "url": "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/embedText", "model": "cohere.embed-multilingual-v3.0"}';
update iris set IRISVECTOR =  dbms_vector.utl_to_embedding(to_CLOB(IRISJSON),json(:embed_genai_params))
```

# 類似性検索
JSONデータをパラメータとして類似性検索を実施

- パラメータ値： {"SEPAL-LENGTH":5.1,"SEPAL-WIDTH":3.5,"PETAL-LENGTH":1.4,"PETAL-WIDTH":0.2} での検索

```sql
var embed_genai_params clob;
exec :embed_genai_params := '{"provider": "ocigenai", "credential_name": "OCI_GENAI_CRED", "url": "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/embedText", "model": "cohere.embed-multilingual-v3.0"}';
SELECT SEPAL_LENGTH,SEPAL_WIDTH,PETAL_LENGTH,PETAL_WIDTH,CLASS 
FROM IRIS
ORDER BY VECTOR_DISTANCE(IRISVECTOR,dbms_vector.utl_to_embedding(to_CLOB('&keyword'), json(:embed_genai_params)), EUCLIDEAN) fetch first 5 rows only;
Enter value for keyword: {"SEPAL-LENGTH":5.1,"SEPAL-WIDTH":3.5,"PETAL-LENGTH":1.4,"PETAL-WIDTH":0.2}
```

検索結果

```
SEPAL_LENGTH SEPAL_WIDTH PETAL_LENGTH PETAL_WIDTH CLASS       
------------ ----------- ------------ ----------- ----------- 
         5.1         3.5          1.4         0.2 Iris-setosa 
         5.1         3.4          1.5         0.2 Iris-setosa 
         5.1         3.5          1.4         0.3 Iris-setosa 
         5.1         3.3          1.7         0.5 Iris-setosa 
         5.1         3.7          1.5         0.4 Iris-setosa 


Elapsed: 00:00:06.666
5行が選択されました。
```

- パラメータ値： {"SEPAL-LENGTH":6.4,"SEPAL-WIDTH":2.8,"PETAL-LENGTH":5.6,"PETAL-WIDTH":2.2} での検索

```sql
var embed_genai_params clob;
exec :embed_genai_params := '{"provider": "ocigenai", "credential_name": "OCI_GENAI_CRED", "url": "https://inference.generativeai.us-chicago-1.oci.oraclecloud.com/20231130/actions/embedText", "model": "cohere.embed-multilingual-v3.0"}';
SELECT SEPAL_LENGTH,SEPAL_WIDTH,PETAL_LENGTH,PETAL_WIDTH,CLASS 
FROM IRIS
ORDER BY VECTOR_DISTANCE(IRISVECTOR,dbms_vector.utl_to_embedding(to_CLOB('&keyword'), json(:embed_genai_params)), EUCLIDEAN) fetch first 5 rows only;
Enter value for keyword: {"SEPAL-LENGTH":6.4,"SEPAL-WIDTH":2.8,"PETAL-LENGTH":5.6,"PETAL-WIDTH":2.2}
```

検索結果

```
SEPAL_LENGTH SEPAL_WIDTH PETAL_LENGTH PETAL_WIDTH CLASS           
------------ ----------- ------------ ----------- --------------- 
         6.4         2.8          5.6         2.2 Iris-virginica  
         6.4         2.8          5.6         2.1 Iris-virginica  
         6.4         3.1          5.5         1.8 Iris-virginica  
         6.4         3.2          4.5         1.5 Iris-versicolor 
         6.2         2.8          4.8         1.8 Iris-virginica  


Elapsed: 00:00:06.052
5行が選択されました。
```


# おわりに

既存の表の複数の列をJSON形式で保持し、JSON列に対してEmbedding化から類似性検索することで、幅広い場面で活用できるのではないでしょうか。

## 参考情報
- [OCI Generative AI EmbeddingモデルでOracle Database 23ai表データをEmbeddingしてみた。(2024/05/05)](https://qiita.com/kenwatan/items/d1bc626ab18628c84958)
- [Generate and Use Embeddings for End-to-End Search](https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/generate-and-use-embeddings-end-end-search.html)
- [SQL Quick Start](https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/sql-quick-start.html)