hbase中sum结果为NULL的问题:AggregationClient执行聚合sum时,给scan添加列过滤器后,sum结果为 null

 

1. 情况说明

在使用hbase-endpoint依赖中的AggregationClient类,对hbase执行sum操作时,当scan不设置 filter时可以正常得到 sum的结果,但是设置filter之后,sum的结果就为 null。

1.1 不设置filter时的执行结果

不设置filter时的代码如下:

        String tableName = "hbaseTableName";
        String cf = "f";
        String col_ORG_ID = "ORG_ID";  // 在hbase列名是 ORG_ID
        Scan scan = new Scan();

        scan.addFamily(cf.getBytes());
        scan.addColumn(cf.getBytes(), col_ORG_ID.getBytes());
        AggregationClient ac = new AggregationClient(config.getHbaseConfiguration());
        DoubleColumnInterpreter columnInterpreter = new DoubleColumnInterpreter();
        Double sum = ac.sum(TableName.valueOf(tableName), columnInterpreter, scan);
        log.info("sum result [{}]", sum);

上述代码会对hbase表里的ORG_ID进行求sum操作。执行sum的结果是

sum result [18.8]

可以对某列执行求sum操作。

1.2 设置filter后执行结果为 null

这是filter的代码如下:

        String tableName = "hbaseTableName";
        String cf = "f";
        String col_ORG_ID = "ORG_ID";  // 在hbase列名是 ORG_ID
        Scan scan = new Scan();

        // 为scan设置filterList
        List<Filter> filters = new ArrayList<>();
        SingleColumnValueFilter scvf = new SingleColumnValueFilter(Bytes.toBytes(cf), Bytes.toBytes(col_ORG_ID), CompareOperator.EQUAL, Bytes.toBytes("100.05"));
        filters.add(scvf);
        scvf.setFilterIfMissing(true);
        FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL,filters);
        scan.setFilter(filterList);

        //对列进行求sum操作
        scan.addFamily(cf.getBytes());
        scan.addColumn(cf.getBytes(), col_ORG_ID.getBytes());
        AggregationClient ac = new AggregationClient(config.getHbaseConfiguration());
        DoubleColumnInterpreter columnInterpreter = new DoubleColumnInterpreter();
        Double sum = ac.sum(TableName.valueOf(tableName), columnInterpreter, scan);
        log.info("sum result [{}]", sum);

此时输出结果是: sum result [null]

为什么添加Filter后,再执行sum的结果就为null了呢。

2. 问题分析

为什么添加Filter后,再执行sum的结果就为null了呢。

经过分析,在SingleColumnValueFilter和Filter一起使用时,创建一个SingleColumnValueFilter对象,就需要在scan添加上这一列,加上如下代码就好了,因为 只有当COLUMNS中包含SingleColumnValueFilter提到的字段时, 该SingleColumnValueFilter才有效的 。(参考这篇文章的讲解):

scan.addColumn(cf.getBytes(), col_ORG_ID.getBytes());

2.2 注意事项

在创建SingleColumnValueFilter对象时,需要注意设置列的值时,注意区分数值型(Double)和字符串类型(String)的区别。

如果为这一列的值是String类型,使用下面的赋值方式:

new SingleColumnValueFilter(Bytes.toBytes(cf), Bytes.toBytes("TRX_DISC_AT" ), CompareOperator.EQUAL, Bytes.toBytes("50.3"));

如果这一列的值类型是Double,则需要使用下面的创建方法:

要将列值转化为对应的数值类型,例如Double类型:Double.valueOf("50.3")

new SingleColumnValueFilter(Bytes.toBytes(cf), Bytes.toBytes("TRX_DISC_AT" ), CompareOperator.EQUAL, Bytes.toBytes(Double.valueOf("50.3")));

 

这里还有一个坑,就是要添加的SingleColumnValueFilter列(例如column_02)如果是数值型,则在最终的计算结果中,也会将这一列也统计进去,即最后的结果是sum(column_01) + sum(column_02)。这时候就需要将最终的计算结果再减去这一列sum(column_02)的值。

