2016-06-18 15 views
4

私はHbaseをクエリするためのクライアントとしてJavaを使用しています。私がする必要がある最初の事は、それに関連付けられたhost.hst.comを持っているすべてのROWKEYsのリストを取得することですHbaseを効率的にクエリする

ROWKEY  |  HOST  |  EVENT 
-----------|--------------|---------- 
21_1465435 | host.hst.com | clicked 
22_1463456 | hlo.wrld.com | dragged 
    .    .    . 
    .    .    . 
    .    .    . 

マイHBaseのテーブルは次のように設定されています。

hostの列にスキャナを作成し、column value = host.hst.comという行の値ごとに対応するROWKEYをリストに追加します。かなり効率的ですね。 O(n)すべての行を取得します。

今は難しい部分です。リスト内の各ROWKEYについては、対応するEVENTを取得する必要があります。私は(ROWKEY, EVENT)でセルを取得するには、通常のGETコマンドを使用している場合

、私はスキャナが正しいセルを見つけて、値を返すためにO(n)時間がかかるEVENTで作成していると信じています。これは、個々の人にとってかなり時間の複雑さが非常に悪いです。ROWKEY 2つを組み合わせるとO(n^2)となります。

これについてもっと効率的な方法がありますか?

事前にお手数をおかけしていただきありがとうございます。

答えて

2

ここではnは何ですか? RowKeyを手にして - 私はHBase rowkeyを意味すると推測します - 手作りのものではありませんか? - それはHBaseのために速く/簡単です。それがO(1)であると考えてください。その後、

代わりのrowKeyが実際の列作成あなたがある場合.. あなたの問題です。代わりに、HBase提供のローキーを使用してください。

ここでは、(a)既に提供されているhbase(rowkey)を正しく使用しているか、そうするようにストラクチャを修正したものとします。

次のようにあなたは、単に各 (rowkey, EVENT)値の個別 getを作成することもでき、その場合には

Perform a `get` with the given `rowkey`. 
In your result then filter out EVENT in <yourEventValues for that rowkey> 

だから、あなたが与えられたのrowKeyためすべて最近(最新のタイムスタンプ)のエントリを取得することになります。これはおそらく 'n'に比べて小さいでしょうか?次に、フィルタリングは1つの列に対する高速操作です。

multigetをバッチ処理することで、これをスピードアップすることもできます。この節約は、HBaseマスタへのラウンドトリップの減少と、マスタ/リージョンサーバーによる解析/プラン生成によるものです。

更新 OPのおかげで:私は状況をより明確に理解しています。私は単純に "ホスト|"を行のキーとして使用することを提案しています。その後、レンジスキャンを実行して、/Scanの1つからエントリを取得することができます。

別の更新

のHBaseはのrowKeyのプレフィックスに基づく範囲スキャンをサポートしています。あなたはfoobarRow1、foobarRow2、.. etcを持っていますので、(foobarRow、foobarRowz)でレンジスキャンを行うことができ、foobarRowで始まる行キーとそれに続く任意の英数字を持つすべての行を見つけることができます。 20110103-120110105-1を検索するrowkeysの範囲を提供することを

SingleColumnValueFilter filter = new SingleColumnValueFilter(
    Bytes.toBytes("columnfamily"), 
    Bytes.toBytes("storenumber"), 
    CompareFilter.CompareOp.NOT_EQUAL, 
    Bytes.toBytes(15) 
); 
filter.setFilterIfMissing(true); 
Scan scan = new Scan(
    Bytes.toBytes("20110103-1"), 
    Bytes.toBytes("20110105-1") 
); 
scan.setFilter(filter); 

お知らせ:

はここにいくつかの例示的なコードは、このHBase (Easy): How to Perform Range Prefix Scan in hbase shell

を見てみましょう。

+0

お返事ありがとうございました。私は 'HOST'カラムをスキャンし、対応する' ROWKEYs'の 'host = x'を文字列リストとして返すメソッドを作成しました。これには3秒かかります。そして、私は、これらのすべてのROWKEYとGETのすべてを、それらのEVENTのすべてをループする方法を書いた。これには約120秒かかります。どのように 'GET'ごとに' O(1) 'になるのでしょうか? –

+0

'n'は行数を意味します。また、私は独自のカスタム列ではなく、デフォルトのRowkeysを使用しています。 –

+0

@GregPeckory OK「取得」します。そこで私は答えを更新しました: " ROWKEY"で構成される連結されたRowkeyを使用してください。その場合、 ""、 ""でレンジスキャンを実行して、そのホストのすべてのエントリのうちの**を1つの 'get'で返すことができます。 – javadba

3

まず、行キーのデザインは、照会するアクセスパターンを定義するのに適しているはずです。あなたは、あなたが以下のようなメソッドを使用することができ、その場合には

先行acccessできるrowkeysこれを知っていれば

1)を取得しますが良いですが、それは結果の配列を返します。 HBaseのスキャン性能を持つ私の経験で

