[Oracle Database 23ai] 特徴抽出アルゴリズムを使用してリレーショナル表データをEmbeddingしてみた。(2024/12/06)

# はじめに

以前、[こちら](https://qiita.com/kenwatan/items/c130ee6ab04718931643)の記事で、リレーショナル表の複数の列値からJSONを生成し、JSON列をEmbeddingし類似性検索をする簡単なテストを実施してみました。
Oracle Database 23ai の2024年10月のアップデートでOracle Machine Learning (OML)の特徴抽出アルゴリズムとVECTOR_EMBEDDING() SQL演算子によりリレーショナル表データをEmbeddingすることが可能になりました。
今回、OMLアルゴリズムとVECTOR_EMBEDDING() SQL演算子によるEmbeddingをしてみました。

# 作業ステップ

- 事前作業
- OMLモデルを作成
- VECTOR_EMBEDDING()関数を使用して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項目）の表形式データセットを使用しました。
主キー列として ID列を追加しました。

```sql
CREATE TABLE "IRIS"."IRIS" 
   (	
    "ID" NUMBER primary key,
	"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
<以下略>
```


# OMLモデルを作成

特徴抽出アルゴリズムは、データから最も有益な特徴(=列)を抽出するのに役立ちます。
最もデータの特徴を表す列を識別することで、列数の多い表からディメンションを削減することで、最も重要な情報を保持しながらデータ・セットが簡略化され、データの相関および冗長性の分析が容易になります。

機械学習で広く使用されているディメンション削減技術である主成分分析(PCA)アルゴリズムを使用します。

### SVDアルゴリズムを構成
主成分分析(PCA)を実行するためのSVD(特異値分解：singular value decomposition)の構成します。

設定表(mod_sett)を作成し、パラメータをセット

```sql
CREATE TABLE mod_sett(
  setting_name  VARCHAR2(30),
  setting_value VARCHAR2(30)
);


BEGIN
-- 特徴抽出アルゴリズムalgo_singular_value_decompを指定
  INSERT INTO mod_sett (setting_name, setting_value) VALUES (dbms_data_mining.algo_name, dbms_data_mining.algo_singular_value_decomp);
-- データ準備の自動化をオン オンにするとモデルはヒューリスティックを使用してビルドデータを変換する
  INSERT INTO mod_sett (setting_name, setting_value) VALUES (dbms_data_mining.prep_auto, dbms_data_mining.prep_auto_on);
-- ビルドデータのスコアリングモードをPCAに設定　投影がU行列とS行列の積になる
  INSERT INTO mod_sett (setting_name, setting_value) VALUES (dbms_data_mining.svds_scoring_mode, dbms_data_mining.svds_scoring_pca);
--　抽出される特徴の数を設定(例として、4)
  INSERT INTO mod_sett (setting_name, setting_value) VALUES (dbms_data_mining.feat_num_features, 4);
  commit;
END;
/
```

### モデルの作成

設定表を指定して、IRIS表に対する特徴抽出のモデルを作成します。

```sql
BEGIN
  DBMS_DATA_MINING.CREATE_MODEL(
    model_name          => 'pcamodel',		-- モデルの名前
    mining_function     => dbms_data_mining.feature_extraction,	-- マイニング機能の設定　ここでは特徴抽出モデルを指定
    data_table_name     => 'iris',		-- 対象表の指定
    case_id_column_name => 'id',		-- キーとなる列
    settings_table_name => 'mod_sett');  	--設定表の指定
END;
/
```




# VECTOR_EMBEDDING()関数を使用してEmbedding

### 作成したモデル ( pcamodel )を使用して、IRIS表のID＝1の特徴量をEmbedding

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

```sql
SELECT id, vector_embedding(pcamodel USING *) embedding
FROM iris
WHERE id=1;

            ID      EMBEDDING
--------------     --------------------------------------------------
             1      [-2.3551013972411354E+002,2.8160084506788273E+001,
                     5.2821278275005774E+001,-1.8960922352439308E-002,
                    -2.5441143639048378E+000]
```

### 特徴量(列)の確認

feature_details関数でEmbeddingに影響ある特徴量(列)を確認

```sql
SELECT feature_details(pcamodel, 4 USING *) features
FROM iris
WHERE id=1;

<Details algorithm="Singular Value Decomposition" feature="4">
<Attribute name="SEPAL_WIDTH" actualValue="3.5" weight=".19" rank="1"/>
<Attribute name="PETAL_LENGTH" actualValue="1.4" weight=".188" rank="2"/>
<Attribute name="PETAL_WIDTH" actualValue=".2" weight=".166" rank="3"/>
<Attribute name="SEPAL_LENGTH" actualValue="5.1" weight="-.456" rank="4"/>
</Details>
```


### Embedding結果を表に格納

作成したモデルpcamodelを使用して、IRIS表のEmbedding結果をIRIS_EMBEDD表に格納

```sql
CREATE TABLE IRIS_EMBEDD AS
(SELECT id, vector_embedding(pcamodel USING *) embedding
 FROM iris);
```

# 類似性検索

- ID=1のデータをインプットに {"SEPAL-LENGTH":5.1,"SEPAL-WIDTH":3.5,"PETAL-LENGTH":1.4,"PETAL-WIDTH":0.2} 類似性検索

```sql
SELECT p.id id, b.SEPAL_WIDTH SEPAL_WIDTH, b.SEPAL_LENGTH SEPAL_LENGTH, b.PETAL_WIDTH PETAL_WIDTH, 
    b.PETAL_LENGTH PETAL_LENGTH,b.class class
FROM IRIS_EMBEDD p, iris b
WHERE p.id <> 1 AND p.id=b.id
ORDER BY VECTOR_DISTANCE(embedding, (select embedding from IRIS_EMBEDD where id=1), COSINE)
FETCH APPROXIMATE FIRST 3 ROWS ONLY;



```

検索結果

```
        ID SEPAL_WIDTH SEPAL_LENGTH PETAL_WIDTH PETAL_LENGTH CLASS                                                           
---------- ----------- ------------ ----------- ------------ ----------------------------------------------------------------
        18         3.5          5.1          .3          1.4 Iris-setosa                                                     
         5         3.6            5          .2          1.4 Iris-setosa                                                     
        29         3.4          5.2          .2          1.4 Iris-setosa                                                     

```

# おわりに

Oracle Machine Learningが提供する主成分分析 SVDアルゴリズムを使ってより特徴を捉える列を特定してEmbedding化し類似性検索することが簡単にできるようになりました。
手軽に構成することができるようになり、より幅広い場面で活用できるのではないでしょうか。

## 参考情報
- [SQL Quick Start](https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/sql-quick-start.html)
- [OCI Generative AI EmbeddingモデルでOracle Database 23ai表データをEmbeddingしてみた。(2024/05/05)](https://qiita.com/kenwatan/items/d1bc626ab18628c84958)
- [Vectorize Relational Tables Using OML Feature Extraction Algorithms](https://docs.oracle.com/en/database/oracle/oracle-database/23/vecse/vectorize-relational-tables-using-oml-feature-extraction-algorithms.html#GUID-DB1E43F3-699D-4739-AB33-34E66F0B3726)