メインコンテンツまでスキップ

BloomFilterインデックス

インデックス原理

BloomFilterインデックスは、BloomFilterに基づくスキップインデックスの一種です。その原理は、BloomFilterを使用して等価クエリにおいて指定された条件に合わないデータブロックをスキップし、IOを削減してクエリを高速化することです。

BloomFilterは1970年にBloomが提案した高速検索アルゴリズムで、複数のハッシュ関数を使用します。要素が集合に属するかどうかを100%の精度を必要とせずに迅速に判定する必要があるシナリオでよく使用されます。BloomFilterには以下の特徴があります:

  • 要素が集合に含まれるかどうかをチェックするために使用される、空間効率の良い確率的データ構造です。
  • 所属確認において、BloomFilterは2つの結果のいずれかを返します:集合に含まれる可能性があるか、確実に集合に含まれないかです。

BloomFilterは非常に長いバイナリビット配列と一連のハッシュ関数で構成されます。ビット配列は最初にすべて0に設定されます。要素をチェックする際は、一連のハッシュ関数によってハッシュ化されて一連の値を生成し、配列のこれらの位置のビットが1に設定されます。

下図はm=18、k=3(mはビット配列のサイズ、kはハッシュ関数の数)のBloomFilterの例を示しています。集合内の要素x、y、zが3つの異なるハッシュ関数によってビット配列にハッシュされます。要素wをクエリする際、ハッシュ関数によって計算されたいずれかのビットが0の場合、wは集合に含まれません。逆に、すべてのビットが1の場合、ハッシュ衝突の可能性があるため、wが集合に含まれる可能性があることを示すだけで、確実ではありません。

Bloom_filter.svg

したがって、計算された位置のすべてのビットが1の場合、ハッシュ衝突の可能性があるため、要素が集合に含まれる可能性があることを示すだけで、確実ではありません。これがBloomFilterの「偽陽性」特性です。そのため、BloomFilterベースのインデックスは条件に合わないデータをスキップすることはできますが、条件に合うデータを正確に特定することはできません。

DorisのBloomFilterインデックスはページ単位で構築され、各データブロックがBloomFilterを格納します。書き込み時には、データブロック内の各値が対応するBloomFilterにハッシュされます。クエリ時には、等価条件について、各データブロックのBloomFilterがその値を含むかどうかをチェックします。含まない場合、そのデータブロックはスキップされ、IOを削減してクエリを高速化します。

使用例

BloomFilterインデックスは等価クエリ(=およびINを含む)を高速化でき、useridなどの一意のidフィールドのような高カーディナリティフィールドに効果的です。

ヒント

BloomFilterには以下の制限があります:

  1. inと=以外のクエリ(!=、NOT IN、>、<など)には効果がありません。
  2. Tinyint、Float、Double型のカラムでのBloomFilterインデックスはサポートされません。
  3. 低カーディナリティフィールドでの高速化効果は限定的です。例えば、2つの値しか持たない「性別」フィールドは、ほぼすべてのデータブロックに含まれる可能性が高く、BloomFilterインデックスは意味をなしません。

クエリに対するBloomFilterインデックスの効果を確認するには、Query Profileの関連メトリクスを分析できます。

  • BlockConditionsFilteredBloomFilterTimeはBloomFilterインデックスによって消費された時間です。
  • RowsBloomFilterFilteredはBloomFilterによってフィルタリングされた行数です。他のRows値と比較してBloomFilterインデックスのフィルタリング効果を分析できます。

インデックスの管理

テーブル作成時のBloomFilterインデックスの作成

歴史的な理由により、BloomFilterインデックスを定義する構文は、転置インデックスに使用される一般的なINDEX構文とは異なります。BloomFilterインデックスは、テーブルのPROPERTIESで"bloom_filter_columns"を使用して指定され、1つまたは複数のフィールドを指定できます。

PROPERTIES (
"bloom_filter_columns" = "column_name1,column_name2"
);

BloomFilter Indexes の表示

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"
);