複数キー索引

複数キー索引は、配列のすべての要素、またはマップのすべての要素やすべてのキーの索引付けに使用されます。結果として、各表の行について、索引には、索引付けされる配列/マップの要素/エントリの数と同じ数のエントリが含まれます(べき乗重複削除)。索引エントリ数の展開を避けるために、1つの配列/マップのみ索引化できます(そうでない場合、表の行ごとに、要素/エントリまたは索引付けされる各配列/マップ間でデカルト積を構成する必要があります)。複数キー索引のより正確な定義は、この項の残りの部分で指定します。

索引は、次の場合に複数キー索引になります。
  1. 複数キー・ステップ(.keys()、.values()、または[])を使用する索引パスが少なくとも1つある場合。このような索引パスは、複数キー索引パスと呼ばれ、関連する索引フィールドは複数キー・フィールドと呼ばれます。索引定義には複数の複数キー・パスが含まれる場合がありますが、すべての複数キー・パスで、複数キー・ステップの前に同じname_pathを使用する必要があります。Mを一般的なname_pathとします。たとえば、ユーザーの市外局番と電話の種類の両方を索引付けできます。つまり、パスaddress.phones[].areaとaddress.phones[].kindは両方とも同じCREATE INDEX文に出現しますが、この場合、Mはパスaddress.phonesです。一方、connections[]とaddress.phones[].areaの両方のパスを使用してUsers2に索引を作成することはできません。これは同じ索引内の2つの配列の索引付けは許可されていないためです。
  2. 単純索引の項で定義されているように、非複数キー索引のパスは単純パスである必要があります。
  3. 共有パスMでは配列またはマップ・フィールドのいずれかを指定する必要があり、指定した配列/マップには、索引付け可能なアトミック項目、レコード項目、またはマップ項目が含まれている必要があります。たとえば、次の表定義について考えてみます。
    CREATE TABLE Foo (
        id INTEGER,
        complex1 RECORD(
            mapField MAP(ARRAY(MAP(INTEGER)))
        ),
        complex2 RECORD(
            matrix ARRAY(ARRAY(RECORD(a LONG, b LONG)))
        ),
        PRIMARY KEY(id)
    );
    パス式complex2.matrix[]は有効ではありません。これは、このパス式の結果がアトミック項目ではなく一連の配列であるためです。他の配列内の配列に索引付けすることはできないため、complex2.matrix[][].aも有効ではありません(実際、構文上1つの索引パスにつき最大1つの[]が許可されているため、このパスでは構文エラーが発生します)。一方、パスcomplex1.mapField.someKey[].someOtherKeyは有効です。この場合、Mはマップを含む配列を指定するパスcomplex1.mapField.someKeyです。この索引パスでは、someKeyおよびsomeOtherKeyはマップエントリ・キーです。そのため、マップ内部に含まれる配列に索引付けしていて、索引付けされる配列にマップが含まれていますが、このパスは有効です。これは、すべての配列エントリに加えて、すべてのマップ・エントリに索引付けするのではなく、関連するマップから特定のエントリを選択するためです。
  4. Mで配列を指定する場合(つまり、配列値フィールドに索引付けする場合):
    1. 配列に索引付け可能なアトミック項目が含まれている場合は、次のようになります。
      1. 索引定義には、M[]の形式(name_pathが[]の後に続く)の複数キー索引パスが1つ含まれる必要があります。この場合も、同じ索引内で複数の配列に索引付けできないことを意味します。
      2. この場合、表の行Rごとに、次のようにして多数の索引エントリが作成されます。単純な索引パス(ある場合)はRで計算されます。この場合、M[]が(問合せパス式である場合と同様に)計算され、NULLまたはEMPTY、あるいはMによって返された配列のすべての要素が返されます。最後に、M[]によって返された値Vごとに、フィールド値がVと単純パスの値である索引エントリが作成されます。
      3. 前述のプロセスで作成される重複索引エントリ(等しいフィールド値および同じ主キーを持つ)は消去されます。
      4. WITH NO NULLS句を指定して索引を作成した場合、NULLまたはEMPTY値を含む索引エントリはすべて破棄されます。残りのエントリは索引に挿入されます。
    2. 配列にレコードまたはマップが含まれる場合は、次のようになります。
      1. すべての複数キー・パスは、M[].name_pathの形式にする必要があります。Riを、i番目の複数キー索引パスのM[]の後に表示されるname_pathにします。Riはそれぞれ、最大で1つの索引付けが可能なアトミック項目を返す必要があります。
      2. この場合、表の行Rごとに、次のようにして多数の索引エントリが作成されます。単純な索引パス(ある場合)はRで計算されます。この場合、M[]が(問合せパス式である場合と同様に)計算され、NULLまたはEMPTY、あるいはMによって返された配列のすべての要素が返されます。次に、M[]で返された値Vごとに、次のようにして1つの索引エントリが作成されます。RiがVで計算され、単一の索引付けが可能なアトミック項目(NULLまたはEMPTY項目の場合もあります)が返され、索引エントリが作成されます。このフィールド値は、単純な索引パスの値とRiの値で計算された値です。
      3. 前述のプロセスで作成される重複索引エントリ(等しいフィールド値および同じ主キーを持つ)は消去されます。
      4. WITH NO NULLS句を指定して索引を作成した場合、NULLまたはEMPTY値を含む索引エントリはすべて破棄されます。残りのエントリは索引に挿入されます。
  5. Mでマップ・フィールドを指定する場合(つまり、索引でマップ値フィールドを索引付けする場合)、索引付けできるのはマップ・キーまたはマップ要素のみ、あるいはキーおよび要素の両方です。すべての場合において、マップ索引の定義を配列索引に関して指定できます。そのためには、2つのフィールドを含む配列としてマップが表示されます。2つのフィールドは、マップ・キーの値を含むkeyという名前のフィールドと対応するマップ要素(MAP(T)がARRAY(RECORD(key STRING, element T))として表示されます)の値を含むelementという名前のフィールドです。この場合、有効な3種類のマップ索引は次のとおりです。
    1. keys()ステップを使用する単一の複数キー索引パスが存在します。マップの配列ビューを使用する場合、M.keys()はM[].keyに相当します。
    2. 複数キー索引のパスが1つ以上あり、すべて.values()ステップを使用しています。これらのそれぞれの形式はM.values().Ri.です。マップの配列ビューを使用する場合、各M.values().RiパスはM[].element.Riに相当します。
    3. 1つのkeys()パスと1つ以上のvalues()パスがあります。これは、前述の2つのケースの組合せにすぎません。

