BloomFilterインデックス
インデックスの原理
BloomFilterインデックスは、BloomFilterに基づくスキップインデックスの一種です。その原理は、BloomFilterを使用して等価クエリで指定された条件を満たさないデータブロックをスキップし、それによってIOを削減してクエリを高速化することです。
BloomFilterは、1970年にBloomによって提案された高速検索アルゴリズムで、複数のハッシュ関数を使用します。これは一般的に、100%の精度を必要とせずに、要素が集合に属するかどうかを迅速に判断する必要があるシナリオで使用されます。BloomFilterには以下の特徴があります:
- 要素が集合に含まれているかどうかを確認するために使用される、空間効率的な確率的データ構造。
- メンバーシップチェックについて、BloomFilterは2つの結果のうち1つを返します:集合に含まれている可能性がある、または確実に集合に含まれていない。
BloomFilterは、非常に長いバイナリビット配列と一連のハッシュ関数から構成されます。ビット配列は最初はすべて0に設定されています。要素をチェックする際、一連のハッシュ関数によってハッシュ化され一連の値を生成し、配列内のこれらの位置のビットが1に設定されます。
以下の図は、m=18およびk=3のBloomFilterの例を示しています(mはビット配列のサイズ、kはハッシュ関数の数)。集合内の要素x、y、zが3つの異なるハッシュ関数によってビット配列にハッシュされます。要素wをクエリする際、ハッシュ関数によって計算されたビットのいずれかが0の場合、wは集合に含まれていません。逆に、すべてのビットが1の場合、それはwが集合に含まれている可能性があることのみを示し、確実ではありません。これはハッシュの衝突の可能性があるためです。

したがって、計算された位置のすべてのビットが1の場合、それは要素が集合に含まれている可能性があることのみを示し、確実ではありません。これはハッシュの衝突の可能性があるためです。これがBloomFilterの「偽陽性」の性質です。したがって、BloomFilterベースのインデックスは、条件を満たさないデータをスキップすることしかできませんが、条件を満たすデータを正確に特定することはできません。
DorisのBloomFilterインデックスはページ単位で構築され、各データブロックがBloomFilterを保存します。書き込み時に、データブロック内の各値が対応するBloomFilterにハッシュされます。クエリ時には、等価条件について、各データブロックのBloomFilterが値を含んでいるかどうかが確認されます。含んでいない場合、データブロックはスキップされ、IOを削減してクエリを高速化します。
使用事例
BloomFilterインデックスは等価クエリ(=およびINを含む)を高速化でき、useridのような固有のidフィールドなど、高カーディナリティフィールドに効果的です。
BloomFilterには以下の制限があります:
- inや=以外のクエリ(!=、NOT IN、>、<など)には効果がありません。
- Tinyint、Float、Double型の列でのBloomFilterインデックスをサポートしていません。
- 低カーディナリティフィールドに対する高速化効果は限定的です。例えば、2つの値のみを持つ「性別」フィールドは、ほぼすべてのデータブロックに含まれる可能性が高く、BloomFilterインデックスが意味をなしません。
クエリでのBloomFilterインデックスの効果を確認するには、Query Profileの関連メトリクスを分析できます。
- BlockConditionsFilteredBloomFilterTimeは、BloomFilterインデックスによって消費される時間です。
- RowsBloomFilterFilteredは、BloomFilterによってフィルタリングされた行数です。他のRows値と比較して、BloomFilterインデックスのフィルタリング効果を分析できます。
インデックスの管理
テーブル作成時のBloomFilterインデックスの作成
歴史的な理由により、BloomFilterインデックスを定義する構文は、転置インデックスで使用される一般的なINDEX構文とは異なります。BloomFilterインデックスは、「bloom_filter_columns」を使用してテーブルのPROPERTIESで指定され、1つ以上のフィールドを指定できます。
PROPERTIES (
"bloom_filter_columns" = "column_name1,column_name2"
);
BloomFilter インデックスの表示
SHOW CREATE TABLE table_name;
既存テーブルでのBloomFilterインデックスの追加または削除
ALTER TABLEを使用してテーブルのbloom_filter_columnsプロパティを変更し、BloomFilterインデックスを追加または削除します。
column_name3のBloomFilterインデックスを追加する
ALTER TABLE table_name SET ("bloom_filter_columns" = "column_name1,column_name2,column_name3");
column_name1のBloomFilterインデックスを削除する
ALTER TABLE table_name SET ("bloom_filter_columns" = "column_name2,column_name3");
インデックスの使用
BloomFilter インデックスは WHERE 句での等価クエリを高速化するために使用されます。適用可能な場合は自動的に有効になり、特別な構文は必要ありません。
BloomFilter インデックスの高速化効果は、Query Profile の以下のメトリクスを使用して分析できます:
- RowsBloomFilterFiltered: BloomFilter インデックスによってフィルタリングされた行数。他の Rows 値と比較してインデックスのフィルタリング効果を分析できます。
- BlockConditionsFilteredBloomFilterTime: BloomFilter 転置インデックスによって消費された時間。
使用例
以下は Doris で BloomFilter インデックスを作成する方法の例です。
Doris の BloomFilter インデックスは、CREATE TABLE 文で "bloom_filter_columns" プロパティを追加することによって作成され、k1、k2、k3 が BloomFilter インデックスのキーカラムになります。例えば、以下は saler_id と category_id に BloomFilter インデックスを作成します。
CREATE TABLE IF NOT EXISTS sale_detail_bloom (
sale_date date NOT NULL COMMENT "Sale date",
customer_id int NOT NULL COMMENT "Customer ID",
saler_id int NOT NULL COMMENT "Salesperson",
sku_id int NOT NULL COMMENT "Product ID",
category_id int NOT NULL COMMENT "Product category",
sale_count int NOT NULL COMMENT "Sales quantity",
sale_price DECIMAL(12,2) NOT NULL COMMENT "Unit price",
sale_amt DECIMAL(20,2) COMMENT "Total sales amount"
)
DUPLICATE KEY(sale_date, customer_id, saler_id, sku_id, category_id)
DISTRIBUTED BY HASH(saler_id) BUCKETS 10
PROPERTIES (
"replication_num" = "1",
"bloom_filter_columns"="saler_id,category_id"
);