★PostgreSQLカンファレンス2024 12月6日開催/チケット販売中★
他のバージョンの文書 16 | 15 | 14 | 13 | 12 | 11 | 10 | 9.6 | 9.5 | 9.4 | 9.3 | 9.2 | 9.1 | 9.0 | 8.4 | 8.3 | 8.2 | 8.1 | 8.0 | 7.4 | 7.3 | 7.2

70.3. 拡張性

GINインタフェースは高度に抽象化されています。 アクセスメソッド実装者に要求されることは、アクセスするデータ型の意味を実装することだけです。 GIN層自体が同時実行性、ログ処理、ツリー構造の検索処理に関する面倒を見ます。

GINアクセスメソッドを動作させるために必要なことは、少数のユーザ定義関数を実装することだけです。 これは、ツリー内のキーの動作とキーとインデックス付けされる項目、インデックス可能な問い合わせ間の関係を定義します。 すなわち、GINは、一般化、コード再利用、整理されたインタフェースによる拡張性を組み合わせます。

GIN用の演算子クラスが提供しなければならないメソッドは2つあります。

Datum *extractValue(Datum itemValue, int32 *nkeys, bool **nullFlags)

インデックス対象値に与えられる、pallocで割り当てられたキーの配列を返します。 返されるキーの数は*nkeysに格納しなければなりません。 キーのいずれかがNULLになるかもしれない場合、*nkeys個のboolの配列をpallocで割り当てそのアドレスを*nullFlagsに格納し、必要に応じてNULLフラグを設定してください。 すべてのキーが非NULLであれば、*nullFlagsNULL(初期値)のままにすることができます。 項目がキーを含まない場合、戻り値はNULLになるかもしれません。

Datum *extractQuery(Datum query, int32 *nkeys, StrategyNumber n, bool **pmatch, Pointer **extra_data, bool **nullFlags, int32 *searchMode)

問い合わせ対象の値に与えられる、pallocで割り当てられたキーの配列を返します。 つまり、queryはインデックス可能な演算子の右辺の値です。 この左辺はインデックス対象の列です。 nは演算子クラス内の演算子の戦略番号です(38.16.2を参照)。 extractQueryはしばしば、queryのデータ型とキー値を抽出するために使用しなければならないメソッドを決定するために、nを調べなければなりません。 返されるキーの数を*nkeysに格納しなければなりません。 キーのいずれかがNULLとなる可能性がある場合はまた、*nkeys個のboolの配列をpallocで割り当て、*nullFlagsにそのアドレスを格納し、必要に応じてNULLフラグを設定してください。 すべてのキーが非NULLならば*nullFlagsNULL(初期値)のままにしておくことができます。 queryがキーを含まない場合、戻り値をNULLにすることができます。

searchModeは出力引数です。 これによりextractQueryは検索がどのように行われるかの詳細を指定することができます。 *searchModeGIN_SEARCH_MODE_DEFAULT(呼び出し前にこの値に初期化されます。)に設定された場合、返されるキーの少なくとも1つに一致する項目が合致候補とみなされます。 *searchModeGIN_SEARCH_MODE_INCLUDE_EMPTYに設定された場合、少なくとも1つの一致するキーを含む項目に加え、キーをまったく含まない項目が合致候補とみなされます。 (このモードは例えば何のサブセットかを求める演算子を実装する際に有用です。) *searchModeGIN_SEARCH_MODE_ALLに設定された場合、返されるキーのいずれかに一致するかどうかは関係なく、インデックス内の非NULLの項目すべてが合致候補とみなされます。 (このモードは、基本的にインデックス全体のスキャン処理が必要ですので、他の2つの選択肢と比べてかなり低速になります。 しかし境界条件を正確に実装するためにこれが必要になるかもしれません。 おそらく、このモードを必要とする演算子はほとんどの場合、GIN演算子クラス向けに優れた候補ではありません。) このモードを設定するために使用する記号はaccess/gin.hで定義されています。

