次の CQL テーブルがあります (わかりやすくするために少し簡略化しています)。
CREATE TABLE test_table (
user uuid,
app_id ascii,
domain_id ascii,
props map<ascii,blob>,
PRIMARY KEY ((user), app_id, domain_id)
)
このテーブルには多くのユーザー (つまり、数千万行など) が含まれるという考えです。ユーザーごとに関心のあるドメインがいくつかあり、ドメインごとにいくつかのアプリがあります。また、各ユーザー/ドメイン/アプリには、小さなプロパティ セットがあります。
このテーブル全体をスキャンし、その内容を特定の app_id と domain_id のチャンクにロードする必要があります。私の考えは、 TOKEN 関数を使用して、データセット全体を数回繰り返して読み取ることができるようにすることでした。したがって、次のようなものです。
SELECT props FROM test_table WHERE app_id='myapp1'
AND domain_id='mydomain1'
AND TOKEN(user) > -9223372036854775808
AND TOKEN(user) < 9223372036854775807;
行キーの範囲を指定し、クラスタリング キーの値を指定することで列範囲を効果的に指定するため、このクエリは効率的であると想定していました。しかし、このクエリを実行しようとすると、「Bad Request: このクエリを実行できません。データのフィルタリングが必要なため、パフォーマンスが予測できない可能性があります。パフォーマンスが予測できないにもかかわらず、このクエリを実行したい場合は、ALLOW FILTERING を使用してください」というエラー メッセージが表示されます。 .
私は Cassandra の経験が限られており、この種のクエリは get_range_slices() 呼び出しにマップされ、スライス述語 (つまり、app_id/domain_id 値で定義された列の範囲) とトークン範囲で定義されたキー範囲を受け入れると想定しました。 . この種のクエリの処理方法を誤解しているか、get_range_slices() 呼び出しの効率について誤解しているようです。
より具体的には、私の質問は次のとおりです。-このデータモデルが私が考えている種類のクエリに対して意味がある場合-このクエリが効率的であると予想される場合-効率的である場合、なぜこのエラーメッセージが表示されるのですかフィルタリングを許可する
最後のものについての私の唯一の推測は、指定された app_id/domain_id の組み合わせを持たない行は結果からスキップする必要があるということでした。
- - アップデート - -
すべてのコメントに感謝します。私はこれについてさらに調査を行ってきましたが、まだ完全には理解していないことがあります。
指定された構造では、取得しようとしているのは、データセットからの長方形の領域のようなものです (すべての行に同じ列があると仮定します)。長方形の上下はトークン範囲 (範囲) によって決定され、左側/右側は列範囲 (スライス) として定義されます。したがって、これは自然に get_range_slices リクエストに変換されます。CQL が ALLOW FILTERING 句を配置する必要がある理由は、探している列を含まない行があるため、スキップする必要があるという私の理解 (間違っている場合は訂正してください)。そして、(指定された範囲内で) 私の基準に適合する行を見つける前に、2 行ごとにスキップする必要があるのか、それとも最初の 100 万行をスキップする必要があるのか は誰にもわからないため、これが予測できないレイテンシーやタイムアウトの原因となります。私は正しいですか?同じ種類のクエリを実行するテストを作成しようとしましたが、低レベルの Astyanax API を使用しました (同じテーブルに対して、CQL で生成されたデータを読み取る必要がありましたが、非常に単純であることが判明しました)。このテストは機能します。 -行に要求している列のスライスが含まれていない列のないキーを返すことを除いて。もちろん、開始トークンに基づいてある種の単純なページングを実装し、小さなチャンクでデータをフェッチするように制限する必要がありました。
今、私は疑問に思っています-繰り返しますが、何十万ものユーザーに対処する必要があることを考えると、このテーブルを部分的に「回転」させて、次のように整理する方がよいでしょうか:
行キー: domain_id + app_id + partition no (hash(user) mod X のようなもの) クラスタリング キー: column partition no (hash(user) >> 16 mod Y のようなもの) + user
「列パーティション番号」について...本当に必要かどうかはわかりません。このモデルを使用すると、ドメインとアプリの組み合わせごとに比較的少数の行 (X=1000..10000) になると思います。これにより、必要に応じて並行して、個々のパーティションに対してクエリを実行できます。ただし、(ユーザーがランダムな UUID であると仮定すると) 1 億ユーザーの場合、1 行あたり数十または数十万の列になります。1 回のリクエストでそのような行を 1 つ読み取るのは良い考えですか? それはCassandraにいくらかのメモリプレッシャーを与えたに違いありません。では、それらをグループ (Y=10..100 など) で読む方がよいでしょうか?
私がやろうとしていることは、Cassandra がうまくやっていることではないことを認識しています - 異なるホストから並列フェッチするために、事前に計算できるチャンク (トークン範囲やパーティション キーなど) で CF データの「すべて」または大きなサブセットを読み取ります。しかし、そのようなユースケースで最も効率的なパターンを見つけようとしています。
ちなみに、「select * from ... where TOKEN(user)>X and TOKEN(user)」のようなクエリは、