9.2 ユーザー定義関数と集計

RDFグラフ問合せの拡張アーキテクチャによって、ユーザー定義の関数と集計を追加して、SPARQL問合せで使用できます。これには、SEM_MATCH表関数と、support for Apache Jenaが使用されます。

SPARQL 1.1標準には、主に、問合せによって取得されるデータをフィルタ処理して分類するために使用されるいくつかの関数が用意されています。ただし、この標準ではサポートされていない特殊な関数が必要な場合があります。

簡単な例として、特定のタイプに属する値の検索、平方和の値を使用した特定のしきい値よりも大きい値の取得があります。これは、関数を組み合せることで実行することはできますが、この計算を処理する単一の関数があると、問合せをより簡単に短くすることができて有用です。

RDFグラフ問合せの拡張機能によって、独自の問合せ関数と集計を含めることができます。このアーキテクチャにより、次のことが可能になっています。

9.2.1 ユーザー定義関数と集計のデータ型

ユーザー定義関数と集計を作成するとき、RDF語句を表現するためにSDO_RDF_TERMオブジェクト型が使用されます。

SDO_RDF_TERMには次の属性があり、RDF_VALUE$表の列に対応しています(これらの属性については、表1-5を参照してください)。CTX1属性とFLAGS属性は、将来使用するために予約されており、RDF_VALUE$内に対応する列はありません。

SDO_RDF_TERM(
  VALUE_TYPE    VARCHAR2(10),
  VALUE_NAME    CLOB, 
  VNAME_PREFIX  CLOB,
  VNAME_SUFFIX  VARCHAR2(512), 
  LITERAL_TYPE  VARCHAR2(1000), 
  LANGUAGE_TYPE VARCHAR2(80), 
  LONG_VALUE    CLOB, 
  CTX1          VARCHAR2(4000),
  FLAGS         INTEGER )

SDO_RDF_TERMオブジェクトの作成には、次のコンストラクタが使用可能です。1つ目のコンストラクタは、単一の字句RDF語句文字列から、各属性を移入します。2番目、3番目および4番目のコンストラクタは、個別の属性値を入力として受け取ります。1番目のRDF語句文字列コンストラクタのみが、VNAME_PREFIXとVNAME_SUFFIXの値を設定します。これらの値は、他のコンストラクタによってNULLに初期化されます。

SDO_RDF_TERM (
  rdf_term_str  VARCHAR2) 
  RETURN SELF;

SDO_RDF_TERM (
  value_type    VARCHAR2, 
  value_name    VARCHAR2, 
  literal_type  VARCHAR2, 
  language_type VARCHAR2, 
  long_value    CLOB) 
  RETURN SELF;

SDO_RDF_TERM (
  value_type    VARCHAR2, 
  value_name    VARCHAR2, 
  literal_type  VARCHAR2, 
  language_type VARCHAR2, 
  long_value    CLOB, 
  ctx1          VARCHAR2) 
  RETURN SELF;

SDO_RDF_TERM (
  value_type    VARCHAR2, 
  value_name    VARCHAR2, 
  literal_type  VARCHAR2, 
  language_type VARCHAR2, 
  long_value    CLOB, 
  ctx1          VARCHAR2,
  flags         INTEGER) 
  RETURN SELF;

SDO_RDF_TERMオブジェクトのリストを格納するために、SDO_RDF_TERM_LIST型が使用され、VARRAY(32767) of SDO_RDF_TERMとして定義されます。

9.2.2 ユーザー定義関数のAPIサポート

ユーザー定義関数は、特定のシグネチャを使用したPL/SQL関数を実装することによって作成され、固有のURIを使用してSPARQL問合せパターンで起動されます。

推論拡張関数コールが正常に実行された後、推論拡張関数で行われた変更を保持するために、コミットが実行されます。pragma autonomous_transactionを指定することによって、推論拡張関数が自律型として定義した場合、実装ロジックの最後で、コミットまたはロールバックする必要があります。推論エンジンでは、推論グラフの作成時(1ラウンドにつき1回)に、拡張関数を複数回コールする場合があることに注意してください。あるコールのコミットおよびロールバックは、他のコールには影響しません。

9.2.2.1 PL/SQL関数の実装

各ユーザー定義関数は、次の形式のシグネチャを持つPL/SQL関数によって実装される必要があります。

FUNCTION user_function_name (params IN SDO_RDF_TERM_LIST)
  RETURN SDO_RDF_TERM

