高效查询Hbase
Querying Hbase efficiently
我正在使用 Java 作为查询 Hbase 的客户端。
我的Hbasetable是这样设置的:
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)
时间来找到正确的单元格和 return 值。这对每个人来说都是非常糟糕的时间复杂度 ROWKEY
。结合这两个给我们 O(n^2)
.
有没有更有效的方法来解决这个问题?
非常感谢您的提前帮助!
你的 n
是什么??有了 RowKey 在手 - 我想你的意思是 HBase rowkey - 不是一些手工制作的? - 即 HBase 的 fast/easy。认为是 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 的 all 个最近(最新时间戳)条目。与 'n' 相比,这可能很小 ??那么过滤就是对一列的快速操作。
您还可以通过批处理 multiget
来加快速度。节省来自减少到 HBase 主服务器的往返次数和 master/region 服务器的 parsings/plan 生成。
更新感谢楼主:我更清楚地了解了情况。我建议简单地使用 "host | " 作为行键。然后您可以执行 Range Scan 并从单个 Get / Scan.
中获取条目
另一个更新
HBase支持基于行键前缀的范围扫描。所以你有 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
提供了一系列要搜索的行键。
首先,您的 rowkey 设计应该是完美的,您可以根据它定义要查询的访问模式。
1) 如果您知道可以预先访问哪些行键,那么获取就很好
在这种情况下,您可以使用如下方法,它将 return 结果数组。
/**
* 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)
In my experience with Hbase Scan performance is bit low if we dont
have perfect rowkey design. I recommend if you are opting for scan for the above mentioned scenario by you.
FuzzyRowFilter(see hbase-the-definitive) This is really useful in our case
We have used bulk clients like map-reduce as well as standalone hbase clients
此过滤器以模糊方式作用于行键。它需要一个应该 returned 的行键列表,以及一个附带的 byte[] 数组,表示行键中每个字节的重要性。构造函数是这样的:
FuzzyRowFilter(List<Pair<byte[], byte[]>> fuzzyKeysData)
fuzzyKeysData 通过取两个值之一来指定行键字节的重要性:
0 Indicates that the byte at the same position in the row key must
match as-is. 1 Means that the corresponding row key byte does not
matter and is always accepted.
示例:部分行键匹配
一个可能的例子是匹配部分键,但不是从左到右,而是在复合键内的某个地方。假设一个行键格式为_,有固定长度的部分,其中是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();
示例代码还在扫描中添加了过滤列,只是为了保持输出简短:
正在向 table 添加行...
扫描结果:
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}
测试代码接线向table添加20行,命名为row-01到row-20。我们想要检索与模式 row-?5 匹配的所有行,换句话说,所有以数字 5 结尾的行。上面的输出确认了正确的结果。
我正在使用 Java 作为查询 Hbase 的客户端。
我的Hbasetable是这样设置的:
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)
时间来找到正确的单元格和 return 值。这对每个人来说都是非常糟糕的时间复杂度 ROWKEY
。结合这两个给我们 O(n^2)
.
有没有更有效的方法来解决这个问题?
非常感谢您的提前帮助!
你的 n
是什么??有了 RowKey 在手 - 我想你的意思是 HBase rowkey - 不是一些手工制作的? - 即 HBase 的 fast/easy。认为是 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 的 all 个最近(最新时间戳)条目。与 'n' 相比,这可能很小 ??那么过滤就是对一列的快速操作。
您还可以通过批处理 multiget
来加快速度。节省来自减少到 HBase 主服务器的往返次数和 master/region 服务器的 parsings/plan 生成。
更新感谢楼主:我更清楚地了解了情况。我建议简单地使用 "host | " 作为行键。然后您可以执行 Range Scan 并从单个 Get / Scan.
中获取条目另一个更新
HBase支持基于行键前缀的范围扫描。所以你有 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
提供了一系列要搜索的行键。
首先,您的 rowkey 设计应该是完美的,您可以根据它定义要查询的访问模式。
1) 如果您知道可以预先访问哪些行键,那么获取就很好
在这种情况下,您可以使用如下方法,它将 return 结果数组。
/**
* 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)
In my experience with Hbase Scan performance is bit low if we dont have perfect rowkey design. I recommend if you are opting for scan for the above mentioned scenario by you.
FuzzyRowFilter(see hbase-the-definitive) This is really useful in our case We have used bulk clients like map-reduce as well as standalone hbase clients
此过滤器以模糊方式作用于行键。它需要一个应该 returned 的行键列表,以及一个附带的 byte[] 数组,表示行键中每个字节的重要性。构造函数是这样的:
FuzzyRowFilter(List<Pair<byte[], byte[]>> fuzzyKeysData)
fuzzyKeysData 通过取两个值之一来指定行键字节的重要性:
0 Indicates that the byte at the same position in the row key must match as-is. 1 Means that the corresponding row key byte does not matter and is always accepted.
示例:部分行键匹配 一个可能的例子是匹配部分键,但不是从左到右,而是在复合键内的某个地方。假设一个行键格式为_,有固定长度的部分,其中是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();
示例代码还在扫描中添加了过滤列,只是为了保持输出简短:
正在向 table 添加行... 扫描结果:
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}
测试代码接线向table添加20行,命名为row-01到row-20。我们想要检索与模式 row-?5 匹配的所有行,换句话说,所有以数字 5 结尾的行。上面的输出确认了正确的结果。