Cassandra Indexing:The Good,the Bad and The Ugly

NoSQL内では、インデックス作成、フェッチ、情報検索の操作は物理ストレージメカニズムに密接に結びついています。 行はホスト間で格納されますが、単一の行は単一のホストに格納されることを覚えておくことが重要です。 (レプリカを使用)列ファミリはソートされた順序で格納されるため、一連の列のクエリが効率的になります(行にまたがる場合)。

ザ-バッド : パーティショニング

最初に慣れるのは難しいことの1つは、行にまたがるインデックスクエリがないと(非常に)悪いことになる可能性があることです。 しかし、私たちのストレージモデルに戻って考えると、それは驚くべきことではありません。 Cassandraがホスト間で行を分散するために使用する戦略は、パーティション分割と呼ばれます。

パーティショニングは、行キーの範囲を”トークンリング”に割り当て、行キーの範囲のセグメント(つまりパーティション)の責任を各ホストに割り当てる行為です。 クラスターを”トークン”で初期化したときに、おそらくこれを見たことがあります。 トークンはホストにトークンリングに沿った場所を与え、トークン範囲のセクションの責任を割り当てます。 パーティショニングは、rowkeyをトークン範囲にマッピングする行為です。

プライマリパーティショナーには、ランダムと順序保存の2つがあります。 彼らは適切に命名されています。 RandomPartitionerはrowkeysをトークンにハッシュします。 RandomPartitionerを使用すると、トークンはrowkeyのハッシュになります。 これは、一連のノードにデータを均等に分散させるのに適していますが、rowkeyスペースの範囲を照会することは非常に困難です。 「Start rowkey」値と「end rowkey」値のみから、Cassandraは必要なトークンスペースの範囲を判断できません。 本質的には、クエリに答えるために「テーブルスキャン」を実行する必要があり、Cassandraの「テーブルスキャン」は、クエリに答えるために各マシン(適切なハッシュ関数

これで、データ配布のコストが大幅に削減され、OrderPreservingPartitioner(OPP)を使用することができます。 私はOPPと*ない*ダウンしています。 OPPは、行キーをトークンに変換するときに順序を保持します。 これで、start rowkey値とend rowkey値が指定されると、Cassandra*は、どのホストが探しているデータを持っているかを正確に判断できます。 開始値をトークンに、終了値をトークンに計算し、その間のすべてを選択して返します。 しかし、順序を維持することで、行キーがスペース全体に均等に分散されない限り、トークンはどちらにもならず、偏ったクラスターが得られ、クラスターの構成と管理のコストが大幅に増加します。 (それだけの価値はありません)

良い:セカンダリインデックス

Cassandraは、セカンダリインデックスにネイティブなインデックス作成メカニズムを提供します。 セカンダリインデックスは、列の値から機能します。 列ファミリにセカンダリインデックスを宣言するとします。 Datastaxには、使用法に関する優れた文書があります。 内部では、Cassandraはインデックスとして”隠された列ファミリ”を維持しています。 (詳細についてはEd Anuffのプレゼンテーションを参照してください)Cassandraはいずれかのノードで列値情報を維持せず、セカンダリインデックスは(rowkeysではなく)columns valueに さらに、セカンダリインデックスは、基数の高いセットには推奨されません。 私はまだ見ていませんが、これは”隠し列ファミリ”内で使用されているデータモデルのためだと思います。 非表示の列ファミリが一意の値ごとに行を格納する場合(rowkeysを列として)、行をスキャンしてクエリの範囲内にあるかどうかを判断することを意味し
エドさんのプレゼンから:

  • 高い基数値(タイムスタンプ、誕生日、キーワードなど)にはお勧めしません。)
  • は、クエリ内で少なくとも一つの等価比較を必要とします-より小さい/より大きい/範囲のクエリには適していません
  • ソートされていない-結果は、クエリ値の順ではなく、トークン順になります
  • データ型の検索に限定され、Cassandraはネイティブに理解しています

すべてのことを言って、セカンダリインデックスは箱から出して動作し、我々は単純な値でそれらを使用して良い成功を収めてきました。

醜い:日曜大工(DIY)/ワイド行

今、美しさは見る人の目にあります。 NoSQLの素晴らしい点の1つは、シンプルさです。 構造は単純です:キースペース、列ファミリ、行と列。 しかしそれを簡単に保つことは時々あなた自身の手に事を取る必要があることを意味する。

これは、ワイド行インデックスの場合に当てはまります。 Cassandraのストレージモデルを利用すると、各行キーがインデックス内の列になる独自のインデックスを簡単に構築できます。 これはあなたの頭を動かすのが難しいことがありますが、郵便番号のすべてのユーザーを選択するケースがあると想像してみましょう。 メインのユーザー列ファミリはuseridでキー設定され、郵便番号は各ユーザー行の列です。 二次索引を使用できますが、かなりの数の郵便番号があります。 代わりに、”idx_zipcode”と呼ばれる単一の行を持つ列ファミリを維持することができます。 次に、”zipcode_userid”という形式のこの行に列を書き込むことができます。 列はソートされた順序で格納されるため、「18964」で始まるすべての列をクエリするのが高速です(たとえば、18964_と18964_ZZZZZZを開始値と終了値として使用できます)。

このアプローチの明らかな欠点の1つは、行がホスト上で自己完結型であることです。 (レプリカを除く)これは、すべてのクエリが単一のノードにヒットすることを意味します。 私はまだこれのための良い答えを見つけていません。

さらに、私見では、DIYワイド行インデックス作成の最も醜い部分は、クライアントの観点からです。 私たちの実装では、クライアント側で言語に依存しないように最善を尽くし、人々がCassandraのデータと対話するための最良のツールを選ぶことができます。 その考え方では、DIYのインデックスにはいくつかの問題があります。 ワイド行はしばしば複合キーを使用します(idx_state_zipがあれば、状態でクエリを実行してからzipを実行できると想像してください)。 複合キーの「ネイティブ」サポートがありますが、すべてのクライアントライブラリは独自のバージョン(Hector、Astyanax、Thrift)を実装しています。 つまり、データを照会する必要があるクライアントには、最初にインデックスを照会するロジックが追加されている必要があり、さらにすべてのクライ

それをより良くする。..

この理由から、私たちはこのロジックをサーバー側にプッシュするのに役立つ二つのオープンソースプロジェクトをリリースすることにしました。 最初のプロジェクトはCassandra-Triggersです。 これにより、cassandraの書き込みに非同期アクティビティをアタッチできます。 (そのような活動の1つは索引付けです)Cassandra-Indexingもリリースしました。 これはプレスからホットであり、まだ初期段階にあります(例えば、インデックス内のUt8Typesのみをサポートしています)が、Cassandraに書き込まれたデータをインデッ Cassandra-Indexingで使用したのと同じサーバー側の手法を使用すると、インデックスを作成する列を構成するだけで、aopコードはターゲットCFに書き込むときに残りを行い いつものように、質問、コメント、思考は大歓迎です。 (特にどこかオフベースの場合)

コメントを残す

メールアドレスが公開されることはありません。