このシグネチャは任意の数のRDF語句引数(単一のSDO_RDF_TERM_LISTオブジェクトを使用する際に渡される)をサポートし、単一のRDF語句(単一のSDO_RDF_TERMオブジェクトとして表現される)を出力として戻します。これらのパラメータの型チェックまたは他の検証は、実行されません。関数の用途に従ってデータを検証するためのステップを実行する必要があります。

CやJavaなど、他のプログラミング言語で記述された関数に対して、PL/SQLからのコールアウトがサポートされているため、ユーザー定義の問合せ関数を実装するPL/SQL関数は、他のプログラミング言語で記述された関数のラッパーとしてのみ機能します。

9.2.2.2 SPARQL問合せパターンからのユーザー定義関数の起動

これは、ユーザー定義関数がPL/SQLで実装された後、接頭辞<http://xmlns.oracle.com/rdf/extensions/>の後にschema.package_name.function_nameが続く関数URI(対応するPL/SQL関数がPL/SQLパッケージの一部である場合)、またはschema.function_nameが続く関数URI(関数がPL/SQLパッケージの一部でない場合)を使用して、SPARQL問合せパターンから起動することができます。次の2つは、関数URIの例です。

<http://xmlns.oracle.com/rdf/extensions/my_schema.my_package.my_function>(arg_1, …, arg_n)

<http://xmlns.oracle.com/rdf/extensions/my_schema.my_function>(arg_1, …, arg_n)

9.2.2.3 ユーザー定義関数の例

この項では、ユーザー定義関数の実装例と、その関数のFILTER句、SELECT式およびBIND演算での使用について示します。

たとえば、ここではN-triple形式で示されている次のデータが、MYMODELと呼ばれるモデル内に存在しているとします。

<a>  <p>  "1.0"^^xsd:double .
<b>  <p>  "1.5"^^xsd:float .
<c>  <p>  "3"^^xsd:decimal .
<d>  <p>  "4"^^xsd:string .

例9-1 2つの平方和を計算するユーザー定義関数

例9-1は、2つの値を受け取って各値の平方和を計算する、単純なファンクションの実装を示しています。

CREATE OR REPLACE FUNCTION sum_squares (params IN SDO_RDF_TERM_LIST) 
   RETURN SDO_RDF_TERM
   AS 
     retTerm    SDO_RDF_TERM;
     sqr1       NUMBER;
     sqr2       NUMBER;
     addVal     NUMBER;
     val1       SDO_RDF_TERM;
     val2       SDO_RDF_TERM;
   BEGIN 
     –- Set the return value to null.
     retTerm := SDO_RDF_TERM(NULL,NULL,NULL,NULL,NULL);
     –- Obtain the data from the first two parameters.
     val1 := params(1); 
     val2 := params(2);
     –- Convert the value stored in the sdo_rdf_term to number.
     –- If any exception occurs, return the null value.
     BEGIN
       sqr1 := TO_NUMBER(val1.value_name);
       sqr2 := TO_NUMBER(val2.value_name);
       EXCEPTION WHEN OTHERS THEN RETURN retTerm;
     END;
     –- Compute the square sum of both values.
       addVal := (sqr1 * sqr1) + (sqr2 * sqr2);
     –- Set the return value to the desired rdf term type.
     retTerm := SDO_RDF_TERM('LIT',to_char(addVal),
                'http://www.w3.org/2001/XMLSchema#integer','',NULL);
     – Return the new value.
     RETURN retTerm;
END;
/
SHOW ERRORS;

例9-1 sum_squaresファンクションでは、受け取った値のデータ型を検証しません。これはあくまでも例であり、SDO_RDF_TERMのVALUE_NAMEフィールドに格納されている数値の取得には、TO_NUMBERを使用します。

例9-2 FILTER句で使用されるユーザー定義関数

例9-2は、FILTER句で使用されるsum_squaresファンクション(例9-1)を示します。