/** 
    * Method getDetailRecords. 
    * 
    * @param listOfRowKeys List<String> 
    * @return Result[] 
    * @throws IOException 
    */ 
    private Result[] getDetailRecords(final List<String> listOfRowKeys) throws IOException { 
     final HTableInterface table = HBaseConnection.getHTable(TBL_DETAIL); 
     final List<Get> listOFGets = new ArrayList<Get>(); 
     Result[] results = null; 
     try { 
      for (final String rowkey : listOfRowKeys) {// prepare batch of get with row keys 
    // System.err.println("get 'yourtablename', '" + saltIndexPrefix + rowkey + "'"); 
       final Get get = new Get(Bytes.toBytes(saltedRowKey(rowkey))); 
       get.addColumn(COLUMN_FAMILY, Bytes.toBytes(yourcolumnname)); 
       listOFGets.add(get); 
      } 
      results = table.get(listOFGets); 

     } finally { 
      table.close(); 
     } 
     return results; 
    } 

2)

我々は は完璧なのrowKeyのデザインを持っていけない場合は少し低いです。あなたが上記のシナリオのスキャンを選択している場合は、私はお勧めします。

FuzzyRowFilter(see hbase-the-definitive) This is really useful in our case我々は、このフィルタは、行キーに作用するが、ファジー方法でマップ低減ならびにスタンドアロンのHBaseクライアント

等バルククライアントを使用しています。返される行キーのリストと、行キーの各バイトの重要度を示す付随するbyte []配列が必要です。コンストラクタは、通りである:

FuzzyRowFilter(List<Pair<byte[], byte[]>> fuzzyKeysData) 

fuzzyKeysDataは、2つの値のいずれかをとることによって、行キーバイトの言及意義を指定:

0は、行の同じ位置にバイトことを示しキーはそのまま に一致する必要があります。 1対応する行キーバイトが ではなく、常に受け入れられることを意味します。

例:複合キーの内部ではなく、どこかで、左から右に部分的な行キーの一致 可能な例ではなく、部分キーに一致しています。 _の固定長部分を持つ行キー・フォーマットを想定すると、4は2、4は2バイト、2バイトは長さです。アプリケーションは、今年1月に特定のアクション(99としてエンコードされた)を行ったすべてのユーザーを要求するようになりました。次いで、行キーとファジーデータの組は、以下のようになります。

行キー 「???? ??_ 01」、ここで「?」無視されるため、任意の文字です。 ファジーデータ = "\ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00 \ x00 \ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00" つまり、ファジーデータ配列は、 "012"を "???? ???? _ 01"と一致するすべての行キーを見つけてください。任意の文字を受け入れます。

このフィルタの利点は、一致する行キーの最後に一致する次の行キーを計算する可能性があることです。これは、getNextCellHint()メソッドを実装して、サーバが一致する次の行範囲に早送りするのを支援します。これは、特にスキップされた範囲がかなり大きい場合に、走査を高速化する。例4-12では、フィルタを使用してテスト・データ・セットから特定の行を取得します。テーブルに行を追加

...スキャンの 結果:サンプルコードもわずか出力を維持するために、スキャンにフィルタ列を追加列のプレフィックス

List<Pair<byte[], byte[]>> keys = new ArrayList<Pair<byte[], byte[]>>(); 
keys.add(new Pair<byte[], byte[]>(
    Bytes.toBytes("row-?5"), new byte[] { 0, 0, 0, 0, 1, 0 })); 
Filter filter = new FuzzyRowFilter(keys); 

Scan scan = new Scan() 
    .addColumn(Bytes.toBytes("colfam1"), Bytes.toBytes("col-5")) 
    .setFilter(filter); 
ResultScanner scanner = table.getScanner(scan); 
for (Result result : scanner) { 
    System.out.println(result); 
} 
scanner.close(); 

によるフィルタリング

例:

keyvalues={row-05/colfam1:col-01/1/Put/vlen=9/seqid=0, 
      row-05/colfam1:col-02/2/Put/vlen=9/seqid=0, 
      ... 
      row-05/colfam1:col-09/9/Put/vlen=9/seqid=0, 
      row-05/colfam1:col-10/10/Put/vlen=9/seqid=0} 
keyvalues={row-15/colfam1:col-01/1/Put/vlen=9/seqid=0, 
      row-15/colfam1:col-02/2/Put/vlen=9/seqid=0, 
      ... 
      row-15/colfam1:col-09/9/Put/vlen=9/seqid=0, 
      row-15/colfam1:col-10/10/Put/vlen=9/seqid=0} 

テストコード配線では、テーブルにrow-01からrow-20という名前の20行が追加されます。パターンrow-?5と一致するすべての行、つまり数字5で終わるすべての行を取得するとします。上記の出力は正しい結果を確認します。

+0

詳細な回答ありがとうございます。 1)の場合、私はROWKEYを知っていればGETが良いと言います。私はそれをしています。約70000行のGETを実行するのに2分かかりますか?しかし、列の値に基づいてROWKEYをフィルタリングするには3秒かかります。 HBaseは列指向なので、これは正しいと思いました。しかし誰もがGETが非常に効率的であると言っています。 'O(1)' –

+0

私には驚きです。上記の方法に7000行のキーをバッチとして渡すと、速くなるはずです。あなたが検索している列の値に基づいて、それはその値を見つけるためにフルテーブルスキャンを行います(そうでなければ遅くなるはずです...(row filter)は、カラム値に基づくアクセス(カラムフィルタ)よりも速くなければなりません。 –

+1

親指ルールは、常にrowkeyベースのアクセス –