有效地查询Hbase

时间:2016-06-18 16:43:21

标签: java hadoop mapreduce hbase hadoop2

我使用Java作为查询Hbase的客户端。

我的Hbase表设置如下:

var data =  [{"value":"3","label":"17 hr"},
 {"value":"2","label":"18 hr"},
 {"value":"1","label":"19 hr"}]

// if you want to keep the data var untouched
var parsedData = data.map(function(item) {
  // make sure you don't change item's reference by returning new object
  return {
    value: parseInt(item.value, 10),// you will end up with NaN if item.value is not a number
    label: item.label
  };
});

// if you don't care about mutation
data.forEach(function(item) {
  item.value = parseInt(item.value, 10)
});

我需要做的第一件事是获取与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

有没有更有效的方法来解决这个问题?

非常感谢您提前获得任何帮助!

2 个答案:

答案 0 :(得分:3)

n在这?随着RowKey的出现 - 我认为你的意思是 HBase rowkey - 不是一些手工制作的? - 这对HBase来说很快/容易。认为是O(1)。

如果ROWKEY是一个实际的列 ,那么 那里 就是你的问题。请改用HBase提供的rowkey。

让我们继续前进 - 假设您(a)已经正确使用了rowkey提供的hbase - 或者已经修复了您的结构。

在这种情况下,您只需为每个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主站的往返和主/区域服务器生成的解析/计划。

更新感谢OP:我更清楚地了解情况。我建议只使用&#34;主机| &#34;作为rowkey。然后,您可以执行范围扫描,并从单个获取 /扫描中获取条目。

另一次更新

HBase支持基于rowkey前缀的范围扫描。所以你有foobarRow1,foobarRow2,..等你可以对(foobarRow,foobarRowz)进行范围扫描,它会找到所有以foobarRow开头的行键的行 - 以及后面的任何字母数字字符。< / p>

看看这个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-120110105-1提供了一系列要搜索的行键。

答案 1 :(得分:3)

首先,您的rowkey设计应该是完美的,您可以根据该设计定义要查询的访问模式。

1)如果您知道可以提前使用哪些rowkeys

,那就很好

在这种情况下,您可以使用如下方法,它将返回Result数组。

/**
     * 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 Scan的体验,如果我们不这样做,性能会有点低   有完美的rowkey设计。如果您选择扫描上述方案,我建议您使用。

     

FuzzyRowFilter(see hbase-the-definitive) This is really useful in our case   我们使用了map-reduce等大容量客户端以及独立的hbase客户端

此过滤器作用于行键,但模糊方式。它需要一个应该返回的行键列表,以及一个附带的byte []数组,它表示行键中每个字节的重要性。构造函数是这样的:

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

fuzzyKeysData通过取两个值之一来指定行键字节的上述重要性:

  

0表示行键中相同位置的字节必须   按原样匹配。 1表示相应的行键字节没有   事情并且总是被接受。

示例:部分行键匹配 一个可能的例子是匹配部分键,但不是从左到右,而是在复合键内的某处。假设 _的行键格式,具有固定长度的部分,其中4是2,是4,并且是2个字节长。该应用程序现在要求所有用户在任何一年的1月份执行某些操作(编码为99)。然后行键和模糊数据对将如下:

行键 “???? 99 ???? _ 01”,其中“?”是一个任意字符,因为它被忽略了。 模糊数据 =“\ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00 \ x00 \ x01 \ x01 \ x01 \ x01 \ x00 \ x00 \ x00” 换句话说,模糊数据数组指示过滤器找到所有匹配“???? 99 ???? _ 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到row-20。我们想要检索与模式行匹配的所有行 - ?5,换句话说,所有以数字5结尾的行。上面的输出确认了正确的结果。