我有650万行键,想从 spark-job 中的hbase检索数据。如何从hbase并行检索结果?
我认为该代码段不会在执行程序上运行。
List<Get> listOFGets = new ArrayList<Get>();
Result[] results = Htable.get(listOFGets);
答案 0 :(得分:0)
您可以通过创建RDD
(以适合您的任何一种方式)然后调用.foreachPartition
对象的方法JavaHBaseContext
来对执行程序执行并行扫描。这样,HBaseContext
会将Connection
实例详细信息传递给函数类的每个实例,在该函数内部,您可以通过获取表等进行扫描。
由您决定如何创建RDD以适应此问题,以及应具有多少个元素(只需确保它具有与并行扫描一样多的分区)。以我的经验,您可以在spark上运行许多并发任务,可以执行许多并行扫描(当然,这取决于您的HBase集群强度)。
Java代码可能如下所示:
在主控上:
JavaHBaseContext hBaseContext = new JavaHBaseContext(sparkContext, HBaseConfig);
JavaRDD<blah> myRDD = ... (create an RDD with a number of elements)
hBaseContext.foreachPartition(myRDD, new MyParFunction());
您的函数类将如下所示:
class MyParFunction implements VoidFunction<Tuple2<Iterator<blah>, Connection>>
{
@Override
public void call(Tuple2<Iterator<blah>, Connection> t) throws Exception
{
// Do your scan here, since you have the Connection object t
}
}
这应该在所有执行程序上并行运行扫描
答案 1 :(得分:0)
我通常使用.newAPIHadoopRDD()
方法进行hbase扫描。请注意,这是Scala与Java API的相当丑陋的组合。您可以传入行键的任意列表(空白列表将返回表中的所有记录)。如果您的行键不是长编码的,那么您可能需要稍微修改一下代码。
def hbaseScan(ids: List[Long]): Dataset[Result] = {
val ranges = ListBuffer[MultiRowRangeFilter.RowRange]()
//converts each id (Long) into a one element RowRange
//(id gets implicitly get converted to byte[])
ids.foreach(i => {
ranges += new MultiRowRangeFilter.RowRange(i, true, i + 1, false)
})
val scan = new Scan()
scan.setCaching(1000) /* fetch 1000 records in each trip to hbase */
scan.setCacheBlocks(false) /* don't waste hbase cache space, since we are scanning whole table
if (ranges.nonEmpty) {
//The list of RowRanges is sorted and merged into a single scan filter
scan.setFilter(new MultiRowRangeFilter(MultiRowRangeFilter.sortAndMerge(ranges.asJava)))
}
val conf = HBaseConfiguration.create()
conf.set(TableInputFormat.INPUT_TABLE, HBASE_TABLE /*set your table name here*/)
conf.set(TableInputFormat.SCAN, scan)
spark.sparkContext.newAPIHadoopRDD(
conf,
classOf[TableInputFormat],
classOf[ImmutableBytesWritable],
classOf[Result]
).toDF("result").as[Result]
}
这将返回一个Dataset[Result]
,其分区数与扫描表中的区域相同。抱歉,我没有任何等效的Java代码可以共享。
编辑:处理不正确的注释
我应该以为这个方法在读取整个hbase表或少量任意行键时效果最好。我的用例正好同时完成了这两个操作,因为我总是一次查询1000个行键或整个表,而中间却什么也没有。
如果任意行键的数量很大,则MultiRowRangeFilter.sortAndMerge()
步骤将挂断一个核心。可以扩展此方法,以在创建用于扫描的Filter
之前,将键列表排序和合并到键范围中的过程并行化。排序和合并后,此方法的确确实可以在您拥有区域的多个分区上并行运行,并且如果您有许多连续的行键范围,甚至可以减少往返hbase的次数。
很难说这个过程是否比在整个集群上散布随机数据更为有效,因为它完全取决于许多因素:记录大小,表大小,行键范围等。我相信许多用例中,这种方法会更有效,但显然不是每个用例都可以。