2016-06-18 1 views
4

Я использую Java как клиент для запроса Hbase.Querying Hbase эффективно

Моя Hbase таблица устанавливается следующим образом:

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

Первое, что нужно сделать, это получить список всех ROWKEYs, которые имеют host.hst.com, связанные с ним.

Я могу создать сканер в столбце host и для каждого значения строки с помощью column value = host.hst.com. Я добавлю соответствующий ROWKEY к списку. Кажется довольно эффективным. O(n) для получения всех строк.

Теперь сложная часть. Для каждого ROWKEY в списке мне нужно получить соответствующий EVENT.

Если я использую обычную GET команды, чтобы получить ячейку в (ROWKEY, EVENT), я считаю, что сканер создан на EVENT который занимает O(n) время, чтобы найти правильную ячейку и возвращает значение. Это довольно сложная временная сложность для каждого человека ROWKEY. Объединение двух дает нам O(n^2).

Есть ли более эффективный способ обойти это?

Большое спасибо за любую помощь заранее!

ответ

2

Ваш n здесь ?? С RowKey в руке - я полагаю, вы имеете в виду HBase rowkey - не какой-то ручной? - это быстро и просто для HBase. Предположим, что O (1).

Если вместо этого RowKey является актуальной колонки вы создали .. то там Ваш вопрос. Вместо этого используйте HBCase rowkey.

Итак, давайте двигаться дальше - если вы либо уже правильно используете предоставленную hbase rowkey, либо исправили свою структуру, чтобы сделать это.

В этом случае вы можете просто создать отдельную get для каждого (rowkey, EVENT) значения следующим образом:

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

Таким образом, вы будете в конечном итоге выборка все недавние (последние метки времени) записи для данного RowKey. Это, по-видимому, мало по сравнению с 'n' ?? Затем фильтрация является быстрой операцией на одном столбце.

Вы также можете ускорить это, сделав пакет multiget. Экономия достигается за счет уменьшения количества поездок в оба конца до мастера HBase и генерации парсеров/планов серверами master/region.

Обновление Благодаря ОП: Я понимаю ситуацию более четко. Я предлагаю просто использовать «host |» в качестве строки. Затем вы можете сделать Range Scan и получить данные от одного Получить/Scan.

Еще одно обновление

HBase поддерживает сканирование диапазона на основе префиксов в RowKey. Таким образом, у вас есть foobarRow1, foobarRow2, .. и т. Д., Тогда вы можете выполнить сканирование диапазона (foobarRow, foobarRowz), и он найдет все строки, у которых есть строки, начинающиеся с foobarRow, - и с любыми буквенно-цифровыми символами.

Взгляните на эту HBase (Easy): How to Perform Range Prefix Scan in hbase shell

Вот некоторые иллюстративные код:

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

Обратите внимание, что 20110103-1 и 20110105-1 обеспечивают диапазон rowkeys для поиска.

+0

Большое спасибо за ответ. Я написал метод, который просматривает столбец 'HOST' и возвращает список строк всех соответствующих' ROWKEYs' с 'host = x'. Это занимает 3 секунды. Затем я написал метод, который перебирает все эти «ROWKEYs» и «ПОЛУЧИТ» все их «СОБЫТИЯ». Это занимает около 120 секунд. Как это может быть «O (1)» для каждого «GET»? –

+0

Под 'n' я имею в виду количество строк. Также я использую Rowkeys по умолчанию, а не свой собственный столбец –

+0

@GregPeckory OK, теперь я «получаю это». Поэтому я обновил свой ответ, чтобы предложить: используйте конкатенированный Rowkey, который состоит из « ROWKEY». В этом случае вы можете выполнить сканирование диапазона на «», «», который будет возвращать ** все ** записей для этого узла в одном 'get'. – javadba

3

Прежде всего, ваш дизайн rowkey должен быть идеальным, на основе которого вы можете определить свой шаблон доступа для запроса.

1) Получить хорошо, если вы знаете, какие rowkeys вы можете заранее Гости могут воспользоваться

В этом случае вы можете использовать метод, как показано ниже, он возвращает массив результата.

/** 
    * 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)

В моем опыте с производительностью Hbase сканирования является немного низкий, если мы не имеют совершенную конструкцию RowKey. Я рекомендую, если вы выбираете сканирование для вышеупомянутого сценария.

FuzzyRowFilter(see hbase-the-definitive) This is really useful in our case Мы использовали объемные клиентов, как карта-свертка, а также автономные клиенты HBase

Этот фильтр действует на ключи строк, но в нечеткой манере. Ему нужен список ключей строк, который должен быть возвращен, плюс сопровождающий массив byte [], который означает важность каждого байта в ключе строки. Конструктор как таковые:

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

fuzzyKeysData определяет упомянутое значение ключевого байта строки, принимая одну из двух значений:

0 Указует, что байты в той же позиции в строке ключ должен соответствовать как есть. 1 означает, что соответствующий байт строки строки не имеет значения и всегда принимается.

Пример: Частичная Строка Ключ соответствие Возможного примера сопоставление частичных ключей, но не слева направо, а где-то внутри ключа соединения. Предполагая формат ключа строки _, с частями фиксированной длины, где 4, равен 2, равен 4 и имеет длину 2 байта. Теперь приложение запрашивает всех пользователей, которые выполнили определенное действие (закодировано как 99) в январе любого года. Тогда пара для ряда ключевых и нечетких данных будет следующим: «?»

ряд ключ «???? ???? _ 01», где является произвольным символом, так как он игнорируется. нечеткие данные = "\ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00 \ x00 \ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00" Другими словами, массив нечетких данных указывает фильтру на найти все строки, соответствующие «???? ???? _ 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} 

Проводка тестового кода добавляет 20 строк в таблицу с именем row-01 to row-20. Мы хотим получить все строки, соответствующие строке шаблона-5, другими словами, все строки, которые заканчиваются на номере 5. Вышеприведенный результат подтверждает правильный результат.

+0

Спасибо за подробный ответ. В случае 1) вы говорите, что GET хорош, если я знаю ROWKEY. Что я делаю. Знаете ли вы, почему запуск GET около 70000 строк занимает 2 минуты. Но фильтрация ROWKEY на основе значений столбцов занимает 3 секунды. Я решил, что это будет правильно, поскольку HBase ориентирован на столбцы. Но все говорят, что GET очень эффективен и 'O (1)' –

+0

Его удивление для меня .. если вы передаете 7000 rowkeys как пакет для вышеупомянутого метода, он должен быть быстрее. Основываясь на значениях столбцов, которые вы ищете, он выполнит полное сканирование таблицы, чтобы узнать это значение (которое должно быть медленным, если ...кстати, у вас есть все эти строки в одном и том же регионе) –

+1

правило одного большого пальца: всегда доступ на основе строки (фильтр строк) должен быть быстрее, чем доступ на основе столбцов (фильтр столбцов) –