pmatchは部分一致が提供されている場合に使用する出力引数です。 使用するには、extractQuery*nkeys個のboolの配列を割り当て、そのアドレスを*pmatchに格納しなければなりません。 関連するキーが部分一致を必要とするとき、それぞれの配列要素は真に、そうでなければ偽に設定されなければなりません。 *pmatchNULLに設定されている場合、GINは部分一致が必要ないと想定します。 呼び出し前に変数はNULLに初期化されますので、この引数は部分一致が提供されていない演算子クラスでは、単に無視できます。

extra_dataは、extractQueryconsistentcomparePartialメソッドに追加データを渡すことができるようにする出力引数です。 使用するには、extractQuery*nkeysポインタの配列を割り当て、そのアドレスを*extra_dataに格納し、そして望まれるものは何でも個別のポインタに格納しなければなりません。 変数は呼び出し前にNULLに初期化されますので、追加データを必要としない演算子クラスでこの引数は単に無視できます。 もし*extra_dataが設定されれば、配列全部がconsistentメソッドに、適切な要素がcomparePartialメソッドに渡されます。

演算子クラスは、インデックス付けされた項目が問い合わせに一致するか確認する関数も提供しなければなりません。 それは2つの方法で行なわれます。 2値のconsistent関数と3値のtriConsistent関数です。 triConsistentが両方の機能を含みますので、triConsistentだけを提供しても十分です。 しかし、2値の亜種を計算するのが著しく安価であれば、両方を提供することは役に立つかもしれません。 2値の亜種のみが提供されていれば、すべてのキーを取得する前にインデックス項目が一致しないことを確認することに基づく最適化の中には無効となるものもあります。

bool consistent(bool check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], bool *recheck, Datum queryKeys[], bool nullFlags[])

インデックス付けられた項目が戦略番号nを持つ問い合わせ演算子を満たす(または、recheck印が返されたときはたぶん満たすかもしれない)場合に真を返します。 GINは項目を明示的に格納しませんので、この関数はインデックス付けされた項目の値に直接アクセスすることができません。 どちらかというと、この問い合わせから取り出される指定された問い合わせで現れるキー値に関する知識が利用できるものです。 check配列は長さnkeysであり、このqueryデータに対して事前に行われたextractQueryが返したキーの数と同じです。 インデックス対象の項目が対応する問い合わせキーを持つ場合、check配列の各要素は真です。 つまり、(check[i] == true)の場合、extractQueryの結果配列のi番目のキーがインデックス対象項目内に存在します。 元のqueryデータは、consistentメソッドがそれを調査する必要がある場合に、渡されます。 このためqueryKeys[]およびnullFlags[]は事前にextractQueryによって返されます。 extra_dataextractQueryにより返された追加データ配列で、ない場合はNULLです。

extractQueryqueryKeys[]内でNULLキーを返す時、インデックス対象項目がNULLキーを含む場合は対応するcheck[]要素は真です、 つまり、check[]の意味はIS NOT DISTINCT FROMのようなものです。 consistent関数は、通常の値の合致とNULL合致との違いを通知する必要がある場合、対応するnullFlags[]要素を検査することができます。

成功の場合、*recheckは、問い合わせ演算子に対してヒープタプルを再検査する必要があればtrue、インデックス検査が的確であればfalseに設定する必要があります。 つまり、falseの戻り値はヒープタプルが問い合わせに一致しないことを保証します。 trueの戻り値で、*recheckがfalseに設定された場合はヒープタプルが問い合わせに一致することを保証します。 trueの戻り値で、*recheckがtrueに設定された場合はヒープタプルが問い合わせに一致する可能性があることを意味します。 したがって、それを取り出し、元のインデックス付けされた項目を直接問い合わせ演算子で評価することで再検査する必要があることを意味します。

GinTernaryValue triConsistent(GinTernaryValue check[], StrategyNumber n, Datum query, int32 nkeys, Pointer extra_data[], Datum queryKeys[], bool nullFlags[])