SELECT s, o
FROM table(sem_match(
'SELECT  ?s ?o
 WHERE { ?s ?p ?o 
 FILTER (<http://xmlns.oracle.com/rdf/extensions/schema.sum_squares>(?o,?o) > 2)}',
sem_models('MYMODEL'),null,null,null,null,'',null,null,'RDFUSER','NET1'));

例9-2の問合せは、次の結果を戻します。

s                    o                    
-------------------- -------------------- 
b                    1.5
c                    3                  
d                    4

例9-3 SELECT式で使用されるユーザー定義関数

例9-3は、SELECT句の式で使用されるsum_squaresファンクション(例9-1)を示します。

SELECT s, o, sqr_sum
FROM table(sem_match(
'SELECT  ?s ?o 
       (<http://xmlns.oracle.com/rdf/extensions/schema.sum_squares>(?o,?o) AS    
        ?sqr_sum)
 WHERE { ?s ?p ?o }',
sem_models('MYMODEL'),null,null,null,null,'',null,null,'RDFUSER','NET1'));

例9-3の問合せは、次の結果を戻します。

s                    o                    sqr_sum
-------------------- -------------------- -------------------- 
a                    1                    2
b                    1.5                  4.5
c                    3                    18
d                    4                    32

例9-4 BIND演算で使用されるユーザー定義関数

例9-4は、BIND演算で使用されるsum_squaresファンクション(例9-1)を示します。

SELECT s, o, sqr_sum
FROM table(sem_match(
'SELECT  ?s ?o ?sqr_sum
 WHERE { ?s ?p ?o .
 BIND (<http://xmlns.oracle.com/rdf/extensions/schema.sum_squares>(?o,?o) AS
       ?sqr_sum)}',
sem_models('MYMODEL'),null,null,null,null,'',null,null,'RDFUSER','NET1'));

例9-4の問合せは、次の結果を戻します。

s                    o                    sqr_sum
-------------------- -------------------- -------------------- 
a                    1                    2
b                    1.5                  4.5
c                    3                    18
d                    4                    32

9.2.3 ユーザー定義の集計のAPIサポート

ユーザー定義の集計は、一連のインタフェース・メソッドを実装するPL/SQLオブジェクト型を定義することによって実装されます。ユーザー定義の集計を作成したら、固有のURIを使用してそれを起動します。

9.2.3.1 ODCIAggregateインタフェース

ユーザー定義の集計では、ODCIAggregate PL/SQLインタフェースを使用します。このインタフェースの詳細は、Oracle Databaseデータ・カートリッジ開発者ガイドのユーザー定義集計関数に関する章を参照してください。

ODCIAggregateインタフェースは、4つの主要な関数を実装するPL/SQLオブジェクト型によって実装されます。

  • ODCIAggregateInitialize

  • ODCIAggregateIterate

  • ODCIAggregateMerge

  • ODCIAggregateTerminate

ユーザー定義関数(「ユーザー定義関数のAPIサポート」を参照)と同様に、ユーザー定義の集計は、SDO_RDF_TERM_LISTオブジェクトとして渡される任意の数のRDF語句引数を受け取り、SDO_RDF_TERMオブジェクトとして表現される単一のRDF語句の値を返します。

このスキームによって、PL/SQL ODCIAggregateインタフェース関数のシグネチャは、次のようになります(my_aggregate_obj_typeは実際のオブジェクト・タイプ名)。

STATIC FUNCTION ODCIAggregateInitialize(
        sctx IN OUT my_aggregate_obj_type)
RETURN NUMBER
 
MEMBER FUNCTION ODCIAggregateIterate(
        self       IN OUT my_aggregate_obj_type
       ,value      IN     SDO_RDF_TERM_LIST)
RETURN NUMBER
 
MEMBER FUNCTION ODCIAggregateMerge(
        self IN OUT my_aggregate_obj_type
       ,ctx2 IN     my_aggregate_obj_type)
RETURN NUMBER
 
MEMBER FUNCTION ODCIAggregateTerminate (
        self IN my_aggregate_obj_type
       ,return_value OUT SDO_RDF_TERM
       ,flags IN NUMBER)              
RETURN NUMBER

9.2.3.2 ユーザー定義の集計の起動

これは、ユーザー定義の集計がPL/SQLで実装された後、接頭辞<http://xmlns.oracle.com/rdf/aggExtensions/>の後にschema_name.aggregate_nameを続けて構築される集計URIを参照することによって、SPARQL問合せから起動することができます。集計URIの例は次のとおりです。

<http://xmlns.oracle.com/rdf/aggExtensions/schema.my_aggregate>(arg_1, …, arg_n)

DISTINCT修飾子は、ユーザー定義の集計で次の例のように使用できます。

<http://xmlns.oracle.com/rdf/aggExtensions/schema.my_aggregate>(DISTINCT arg_1)

この場合、distinct引数の値のみが集計に渡されます。ただしDISTINCT修飾子は、厳密に1つの引数の集計でのみ使用できることに注意してください。

9.2.3.3 ユーザー定義の集計の例

この項では、ユーザー定義の集計を実装して使用する例を示します。たとえば、ここではN-triple形式で示されている次のデータが、MYMODELと呼ばれるモデル内に存在しているとします。

<a>  <p>  "1.0"^^xsd:double .
<b>  <p>  "1.5"^^xsd:float .
<c>  <p>  "3"^^xsd:decimal .
<c>  <p>  "4"^^xsd:decimal .
<d>  <p>  "4"^^xsd:string .

例9-5 ユーザー定義の集計の実装

例9-5は、単純なユーザー定義の集計の実装(countSameType)を示しています。この集計には2つの引数があり、1番目は任意のRDF語句、2番目は定数のデータ型URIです。集計は、1番目の引数の位置からのRDF語句にある、2番目の引数と等しいデータ型の数をカウントします。

-- Aggregate type creation
CREATE OR REPLACE TYPE countSameType authid current_user AS OBJECT(
 
count NUMBER, –- Variable to store the number of same-type terms.
 
–- Mandatory Functions for aggregates 
STATIC FUNCTION ODCIAggregateInitialize(
        sctx IN OUT countSameType)
RETURN NUMBER,
 
MEMBER FUNCTION ODCIAggregateIterate(
         self       IN OUT countSameType
       , value      IN     SDO_RDF_TERM_LIST)
RETURN NUMBER,
 
MEMBER FUNCTION ODCIAggregateMerge(
        self IN OUT countSameType
       ,ctx2 IN     countSameType)
RETURN NUMBER,
 
MEMBER FUNCTION ODCIAggregateTerminate (
        self IN          countSameType
       ,return_value OUT SDO_RDF_TERM
       ,flags IN NUMBER)              
RETURN NUMBER
);
/
SHOW ERRORS;
 
–- Interface function for the user-defined aggregate
CREATE OR REPLACE FUNCTION countSameAs (input SDO_RDF_TERM_LIST) RETURN SDO_RDF_TERM
PARALLEL_ENABLE AGGREGATE USING countSameType;
/
show errors;
 
–- User-defined aggregate body
CREATE OR REPLACE TYPE BODY countSameType IS
 
STATIC FUNCTION ODCIAggregateInitialize(
         sctx            IN OUT countSameType)
RETURN NUMBER IS
BEGIN
  sctx := countSameType (0); –- Aggregate initialization
  RETURN ODCIConst.Success;
END;
 
MEMBER FUNCTION ODCIAggregateIterate(
         self           IN OUT countSameType
       , value          IN     SDO_RDF_TERM_LIST )
RETURN NUMBER IS
BEGIN
  -- Increment count if the first argument has a literal type
  -- URI equal to the value of the second argument
  IF (value(1).literal_type = value(2).value_name) THEN
    self.count := self.count + 1;
  END IF;                                    
  RETURN ODCIConst.Success;
END;   
 
MEMBER FUNCTION ODCIAggregateMerge(
         self            IN OUT countSameType
        ,ctx2            IN countSameType)
RETURN NUMBER IS
BEGIN
  –- Sum count to merge parallel threads.
  self.count := self.count + ctx2.count;   
  RETURN ODCIConst.Success;
END;
 
MEMBER FUNCTION ODCIAggregateTerminate(
         self            IN  countSameType
        ,return_value    OUT SDO_RDF_TERM
        ,flags           IN  NUMBER)              
RETURN NUMBER IS
BEGIN
   -- Set the return value
   return_value := SDO_RDF_TERM('LIT',to_char(self.count),
     'http://www.w3.org/2001/XMLSchema#decimal',NULL,NULL); RETURN  ODCIConst.Success;
END;
 
END;
/
SHOW ERRORS;

例9-6 GROUP BY句なしで使用されるユーザー定義の集計

例9-6は、問合せ結果のすべてのグループに使用されるcountSameType集計(例9-5)を示しています。

FROM o
from table(sem_match(
'SELECT 
 (<http://xmlns.oracle.com/rdf/aggExtensions/schema.countSameType>(?o,xsd:decimal) 
  AS ?o)
 WHERE { ?s ?p ?o }',
sem_models('MYMODEL'),null,null,null,null,'',null,null,'RDFUSER','NET1'));

例9-6の問合せは、次の結果を戻します。

o                    
-------------------- 
2                    

例9-7 GROUP BY句とともに使用されるユーザー定義の集計

例9-7は、GROUP BY句から形成される一連のグループに使用されるcountSameType集計(例9-5)を示しています。

select s, o
from table(sem_match(
'SELECT ?s
 (<http://xmlns.oracle.com/rdf/aggExtensions/schema.countSameType>(?o,xsd:decimal) 
  AS ?o)
 WHERE { ?s ?p ?o } GROUP BY ?s',
sem_models('MYMODEL'),null,null,null,null,'',null,null,'RDFUSER','NET1'));

例9-7の問合せは、次の結果を戻します。

s                    o                    
-------------------- -------------------- 
a                    0
b                    0
c                    2                    
d                    0