Java 如何在spark中从hbase表中获取所有数据

Java 如何在spark中从hbase表中获取所有数据,java,mapreduce,hbase,bigdata,apache-spark,Java,Mapreduce,Hbase,Bigdata,Apache Spark,我在hbase中有一个很大的表,名为UserAction,它有三个列族(歌曲、专辑、歌手)。我需要从'song'列家族中获取所有数据,作为JavaRDD对象。我试过这个代码,但效率不高。有更好的解决方案吗 static SparkConf sparkConf = new SparkConf().setAppName("test").setMaster( "local[4]"); static JavaSparkContext jsc = new JavaSparkCont

我在hbase中有一个很大的表,名为UserAction,它有三个列族(歌曲、专辑、歌手)。我需要从'song'列家族中获取所有数据,作为JavaRDD对象。我试过这个代码,但效率不高。有更好的解决方案吗

    static SparkConf sparkConf = new SparkConf().setAppName("test").setMaster(
        "local[4]");
static JavaSparkContext jsc = new JavaSparkContext(sparkConf);

static void getRatings() {

    Configuration conf = HBaseConfiguration.create();
    conf.set(TableInputFormat.INPUT_TABLE, "UserAction");
    conf.set(TableInputFormat.SCAN_COLUMN_FAMILY, "song");

    JavaPairRDD<ImmutableBytesWritable, Result> hBaseRDD = jsc
            .newAPIHadoopRDD(
                    conf,
                    TableInputFormat.class,
                    org.apache.hadoop.hbase.io.ImmutableBytesWritable.class,
                    org.apache.hadoop.hbase.client.Result.class);

    JavaRDD<Rating> count = hBaseRDD
            .map(new Function<Tuple2<ImmutableBytesWritable, Result>, JavaRDD<Rating>>() {

                @Override
                public JavaRDD<Rating> call(
                        Tuple2<ImmutableBytesWritable, Result> t)
                        throws Exception {
                    Result r = t._2;
                    int user = Integer.parseInt(Bytes.toString(r.getRow()));
                    ArrayList<Rating> ra = new ArrayList<>();

                    for (Cell c : r.rawCells()) {

                        int product = Integer.parseInt(Bytes
                                .toString(CellUtil.cloneQualifier(c)));
                        double rating = Double.parseDouble(Bytes
                                .toString(CellUtil.cloneValue(c)));

                        ra.add(new Rating(user, product, rating));
                    }

                    return jsc.parallelize(ra);
                }
            })
            .reduce(new Function2<JavaRDD<Rating>, JavaRDD<Rating>, JavaRDD<Rating>>() {
                @Override
                public JavaRDD<Rating> call(JavaRDD<Rating> r1,
                        JavaRDD<Rating> r2) throws Exception {
                    return r1.union(r2);
                }
            });
    jsc.stop();
}

更新:好吧,我现在看到你的问题了,因为一些疯狂的原因,你把你的数组变成了RDD
returnJSC.parallelize(ra)。你为什么这么做??为什么要创建RDD的RDD??为什么不将它们保留为数组?执行reduce时,可以连接数组。RDD是一种抗干扰的分布式数据集—拥有分布式数据集的分布式数据集在逻辑上是没有意义的。我很惊讶你的工作竟然运行而且没有崩溃!不管怎么说,这就是为什么你的工作这么慢

无论如何,在Scala中,在映射之后,只需执行
flatMap(identity)
,即可将所有列表连接在一起

我真的不明白为什么你需要做一个减少,也许这就是你有效率的地方。下面是我用来读取HBase表的代码(它的通用性——即,适用于任何方案)。需要确保的一件事是,当您读取HBase表时,确保分区的数量是合适的(通常您需要很多分区)

type HBaseRow=java.util.NavigableMap[Array[Byte],
java.util.NavigableMap[Array[Byte],java.util.NavigableMap[java.lang.Long,Array[Byte]]]
//映射(CF->Map(列限定符->映射(时间戳->值)))
键入CFTimeseriesRow=Map[Array[Byte],Map[Array[Byte],Map[Long,Array[Byte]]]
def navMapToMap(导航地图:HBaseRow):CFTimeseriesRow=
navMap.asScala.toMap.map(cf=>
(参见图1、图2.asScala.toMap.map(col=>
(第1列,第2列,关联地图(元素=>(元素1.toLong,元素2‘‘‘‘‘‘))
def readTableAll(表格:字符串):RDD[(数组[字节],CFTimeseriesRow)]={
val conf=HBaseConfiguration.create()
conf.set(TableInputFormat.INPUT\u表格,表格)
sc.newAPIHadoopRDD(conf,classOf[TableInputFormat],
classOf[org.apache.hadoop.hbase.io.ImmutableBytesWritable],
classOf[org.apache.hadoop.hbase.client.Result])
.map(kv=>(kv._1.get(),navMapToMap(kv._2.getMap)))
}
如您所见,我的代码中不需要reduce。这些方法是相当自我解释的。我可以深入研究您的代码,但我没有耐心阅读Java,因为它过于冗长

我还有一些代码专门用于从行(而不是整个历史)中获取最新的元素。如果你想看的话,请告诉我


最后,建议您考虑使用Cassandra而不是HBase,因为datastax正在与databricks合作。

或者,我是否应该根据此访问模式创建一个新表?在读取整个表的末尾,您有一个每行的映射。实际上,我已经这样做了,但是我想要一个rdd,它将每一行的所有数据作为一个映射,而不是每一行的不同映射@Samthebest抱歉,我不明白你的意思@FatihYakut,但通过运行reduce,你将得到一个
Rating
而不是一个带有1
Rating
的RDD。还有什么是评级?我不知道
union
方法做什么。提供更多的代码,更加具体,澄清问题,也许有人可以提供帮助。CFTimeseriesRow类型保存一行的所有数据。有许多行,因此将有许多CFTimesPeriesRow。我只想要一个包含所有数据的CFTimeseriesRow。Union操作组合两个rdd并从中生成一个rdd,我在reduce中使用此操作以只有一个rdd。换句话说,为了只有一个CFTimeseriesRow,我将所有CFTimeseriesRow组合在reduce中。顺便说一下,评级有userId、productId和产品的评级值。它用于spark的mllib库中@在RDD上执行reduce也是最好的!!!这太疯狂了,你真的不应该创建RDD的RDD。这就是为什么你的工作做不到的原因!我将更新我的答案以进一步解释@FatihYakutSpark不支持RDD的嵌套;如果使用嵌套RDD编写程序,在尝试对嵌套RDD执行操作时,可能会遇到
NullPointerException
s或其他问题。
RowKey = userID, columnQualifier = songID and value = rating.