我使用Hbase和Spark。我需要按状态(可能是0、1、2、3)从表中获取经过过滤的数据。我只需要状态为0的数据-这大约是Hbase中所有数据的5%。
什么会更快-将过滤器用于在Hbase上扫描或将Spark过滤器用于已读取所有Hbase数据的所有数据的rdd?
为什么?它取决于什么?
Scan scan = new Scan();
scan.setFilter(new SingleColumnValueFilter(...));
JavaRDD<MyType> rdd = <get data from table with scan>
OR
JavaRDD<MyType> rdd = <get all data from table with new Scan()>
rdd.filter(r->r.getStatus()==0)
答案 0 :(得分:1)
在HBase端按列值进行过滤意味着速度较慢,因为这需要遍历整个表(速度到底有多慢取决于数据大小)。另一方面,不对HBase端进行过滤意味着您必须首先将ENTIRE表转移到Spark端,然后再通过Spark对其进行过滤,不是吗?考虑到您的目标值仅代表整个数据的5%,我想这可能是一个过大的选择。不确定要处理的数据大小,但这可能会对内存(服务器端和客户端)以及网络流量产生重大影响。考虑到所有这些,我认为您使用Spark过滤器的情况会更糟(顺便说一句,就我所知,它并不一定要那么快)
答案 1 :(得分:1)
确定要在HBase中进行更快的扫描,可以尝试查看FuzzyRowFilter。 https://hbase.apache.org/apidocs/org/apache/hadoop/hbase/filter/FuzzyRowFilter.html
这种过滤器的作用是跳过与指定模式不匹配的行键,从而使扫描速度更快。它也需要部分模式。
因此,在您的情况下,您的状态必须是行键的一部分。
答案 2 :(得分:0)
为什么不使用DS / DF代替RDD?因为后者会随着时间的流逝而消失。
请参见https://blog.cloudera.com/spark-hbase-dataframe-based-hbase-connector/
我的观点是,由于无法使用Catalyst Optimizer-afaik禁用谓词下推,因此使用DF / DS的示例将得出相同的物理计划。因此,从这个意义上讲,性能不会有差异。如果有一个缓存,那么我们可以看到它被禁用了-参见How to prevent predicate pushdown?。
现在,我注意到(随着时间的流逝)有不同的连接器,所以根据您使用的连接器类型,可能会有不同的方法。我们似乎已经从需要谓词下推的时期过渡到了通常无法禁用它的时期。
无论如何,通常来说,您的5%数据样本对我来说是希望进行谓词下推的标志。
答案 3 :(得分:0)
也许您可以尝试这样的事情?我很快就得到了结果。
val scanner = new Scan()
val filter = new SingleColumnValueFilter(colFamily.getBytes, <column name>.getBytes, CompareOp.EQUAL, dt.getBytes)
scanner.setFilter(filter)
val conf = HBaseConfiguration.create()
conf.set(TableInputFormat.INPUT_TABLE, table.getName.toString)
conf.set(TableInputFormat.SCAN, convertScanToString(scanner))
val dictRDD = sc.sparkContext.newAPIHadoopRDD(
conf,
classOf[TableInputFormat],
classOf[ImmutableBytesWritable],
classOf[Result]
)
您将需要此功能:
private def convertScanToString(scan: Scan): String = try {
val proto = ProtobufUtil.toScan(scan)
Base64.encodeBytes(proto.toByteArray)
} catch {
case e: Exception =>
e.printStackTrace()
""
}