11.7.2.2 pyqEvalファンクション(Autonomous Database)

ファンクションpyqEvalは、Oracle Autonomous Databaseで使用すると、ユーザー定義Python関数をコールします。ユーザーは、ユーザー定義Python関数に引数を渡すことができます。

ファンクションpyqEvalは、データを自動的にロードしません。ユーザー定義のPython関数内では、透過層またはROracleデータベース接続を使用して、ユーザーがデータに明示的にアクセスまたは取得(あるいはその両方)できます。

構文

FUNCTION PYQSYS.pyqEval(
    PAR_LST    VARCHAR2, 
    OUT_FMT    VARCHAR2,
    SCR_NAME   VARCHAR2,
    SCR_OWNER  VARCHAR2 DEFAULT NULL,
    ENV_NAME   VARCHAR2 DEFAULT NULL
    )
    RETURN SYS.AnyDataSet

パラメータ

パラメータ 説明

PAR_LST

SCR_NAMEパラメータで指定されたユーザー定義Python関数に渡す追加パラメータが含まれるJSON文字列。oml_で始まる特殊な制御引数は、SCR_NAMEで指定された関数に渡されるのではなく、関数の呼出し前後の動作を制御します。

たとえば、入力データ型をpandas.DataFrameとして指定するには、次を使用します。

'{"oml_input_type":"pandas.DataFrame"}'

関連項目: 特殊な制御引数(Autonomous Database)

OUT_FMT

ファンクションによって返される出力の形式。次のいずれかになります。

  • ファンクションによって返された表の列名およびデータ型を指定するJSON文字列。イメージ・データは破棄されます。Python関数は、pandas.DataFramenumpy.ndarraytupleまたはtupleのリストを返す必要があります。
  • 文字列'JSON'。返される表にJSON文字列であるCLOBが含まれることを指定します。

  • 文字列'XML'。返される表にXML文字列であるCLOBが含まれることを指定します。XMLには構造化データとイメージの両方が含まれる可能性があり、最初に構造化または半構造化のPythonオブジェクトが含まれ、続いてPython関数によって生成されたイメージが含まれます。
  • 文字列'PNG'。返される表に、Python関数によって生成されたイメージを格納するBLOBが含まれることを指定します。イメージはPNG表示のbase 64エンコーディングとして返されます。

関連項目: 出力形式(Autonomous Database)

SCR_NAME

OML4Pyスクリプト・リポジトリ内のユーザー定義Python関数の名前。

SCR_OWNER

登録済Pythonスクリプトの所有者。デフォルト値はNULLです。NULLの場合、ユーザーのスクリプト・リポジトリでPythonスクリプトを検索します。

ENV_NAME

指定されたユーザー定義Python関数の実行時に使用されるconda環境の名前。

この例では、Python関数を定義し、OML4Pyスクリプト・リポジトリに格納します。ユーザー定義Python関数に対してpyqEvalファンクションをコールします。

PL/SQLブロックで、pyqFun1という名前でスクリプト・リポジトリに格納されるPython関数を作成します。

