GINインタフェースは高度に抽象化されています。 アクセスメソッド実装者に要求されることは、アクセスするデータ型の意味を実装することだけです。 GIN層自体が同時実行性、ログ処理、ツリー構造の検索処理に関する面倒を見ます。
GINアクセスメソッドを動作させるために必要なことは、少数のユーザ定義関数を実装することだけです。 これは、ツリー内のキーの動作とキーとインデックス付けされる項目、インデックス可能な問い合わせ間の関係を定義します。 すなわち、GINは、一般化、コード再利用、整理されたインタフェースによる拡張性を組み合わせます。
GIN用の演算子クラスが提供しなければならないメソッドは2つあります。
Datum *extractValue(Datum itemValue, int32 *nkeys,
bool **nullFlags)
インデックス対象値に与えられる、pallocで割り当てられたキーの配列を返します。
返されるキーの数は*nkeys
に格納しなければなりません。
キーのいずれかがNULLになるかもしれない場合、*nkeys
個のbool
の配列をpallocで割り当てそのアドレスを*nullFlags
に格納し、必要に応じてNULLフラグを設定してください。
すべてのキーが非NULLであれば、*nullFlags
をNULL
(初期値)のままにすることができます。
項目がキーを含まない場合、戻り値は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ならば*nullFlags
はNULL
(初期値)のままにしておくことができます。
query
がキーを含まない場合、戻り値をNULL
にすることができます。
searchMode
は出力引数です。
これによりextractQuery
は検索がどのように行われるかの詳細を指定することができます。
*searchMode
がGIN_SEARCH_MODE_DEFAULT
(呼び出し前にこの値に初期化されます。)に設定された場合、返されるキーの少なくとも1つに一致する項目が合致候補とみなされます。
*searchMode
がGIN_SEARCH_MODE_INCLUDE_EMPTY
に設定された場合、少なくとも1つの一致するキーを含む項目に加え、キーをまったく含まない項目が合致候補とみなされます。
(このモードは例えば何のサブセットかを求める演算子を実装する際に有用です。)
*searchMode
がGIN_SEARCH_MODE_ALL
に設定された場合、返されるキーのいずれかに一致するかどうかは関係なく、インデックス内の非NULLの項目すべてが合致候補とみなされます。
(このモードは、基本的にインデックス全体のスキャン処理が必要ですので、他の2つの選択肢と比べてかなり低速になります。
しかし境界条件を正確に実装するためにこれが必要になるかもしれません。
おそらく、このモードを必要とする演算子はほとんどの場合、GIN演算子クラス向けに優れた候補ではありません。)
このモードを設定するために使用する記号はaccess/gin.h
で定義されています。
pmatch
は部分一致が提供されている場合に使用する出力引数です。
使用するには、extractQuery
が*nkeys
個のbool
の配列を割り当て、そのアドレスを*pmatch
に格納しなければなりません。
関連するキーが部分一致を必要とするとき、それぞれの配列要素は真に、そうでなければ偽に設定されなければなりません。
*pmatch
がNULL
に設定されている場合、GINは部分一致が必要ないと想定します。
呼び出し前に変数はNULL
に初期化されますので、この引数は部分一致が提供されていない演算子クラスでは、単に無視できます。
extra_data
は、extractQuery
がconsistent
とcomparePartial
メソッドに追加データを渡すことができるようにする出力引数です。
使用するには、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_data
はextractQuery
により返された追加データ配列で、ない場合はNULL
です。
extractQuery
がqueryKeys[]
内で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[])
triConsistent
はconsistent
と似ていますが、check
ベクターの論理値の代わりに、各キーに対して3つの可能な値があります。GIN_TRUE
、GIN_FALSE
、GIN_MAYBE
です。
GIN_FALSE
とGIN_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_data
はextractQuery
で作成される追加データ配列の対応する要素、もしなければNULL
です。
NULLキーがこの関数に渡されることはありません。
void options(local_relopts *relopts)
演算子クラスの振舞いを制御するユーザに可視のパラメータの集合を定義します。
options
関数にはlocal_relopts
構造体へのポインタが渡されますが、構造体を演算子クラスに固有のオプションの集合で満たすことが必要です。
オプションはマクロPG_HAS_OPCLASS_OPTIONS()
とPG_GET_OPCLASS_OPTIONS()
を使って他のサポート関数からアクセスできます。
インデックス付けされた値からのキーの抽出にもGINでのキーの表現にも柔軟性がありますので、ユーザに固有のパラメータに依存するかもしれません。
「部分一致」問い合わせをサポートするためには、演算子クラスはcomparePartial
メソッドを提供しなければなりません。
またそのextractQuery
は、部分一致問い合わせであった時にpmatch
パラメータを設定しなければなりません。
詳細については67.4.2を参照してください。
上記の各種Datum
値の実データ型は、演算子クラスに依存して変動します。
extractValue
に渡される項目値は常に演算子クラスの入力型であり、キー値はすべてそのクラスのSTORAGE
型でなければなりません。
extractQuery
、consistent
およびtriConsistent
に渡されるquery
引数の型は、戦略番号によって識別されるクラスのメンバ演算子の右辺入力型です。
正しい型のキー値がそこから抽出できる限り、これはインデックス付けされた型と同じである必要はありません。
しかしながら、この3つのサポート関数のSQL宣言では、実際の型は演算子に依存して何か他のものであるとしても、query
引数には演算子クラスのインデックス付けされたデータ型を使うことを勧めます。