如果在求sum时,不想统计sum(过滤列),则可以使用 SingleColumnValueExcludeFilter ,因为SingleColumnValueExcludeFilter会将该字段排除,仅仅用于过滤使用。

 

还是要多了解下hbase中的数据类型,例如string和数值型double的使用区别的

3. 结论

3.1 SingleColumnValueFilter列添加到scan对象中

使用SingleColumnValueFilter时,只有当scan的COLUMNS中包含SingleColumnValueFilter提到的字段时, 该SingleColumnValueFilter才有效的。[参考这里 => SingleColumnValueFilter should be able to find the column value even when it's not specifically added as input on the scan.]

即把col这一列添加到scan对象中去

//为scan添加列
scan.addColumn(cf.getBytes(), col.getBytes());

3.2 使用替代的SingleColumnValueExcludeFilter类

使用SingleColumnValueExcludeFilter这时只会返回除开AREA_ID和TIME_ID的字段, 但记录数是对的。这样就不用再手动把过滤列添加到scan对象了

 

3.3 的区别

请参考这一篇文章 SingleColumnValueFilter 和 SingleColumnValueExcludeFilter的区别

 

 

4. 参考链接

https://blog.youkuaiyun.com/zhangjianying/article/details/8628249  (重点参考下这篇,分析的比较详细)

http://www.bubuko.com/infodetail-542553.html

https://issues.apache.org/jira/browse/HBASE-2198

https://issues.apache.org/jira/browse/HBASE-2211

http://www.bubuko.com/infodetail-542553.html

https://bbs.youkuaiyun.com/topics/390223353

 

<think>我们正在处理用户的问题:yarn运行程序后,使用HBaseshell查询不到数据,需要分析可能的原因。用户提供了几个引用,其中涉及HBase的使用注意事项、HBaseshell的特性、创建表的命令以及一个大数据分析项目的描述。根据引用内容,我们注意到以下几点可能与问题相关:[^1]:强调名大小写必须正确,如果名写错,HBase不会报错,因为HBase是无模式的。[^2]和[^3]:介绍了HBaseshell是JRuby的IRB,并给出了创建表的示例。用户的问题是在YARN(运行MapReduce或Spark等程序)将数据写入HBase之后,通过HBaseshell查询不到数据。可能的原因分析如下:1.**写入程序没有正确提交到YARN或运行失败**:首先确认程序是否真正运行成功。可以检查YARN的应用程序状态(通过yarnapplication-list或查看YARN的WebUI)和日志,确认程序是否成功执行,且没有抛出异常。2.**写入程序配置问题**:-程序配置的HBase表名是否正确?是否与HBase中存在的表名一致(包括大小写)?-程序配置的簇名和名是否正确?注意HBase是区分大小写的,且名需要完整(包括簇前缀)。-程序是否真正执行了写入操作?例如,在MapReduce中,需要确保在Reducer或最后的OutputFormat中正确写入了数据。3.**HBase表是否存在**:如果程序在写入之前会创建表,那么创建表的代码是否执行?或者表是否已经存在?如果表不存在,写入操作可能会失败。但注意,有些程序配置(如自动创建表)可能会在第一次写入创建表,但这需要确保配置正确。4.**HBase写入延迟(WAL或MemStore)**:HBase写入数据,会先写入WriteAheadLog(WAL)和内存(MemStore),当MemStore满才会刷写到磁盘(形成StoreFile)。因此,刚写入的数据可能还未刷写,而HBaseshell的scan命令默认是读取最新数据,但如果RegionServer尚未刷新,或者存在间戳问题,也可能看不到。可以尝试在写入后执行flush操作,或者检查间戳。5.**命名空间问题**:HBase表可能有命名空间(namespace),例如创建表使用了`namespace:tablename`,而程序写入可能没有指定命名空间,或者指定了默认的命名空间(default)导致写入到另一个表中。6.**数据是否被写入到正确的RowKey**:程序写入的RowKey是什么?在查询使用的RowKey范围是否正确?如果scan没有指定范围,默认扫描整个表,但要注意RowKey的分布。另外,RowKey的二进制编码问题也可能导致查询不到。7.**HBase客户端配置问题**:运行程序的集群(YARN)与HBase集群是否在同一网络?客户端配置(hbase-site.xml)是否正确?特别是ZooKeeper的地址。8.**HBase权限问题**:运行YARN任务的用户是否有权限写入HBase表?可以通过HBase的ACL检查。9.**程序逻辑问题**:程序是否有条件写入?例如,某些条件不满足导致跳过写入。或者写入的数据量很小,RowKey分布很特殊,扫描没有覆盖到。10.**HBaseshell查询方式问题**:是否因为HBaseshell的查询条件不正确?例如,引用[^1]中提到,名写错了查不出数据也不会报错。另外,注意使用正确的过滤器Filter)格式。11.**版本问题**:如果写入的数据有版本号(timestamp),而查询指定的版本不对,也可能查询不到。12.**HBase集群状态**:检查HBase集群状态是否正常,各个RegionServer是否在线?是否有Region在切换?针对以上可能的原因,我们可以建议用户逐步排查:步骤1:验证程序运行成功-通过YARN的WebUI或命令行`yarnapplication-list-appStatesALL`查看程序状态,确保程序成功运行(SUCCEEDED)。步骤2:验证HBase表结构-使用HBaseshell的`list`命令查看表是否存在。-使用`describe'TABLE_NAME'`查看表结构,确保程序写入的簇和名与表结构一致。步骤3:手动写入测试-HBaseshell中手动插入一条数据,然后查询,确认HBaseshell操作正常,且能立即查询到(注意:如果立即scan可能看不到,因为MemStore未刷新,可以尝试刷新表:`flush'TABLE_NAME'`)。-使用`put`命令插入一条数据,再使用`scan`扫描整个表或`get`指定rowkey查看。步骤4:检查程序写入的RowKey-如果可能,在程序中打印写入的RowKey,然后尝试在HBaseshell中使用`get`命令通过该RowKey查询。步骤5:检查HBase配置-确保程序使用的HBase配置文件(hbase-site.xml)正确,尤其是ZooKeeper的地址。步骤6:检查程序写入代码-仔细检查写入HBase的代码,例如在MapReduce中,检查OutputFormat的配置,写入的Put对象是否正确。步骤7:查看HBase日志-查看HBaseRegionServer的日志,是否有异常信息。步骤8:考虑间因素-如果是批量写入,数据可能还在缓存中,可以尝试手动刷新表,或者稍等片刻再查询。步骤9:使用其他工具查看-可以使用HBase的JavaAPI写一个小程序读取数据,或者使用HBase的WebUI查看表的region分布和存储大小。由于引用中特别提到名大小写问题,以及HBaseshell中创建表的命令,因此需要特别关注表名、簇名和名的大小写问题。确保程序中写入的名(包括簇)与HBaseshell中的完全一致(包括大小写)。根据引用[^1],在HBaseshell中查询名STATUS必须大写。同样,程序中写入的名也必须匹配。示例:如果表ORDER_INFO的簇C1中有一个名为status,但程序中写入了大写的STATUS,则两者不匹配,无法查询到。另外,引用[^3]给出了创建表命令:`create'ORDER_INFO','C1'`,所以如果程序写入的簇名是`c1`(小写)而不是`C1`(大写),则会出现问题。因此,建议用户检查程序中写入的簇名和名与创建表使用的是否一致(包括大小写)。最后,引用[^4]提到的大数据分析项目,虽然与问题没有直接关系,但提醒我们可能涉及MapReduce、Hive等组件的使用。如果用户使用的是MapReduce写入HBase,那么需要检查MapReduce作业的配置和输出步骤。我们将按照这些思路为用户解答。生成相关问题:1.HBase写入后如何手动刷新MemStore?2.如何检查HBase表的结构?3.如何在YARN上查看应用程序的日志?4.如何确认HBase的客户端配置是否正确?5.HBase簇和名的大小写敏感吗?6.为什么HBasescan命令使用过滤器会查不到数据?7.MapReduce写入HBase的基本步骤是什么?8.HBase的命名空间如何指定?</think> ### YARN运行程序后HBase Shell查询不到数据的原因分析 #### 1. **数据写入异常** - **程序未正常提交**:YARN任务可能未成功提交或中途失败。使用 `yarn application -list` 查看任务状态,通过 `yarn logs -applicationId <应用ID>` 检查日志中的错误信息[^2]。 - **写入逻辑错误**:程序中的HBase写入代码(如 `Put` 操作)可能存在逻辑错误,或未正确关闭连接(`Table.close()`),导致数据未持久化。 #### 2. **表结构不匹配** - **名/簇大小写问题**:HBase严格区分大小写。若写入代码中的名(如 `STATUS`)与表结构(如 `status`)不一致,数据会写入但无法查询(无报错)[^1]。 - **簇未创建**:若程序写入前未显式建表,且未开启自动建表(`hbase.table.create.enabled=false`),数据可能写入失败。 #### 3. **查询方式错误** - **间范围限制**:HBase默认只返回最新版本数据。若写入间戳与查询间不匹配,需显式指定间范围: ```bash scan 'ORDER_INFO', {TIMERANGE => [开始间戳, 结束间戳]} ``` - **过滤器语法错误**:Shell过滤器的值需明确编码类型。例如: ```bash # 正确:指定binary编码 scan 'ORDER_INFO', {FILTER => "SingleColumnValueFilter('C1','STATUS',=,'binary:已付款')"} ``` 若忽略 `binary:` 前缀,查询会失败[^1]。 #### 4. **数据未持久化** - **WAL未同步**:若写入关闭WAL(`Put.setDurability(false)`),RegionServer宕机可能导致数据丢失。 - **MemStore未刷盘**:数据暂存内存(MemStore),未达到刷写阈值(`hbase.hregion.memstore.flush.size`),Shell查询不到。手动刷盘解决: ```bash flush 'ORDER_INFO' ``` #### 5. **集群配置问题** - **ZooKeeper连接错误**:程序与HBase Shell使用的ZooKeeper地址(`hbase.zookeeper.quorum`)不一致,导致访问不同集群。 - **HBase版本冲突**:YARN任务依赖的HBase客户端版本与集群版本不兼容,可能引发序化异常。 --- ### 排查步骤 1. **确认写入成功** - 检查YARN日志,确认任务状态为 `SUCCEEDED`。 - 在程序代码中增加写入计数器,确保 `put` 操作执行。 2. **验证表结构与名** ```bash describe 'ORDER_INFO' # 检查簇C1和名STATUS的大小写 ``` 3. **检查数据是否存在** ```bash scan 'ORDER_INFO', {LIMIT => 10} # 全表扫描前10行 get 'ORDER_INFO', '指定RowKey' # 按RowKey查询 ``` 4. **强制刷新与验证** ```bash flush 'ORDER_INFO' # 刷写内存数据 major_compact 'ORDER_INFO' # 合并HFile(测试环境) ``` 5. **跨集群一致性检查** - 比对程序与HBase Shell的配置文件: ```bash hbase shell > status # 查看Shell连接集群 ``` - 确认程序的 `hbase-site.xml` 中ZooKeeper地址正确。 --- ### 常见解决案例 - **案例1**:日志显示写入成功,但Shell查不到 **原因**:程序名写为 `Status`(首字母大写),实际表结构为 `STATUS`(全大写)[^1]。 **解决**:代码中统一大小写或修改表结构。 - **案例2**:YARN任务失败 **原因**:依赖包冲突(如Guava版本)。 **解决**:在 `hadoop classpath` 输出中检查依赖优先级,排除冲突JAR。 - **案例3**:写入后RegionServer宕机 **原因**:WAL未启用导致数据丢失。 **解决**:代码中启用WAL(`Put.setDurability(true)`)。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值