Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/apache-spark/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Apache spark 如何使用Spark中的行键列表并行读取Hbase_Apache Spark_Hbase - Fatal编程技术网

Apache spark 如何使用Spark中的行键列表并行读取Hbase

Apache spark 如何使用Spark中的行键列表并行读取Hbase,apache-spark,hbase,Apache Spark,Hbase,我有650万行键,希望在spark job中从hbase检索数据。如何并行地从hbase检索结果 我认为这个片段不会在执行者身上运行 List<Get> listOFGets = new ArrayList<Get>(); Result[] results = Htable.get(listOFGets); 通过以适合您的方式创建RDD,然后调用JavaHBaseContext对象的method.foreachPartition,可以在执行器上运行并行扫描。这样,HBa

我有650万行键,希望在spark job中从hbase检索数据。如何并行地从hbase检索结果

我认为这个片段不会在执行者身上运行

List<Get> listOFGets = new ArrayList<Get>();
Result[] results = Htable.get(listOFGets);

通过以适合您的方式创建RDD,然后调用JavaHBaseContext对象的method.foreachPartition,可以在执行器上运行并行扫描。这样,HBaseContext将连接实例详细信息传递给函数类的每个实例,在该函数中,您可以通过获取表等方式进行扫描

如何创建RDD来适应这一点,以及它应该有多少元素取决于您,只要确保它具有您想要的并行扫描分区数量即可。根据我的经验,您可以在spark上运行许多并发任务,当然,您可以根据您的HBase群集强度执行许多并行扫描

Java代码可以如下所示:

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
}
}
关于master:

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
}
}

这应该在所有执行器上并行运行扫描

我通常使用hbase扫描,使用.newAPIHadoopRDD方法。注意,这是scala与JavaAPI的一个非常丑陋的混合体。您可以传入任意行键列表,空列表返回表中的所有记录。如果行键不是长编码的,则可能需要稍微修改代码

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步骤中将出现单核心挂起。此方法可以扩展为在创建扫描过滤器之前,将密钥列表排序和合并到密钥范围的过程并行化。在排序和合并之后,此方法实际上可以并行地跨多个分区(如有多个区域),如果有多个连续的行键范围,甚至可以减少到hbase的往返次数


很难说这个过程对您来说是否比在集群中传播随机访问更有效,因为它完全取决于许多因素:记录大小、表大小、行键范围等。我相信对于许多用例,这种方法会更有效,但显然不是每个用例都适用。

您可以尝试这样的方法:这不是正确的方法。或者,您甚至可以在spark而不是htable上花费大量时间来监视此逻辑。在java上使用“不正确”是不正确的评估。这种方法在从hbase检索数据时确实是并行的,但我承认它有一个弱点,可以改进,如edit.Great中所述。接受答案,以便其他人将来知道这是可行的。