例8-5 複数キー索引

CREATE INDEX midx1 ON Users2 (connections[]);

接続配列の要素の索引を作成します。Users2のサンプル行のこの索引の内容は、次のとおりです。

[ 10, 0 ]
[ 20, 0 ]
[ 100, 0 ]
[ EMPTY, 1 ]
[ NULL, 2 ]

前述のCREATE INDEX文でWITH NO NULLS句が使用されていた場合、前述のエントリの最後の2つは索引に表示されません。

例8-6 複数キー索引

CREATE INDEX midx2 ON Users2 (address.phones[].area, income);

ユーザーの市外局番と収入の索引を作成します。Users2のサンプル行のこの索引の内容は、次のとおりです。

[ 408, 1000, 0 ]
[ 408, NULL, 1 ]
[ 415, 1000, 0 ]
[ EMPTY, 2000, 2 ]
[ NULL, 1000, 0 ]

例8-7 複数キー索引

CREATE INDEX midx3 ON Users2
    (address.phones[].area, address.phones[].kind, income);

ユーザーの市外局番、電話番号の種類および収入の索引を作成します。Users2のサンプル行のこの索引の内容は、次のとおりです。

[ 408, "work", 1000, 0 ]
[ 408, "home", NULL, 1 ]
[ 408, "work", NULL, 1 ]
[ 415, "work", 1000, 0 ]
[ EMPTY, EMPTY, 2000, 2 ]
[ NULL, "home", 1000, 0 ]

例8-8 複数キー索引

CREATE INDEX midx4 ON Users2 (
    expenses.keys(), expenses.values());

費用マップのフィールド(キーと値の両方)に索引を作成します。Users2のサンプル行のこの索引の内容は、次のとおりです。

[ "books", 50, 0 ]
[ "clothes", 230, 0 ]
[ "housing", 1000, 0 ]
[ "housing", 1000, 1 ]
[ "travel", 300, 1 ]
[ NULL, NULL, 2 ]