この回答を書いた後、おそらく「広すぎる」という質問にフラグを立てる必要があります。さまざまな戦略について長年話し合うことができます。最終的には、データでベンチマークを実行する必要があります。
各タグは整数で効率的に表すことができます。各エンティティにはタグのセットがあります。正しいセットの実装を選択することは重要です。Bツリーとソートされた配列の両方が可能です。このセットでは、メンバーシップテストのみを行います。どちらの構造もO(log t)(エンティティごとにtタグを使用)でこれを行うため、配列の密度が高いため配列を優先します。
O(n・log t・p)操作ですべてのエンティティをフィルター処理できるようになりました。ここで、pは述語決定ツリーの平均パス長です。この決定木は、決定に迅速に到達できるように順序付けることができます。統計データがなければ、共通の部分式を除外することしかできません。
エンティティが検索される順序は実際には重要ではありません。一方、すべてのインデックス0
にあるエンティティにi
特定のタグを付け、残りには付けないようにソートすることは有利です。これにより、この特定のタグを検索する際のnが削減されます(決定ツリーでは、これが最初のテストになります)。これは、複数のレベルに拡大するが、この複雑ものと取ることができるO(2 K)とメモリをKレベル。複数のレベルでは、ゲインが最も高いタグを最初に決定する必要があります。ゲインとは、検索する必要のないエンティティの数とそれらを破棄する確率です。ゲインは、50:50の機会、またはエンティティの50%がこの特定のタグを持っている場合に最大になります。これにより、アクセスパターンが不明な場合でも最適化できます。
以下のためのすべてのエンティティと1セット-あなたはまた、各タグにより、インデックスのエンティティが使用したセット作成することができT1
、ために次をT2
。(空間と時間)明らかな最適化は、セットがよりすべての要素の半分以上が含まれている場合に停止し、そしてそれらの要素保存することですしていないこのように、すべてのタグのインデックスを構築すると、以下になります-このタグを持っているの½ · n · t
と(スペース合計でtタグ)。補完セットを保存すると、他の最適化がより難しくなることに注意してください。繰り返しますが、私はセットの配列を(ソート)します。
整数範囲でエンティティを表す場合、連続範囲の開始メンバーと終了メンバーのみを保存することにより、インデックスセットに使用されるスペースを圧縮できます。実装上、これはおそらくエントリが範囲バウンドであるか通常のエントリであるかを示すために高ビットで行われます。
インデックスセット(およびタグの統計情報)があれば、述語を最適化して、ありそうもないプロパティが最初にテストされるようにすることができます(フェイルファースト戦略)。つまり、T1
一般的でT2
まれな場合は、T1 & T2
すべてのT2
インデックスセットエントリを反復処理し、各要素のをテストして述語を評価する必要がありますT1
。
ソートされた配列を使用してインデックスセットを実装する場合、多くの評価ステップをマージ操作として実装できます。とリストT1 & T2
を取得し、より大きな入力のサイズにターゲット配列を割り当て、両方の入力が空になるまで次のアルゴリズムを実行することを意味します:If 、then (破棄)。もし、その後。両方のヘッドが等しい場合、標的配列への上、その番号をコピーし、すべての3つのポインタ(インクリメントし、ターゲットを)。述語がの場合、要素は破棄されませんが、より小さい要素がコピーされます。フォームの述語はまた、マージ戦略を使用して実装することができるが、又はできません。T1
T2
T1[0] < T2[0]
T1++
T1[0] > T2[0]
T2++
T1
T2
T1 | T2
T1 & ¬T2
¬T1
T1 | ¬T2
これは、述語決定ツリーの順序付け時に考慮する必要があります。補数は&
、最終カウントが決定され、実際の要素を調べる必要がない場合、のRHSで、または最後に発生する必要があります。
インデックスセットを使用せずに、各スレッドはエンティティの一部をフィルター処理し、述語に一致する要素の数を返すことができます。インデックスセットを使用する場合、各スレッドには決定ツリーの1つのノードが割り当てられます。順序付けられたセットに対応する2つの入力ストリームを受け取り、マージされたストリームを返します。デシジョンツリーの各ノードには、その部分式を満たすすべてのエンティティを表す対応するセットがあり、セットの順序により、それらをマージするためにセット全体を一度に知る必要がないことに注意してください。 。
インデックスセットのマージやエンティティのリストのフィルタリングなど、さまざまな戦略をある程度組み合わせることができます。フィルタリングのパフォーマンスは非常に予測可能です。クエリが非常に限定的であるため、インデックスセットを使用すると検索スペースが大幅に減少する場合、マージ操作の方が優れている可能性があります。多くの大きな入力セットをマージすると、ブルートフォース検索よりもパフォーマンスが大幅に低下する可能性があることに注意することが重要です。非常に最適化されたアルゴリズムは、入力サイズ、クエリ構造、統計指標に基づいて適切な戦略を選択します。
余談ですが、部分的な結果のキャッシングは、初期クエリの実行速度を上げなくても、同様のクエリが将来実行されることが予想される場合に役立ちます。
T1
ため、同じオブジェクトの参照E1
、E2
など?