triConsistentconsistentと似ていますが、checkベクターの論理値の代わりに、各キーに対して3つの可能な値があります。GIN_TRUEGIN_FALSEGIN_MAYBEです。 GIN_FALSEGIN_TRUEは通常の論理値と同じ意味であり、GIN_MAYBEはそのキーの存在が分からないこと意味します。 GIN_MAYBE値があれば、インデックス項目が対応する問い合わせキーを含むかどうかに関わらず、項目が確実に一致する場合にのみ関数はGIN_TRUEを返すべきです。 同様に、GIN_MAYBEを含むかどうかに関わらず項目が確実に一致しない場合にのみ関数はGIN_FALSEを返さなければなりません。 結果がGIN_MAYBE項目に依存する、すなわち、分かっている問い合わせキーに基づいて、一致することもしないことも確認できない場合には、関数はGIN_MAYBEを返さなければなりません。

checkベクターにGIN_MAYBE値がなければ、GIN_MAYBE戻り値は論理値のconsistent関数でrecheckフラグを設定することと同じです。

さらに、GINにはインデックス内に格納されているキー値をソートする方法がなければなりません。 演算子クラスは比較メソッドを指定することでソート順を定義できます。

int compare(Datum a, Datum b)

キー(インデックス付けされる項目ではありません)を比較し、0より小さい、0、または0より大きい整数を返します。 それぞれ、最初のキーが2番目のキーより、小さい、等しい、または大きいことを示します。 NULLキーがこの関数に渡されることはありません。

あるいは、演算子クラスがcompareメソッドを提供しない場合には、GINはそのインデックスキーデータ型に対するデフォルトのbtree演算子クラスを探し、その比較関数を使います。 btree演算子クラスを探すのは処理に多少掛かりますので、GIN演算子クラスの中で比較関数を指定することを勧めます。それはただ一つのデータ型に対するものであることを意味します。 しかし、(array_opsのような)多様GIN演算子クラスでは、通常は単一の比較関数を指定できません。

省略可能ですが、GINに対する演算子クラスは以下のメソッドを提供します。

int comparePartial(Datum partial_key, Datum key, StrategyNumber n, Pointer extra_data)

問い合わせキーとインデックスキーの部分一致を比較します。 符号が結果を示す整数が返ります。 ゼロ未満はインデックスキーは問い合わせに一致しないが、インデックススキャンを続けるべきであることを示します。 ゼロはインデックスキーが問い合わせに一致することを示します。 ゼロより大きな値はこれ以上の一致はありえないためインデックススキャンを停止すべきであることを示します。 スキャンをいつ停止するかを決めるためにセマンティクスが必要とされる場合、部分一致問い合わせを生成した演算子の戦略番号nが提供されます。 またextra_dataextractQueryで作成される追加データ配列の対応する要素、もしなければNULLです。 NULLキーがこの関数に渡されることはありません。

void options(local_relopts *relopts)

演算子クラスの振舞いを制御するユーザに可視のパラメータの集合を定義します。

options関数にはlocal_relopts構造体へのポインタが渡されますが、構造体を演算子クラスに固有のオプションの集合で満たすことが必要です。 オプションはマクロPG_HAS_OPCLASS_OPTIONS()PG_GET_OPCLASS_OPTIONS()を使って他のサポート関数からアクセスできます。

インデックス付けされた値からのキーの抽出にもGINでのキーの表現にも柔軟性がありますので、ユーザに固有のパラメータに依存するかもしれません。

部分一致問い合わせをサポートするためには、演算子クラスはcomparePartialメソッドを提供しなければなりません。 またそのextractQueryは、部分一致問い合わせであった時にpmatchパラメータを設定しなければなりません。 詳細については70.4.2を参照してください。

上記の各種Datum値の実データ型は、演算子クラスに依存して変動します。 extractValueに渡される項目値は常に演算子クラスの入力型であり、キー値はすべてそのクラスのSTORAGE型でなければなりません。 extractQueryconsistentおよびtriConsistentに渡されるquery引数の型は、戦略番号によって識別されるクラスのメンバ演算子の右辺入力型です。 正しい型のキー値がそこから抽出できる限り、これはインデックス付けされた型と同じである必要はありません。 しかしながら、この3つのサポート関数のSQL宣言では、実際の型は演算子に依存して何か他のものであるとしても、query引数には演算子クラスのインデックス付けされたデータ型を使うことを勧めます。