begin
    sys.pyqScriptCreate('pyqFun1',
        'def fun_tab():
                import pandas as pd
                names = ["demo_"+str(i) for i in range(10)]
                ids = [x for x in range(10)]
                floats = [float(x)/10 for x in range(10)]
                d = {''ID'': ids, ''NAME'': names, ''FLOAT'': floats}
                scores_table = pd.DataFrame(d)
                return scores_table
',FALSE,TRUE); -- V_GLOBAL, V_OVERWRITE 
end; 
/

次に、pyqEvalファンクションをコールします。これにより、ユーザー定義Python関数が実行されます。

PAR_LST引数は、特殊な制御引数oml_service_levelLOWサービス・レベルを使用することを指定します。

OUT_FMT引数で、文字列'JSON'は、返される表にJSON文字列であるCLOBが含まれることを指定します。

SCR_NAMEパラメータは、コールするPython関数としてスクリプト・リポジトリ内のpyqFun1ファンクションを指定します。

JSON出力はCLOBです。set long [length]をコールすると、詳細出力を取得できます。

set long 500
select *
    from table(pyqEval(
        par_lst => '{"oml_service_level":"LOW"}',
        out_fmt => 'JSON',
        scr_name => 'pyqFun1'));

出力は次のようになります。

NAME
----------------------------------------------------------------------
VALUE
----------------------------------------------------------------------
[{"FLOAT":0,"ID":0,"NAME":"demo_0"},{"FLOAT":0.1,"ID":1,"NAME":"demo_1
"},{"FLOAT":0.2,"ID":2,"NAME":"demo_2"},{"FLOAT":0.3,"ID":3,"NAME":"de
mo_3"},{"FLOAT":0.4,"ID":4,"NAME":"demo_4"},{"FLOAT":0.5,"ID":5,"NAME"
:"demo_5"},{"FLOAT":0.6,"ID":6,"NAME":"demo_6"},{"FLOAT":0.7,"ID":7,"N
AME":"demo_7"},{"FLOAT":0.8,"ID":8,"NAME":"demo_8"},{"FLOAT":0.9,"ID":
9,"NAME":"demo_9"}]

1 row selected.

同じpyqFun1スクリプトを起動する別の問合せを発行します。OUT_FMT引数は、構造化表の出力の列名とデータ型を含むJSON文字列を指定します。

select *
    from table(pyqEval(
        par_lst => '{"oml_service_level":"LOW"}',
        out_fmt => '{"ID":"number", "NAME":"VARCHAR2(8)", "FLOAT":"binary_double"}',
        scr_name => 'pyqFun1'));

出力は次のようになります。

ID NAME FLOAT
   0 demo_0 0.0
   1 demo_1 0.1
   2 demo_2 0.2
   3 demo_3 0.3
   4 demo_4 0.4
   5 demo_5 0.5
   6 demo_6 0.6
   7 demo_7 0.7
   8 demo_8 0.8
   9 demo_9 0.9


10 rows selected.

次のコードを使用して、Pythonバージョン3.10に基づいて"seaborn"環境を作成し、プラガブル・データベース(PDB)が所有するオブジェクト・ストレージに環境をアップロードします。

ノート:

Conda環境の作成と管理には管理権限が必要です。
create -n seaborn python=3.10 seaborn
upload seaborn --overwrite --description 'Python package for seaborn' -t python 3.10 -t
      application OML4PY

データ・ビジュアライゼーション・ライブラリの'seaborn'が環境にインストールされています。

次のコードを使用して、スクリプト'test_seaborn_noinp'を作成します。

begin
  sys.pyqScriptCreate('test_seaborn_noinp',  
  'def fun_tab():
  import seaborn as sns
  import matplotlib.pyplot as plt
  import numpy as np  
  import pandas as pd    
  data = np.random.multivariate_normal([0, 0], [[5, 2], [2, 2]], size=2000)    
  data = pd.DataFrame(data, columns=["x", "y"])    
  sns.displot(data["x"])    
  plt.title("Dist plot")    
  plt.show()
  return "hello world" ',FALSE,TRUE); -- V_GLOBAL, V_OVERWRITE
end;
/

この例では、指定されたPythonスクリプトを実行するpyqEval関数をコールします。

PAR_LST引数は、特殊な制御引数oml_graphics_flagを使用してスクリプトでレンダリングされたイメージを取得することを指定します。

OUT_FMT引数で、文字列'PNG'は、Python関数によって生成されたイメージが格納されたBLOBが含まれる表を返すことを指定します。

SCR_NAMEパラメータは、コールするPython関数としてスクリプト・リポジトリ内の'test_seaborn_noinp'スクリプトを指定します。

ENV_NAMEパラメータは、Python関数を実行するConda環境である'seaborn'を指定します。

select *
  from table(pyqEval(
        par_lst => '{"oml_graphics_flag":true}',
        out_fmt => 'PNG',
        scr_name => 'test_seaborn_noinp',
        scr_owner => NULL,
        env_name => 'seaborn'
));

出力は次のようになります。

NAME
--------------------------------------------------------------------------------
        ID
----------
VALUE
--------------------------------------------------------------------------------
TITLE
--------------------------------------------------------------------------------
IMAGE
--------------------------------------------------------------------------------

         1
"hello world"

NAME
--------------------------------------------------------------------------------
        ID
----------
VALUE
--------------------------------------------------------------------------------
TITLE
--------------------------------------------------------------------------------
IMAGE
--------------------------------------------------------------------------------
Lineplot
89504E470D0A1A0A0000000D4948445200000280000001E0080600000035D1DCE400000039744558
74536F667477617265004D6174706C6F746C69622076657273696F6E332E332E332C206874747073

NAME
--------------------------------------------------------------------------------
        ID
----------
VALUE
--------------------------------------------------------------------------------
TITLE
--------------------------------------------------------------------------------
IMAGE
--------------------------------------------------------------------------------
3A2F2F6D6174706C6F746C69622E6F72672FC897B79C000000097048597300000F6100000F6101A8
3FA7690000682C49444154789CEDDD797C5355FE3FFE579236E9BEB7E942DBB414286B0B2D94820A
4AC7023A82A2022E2C83B801A37674147F0A2EDFCF1415114719D119293AC280CC208EC8A050D984

NAME
--------------------------------------------------------------------------------
        ID
----------
VALUE
--------------------------------------------------------------------------------
TITLE
--------------------------------------------------------------------------------
IMAGE
--------------------------------------------------------------------------------

PL/SQLブロックで、Python関数create_iris_tableを定義し、create_iris_tableという名前でスクリプト・リポジトリに格納し、同じ名前でスクリプト・リポジトリに格納されている既存のユーザー定義Python関数を上書きします。

create_iris_table関数は、irisデータ・セットをインポートしてロードし、2つのpandas.DataFrameオブジェクトを作成した後、これらのオブジェクトの連結を返します。

BEGIN
    sys.pyqScriptCreate('create_iris_table',
        'def create_iris_table():
            from sklearn.datasets import load_iris
            import pandas as pd
            iris = load_iris()
            x = pd.DataFrame(iris.data, columns = ["Sepal_Length",\
                "Sepal_Width", "Petal_Length", "Petal_Width"])
            y = pd.DataFrame(list(map(lambda x: {0:"setosa", 1: "versicolor",\
                2: "virginica"}[x], iris.target)),\
                columns = ["Species"])
            return pd.concat([y, x], axis=1)',
        FALSE, TRUE); -- V_GLOBAL, V_OVERWRITE
   END;
/
CREATE TABLE IRIS AS
(SELECT * FROM pyqEval(
    NULL,
    '{"Species":"VARCHAR2(10)","Sepal_Length":"number",
      "Sepal_Width":"number","Petal_Length":"number",
      "Petal_Width":"number"}',
    'create_iris_table'
));