python中,用pyspark读取Hbase数据,并转换为dataframe格式

本文介绍如何使用PySpark连接Spark并从HBase读取数据,包括设置配置、读取数据为RDD格式及转换为DataFrame的方法。文章还提供了解决HBase列长度不一致问题的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需要完成的关键三个点分别是,设置好连接spark的配置,通过spark从hbase中将数据读进来为rdd格式,然后将rdd格式的数据转换成dataframe的格式。

1、首先需要设置pyspark连接spark的配置,spark连接有sparkcontext和sparksession这两种方式,同时这两种方式之间可以互相转换,连接代码如下:

(1)通过SparkConf和SparkContext连接

from pyspark import SparkConf, SparkContext
 
spark_host = "spark://spark-master:7077"   #spark集群的地址,如果是本地单机版的,设置为local[x],x为使用的核数,单机版的即为线程数
app_name = "test"
 
# 设置连接配置,这里的1g是设置使用的核数
spark_conf = SparkConf().setMaster(spark_host).setAppName(app_name).set("spark.executor.memory", "1g")
spark_context = SparkContext.getOrCreate(conf=spark_conf)
 
# sparkContext 也可以通过下面的语句转换成sparkSession对象
from pyspark.sql import SparkSession
spark_session = SparkSession(spark_context)
(2)通过sparkSession连接,个人觉得这种方式更简洁,因为一句话就搞定了,啊哈哈

from pyspark.sql import SparkSession
 
spark_host = "spark://spark-master:7077"
app_name = "test"
 
spark_session = SparkSession.builder.master(spark_host).appName(app_name).getOrCreate()
2、pyspark读取HBASE的数据,读取完后的数据为RDD格式,代码如下:

hbase_host = ""
table_name = ""
 
"""
(1)pyspark读取hbase的时候可以根据hbase中record的row_key进行筛选,但是这个筛选是连续的一片式的筛选
(2)hbase的row_key筛选可以通过前缀进行模糊匹配,比如下面的'2019-04-29_'可以取row_key前缀是2019-04-29_的行,设置的stop则是表示以前缀是2019-04-30_的record结束(但是返回结果不包含满足stop前缀的record)
(3)hbase.mapreduce.scan.columns的设置是选取想要读取的hbase中的基本列以{列簇名:列名}的形式表示一列,不同的列之间用空格隔开
"""
conf = {
        "hbase.zookeeper.quorum": hbase_host,
        "hbase.mapreduce.inputtable": table_name,
        "hbase.mapreduce.scan.row.start": '2019-04-29_',
        "hbase.mapreduce.scan.row.stop": '2019-04-30_',
        "hbase.mapreduce.scan.columns": "family1:column1 family1:column2 family2:column1"
    }
keyConv = "org.apache.spark.examples.pythonconverters.ImmutableBytesWritableToStringConverter"
valueConv = "org.apache.spark.examples.pythonconverters.HBaseResultToStringConverter"
 
# pysaprk连接hbase目前只能通过sparkContext对象,所以这里用的前面设置的spark_context 
hbase_rdd = spark_context.newAPIHadoopRDD("org.apache.hadoop.hbase.mapreduce.TableInputFormat",
                                           "org.apache.hadoop.hbase.io.ImmutableBytesWritable",
                                                   "org.apache.hadoop.hbase.client.Result", 
                                            keyConverter=keyConv,
                                            valueConverter=valueConv,
                                            conf=conf)
 
# 如果想通过sparkSesssion对象连接hbase,代码如下
hbase_rdd = spark_session.saprkContext.newAPIHadoopRDD("org.apache.hadoop.hbase.mapreduce.TableInputFormat",
                                           "org.apache.hadoop.hbase.io.ImmutableBytesWritable",
                                                   "org.apache.hadoop.hbase.client.Result", 
                                            keyConverter=keyConv,
                                            valueConverter=valueConv,
                                            conf=conf)
3、将读取的rdd格式的数据转换为dataframe格式,便于后续计算

        这一块曾经多次采坑,大概原因是跟hbase的表结构(非关系型)有关。因为hbase本身在生成record的时候,有些列值可以不赋值,然后spark读进来的时候,那些值也不会自动给你赋值为null,这就会导致你读取的每一条record的列长度可能不一样,hbase中你这条记录存了几个列值,那么读进来的就只有几个列值。

        所以pyspark本身的rdd.toDF()这个函数根本用不了,这个函数只适合那些列数都一样的数据。下面的代码是根据网上找到的一个版本的代码进行修正改进之后的代码。

""" 
这个函数是一行一行读取hbase_rdd中的record,然后将每个列里面的数据提取出来,最终形成一个dict,这个dict的结构
大概是这样的{column_name1:value1, column_name2:value2, column_name3:value3},如果hbase里面有些列没有值,就是
压根没存这个字段,可以给这个字段填充一个“Null”值,以便后续可以转为dataframe格式(但是这里的“Null”就是一个字
符串,和dataframe里面本身没有值自动默认为的“Null”是不一样的,前者在用filter这个函数是,条件要写“!=Null”,而后
者则需要用“isNotNull()”这个函数)
"""
import json
def row_transform(row_cells_info, hbase_structure):
    row_cell_info_list = [json.loads(i) for i in row_cells_info]
    row_dict = {}
 
    hbase_index = 0
    for cell_index in range(len(row_cell_info_list)):
        column_name = row_cell_info_list[cell_index]['qualifier']
        column_value = row_cell_info_list[cell_index]['value']
        if hbase_structure[hbase_index] == column_name:
            row_dict[column_name] = column_value
            hbase_index += 1
        else:
            row_dict[hbase_structure[hbase_index]] = "Null"
            for j in range(hbase_index + 1, len(hbase_structure)):
                if hbase_structure[j] == column_name:
                    row_dict[column_name] = column_value
                    hbase_index = j + 1
                    break
                else:
                    row_dict[hbase_structure[j]] = "Null"
    for j in range(hbase_index, len(hbase_structure)):
        row_dict[hbase_structure[j]] = "Null"
    return row_dict
 
"""
将HBase RDD转换为DataFrame,这里的hbase_structure对应的是hbase中数据的列名list,如[column_name1,column_name2,column_name3]
并且元素的顺序与hbase中列的顺序对应
"""
def rdd_to_df(hbase_rdd, hbase_structure):
    # 同一个RowKey对应的列之间是用\n分割,进行split,split后每列是个dict
    data_rdd_split = hbase_rdd.map(lambda x: (x[0], x[1].split('\n')))
    # 提取列名和取值
    data_rdd_columns = data_rdd_split.map(lambda x: (x[0], row_transform(x[1], hbase_structure)))
 
    data = data_rdd_columns.map(lambda x: [x[0]] + [x[1][i] for i in x[1]])
 
    data_df = sess.createDataFrame(data, ["row_key"] + hbase_structure)
 
    return data_df
 
if __name__ == '__main__':
    hbase_rdd = load_from_hbase()  #可以用前面1和2步的代码读取hbase的数据读为rdd
 
    # 将 rdd格式转换成dataframe格式
    hbase_structure = [column_name1,column_name2,column_name3]
    hbase_df = rdd_to_df(hbase_rdd, hbase_structure)
由于代码都是项目中的记录,所以没有运行结果,因为现在写博客的环境没有代码运行的环境,但是代码都是从项目代码里面直接抠出来的,都是亲测没问题的。

话说这样读hbase的数据其实挺麻烦的,如果可以的话(对数据速度要求不是太高),可以将hbase的数据映射成Hive的表(这个其实非常好操作),然后pyspark读hive的数据就直接是dataframe格式了,不用这样费心来转换格式了。

如果有更好更专业的方式,期待分享!
 

<think>我们参考用户提供的引用[1]和引用[2]中的代码示例,它们都使用了`sc.newAPIHadoopRDD`方法来读取HBase数据。同时,引用[3]提到了一种转换思路(将HBase数据映射到Hive表,然后直接读取Hive表得到DataFrame),但用户明确要求使用Spark读取HBase的示例代码,因此我们主要展示第一种方式。注意:在Spark中读取HBase数据通常需要将HBase的配置(如Zookeeper地址、表名)传递给RDD读取方法。另外,需要指定key和value的转换器。根据引用[1]和[2]的示例,我们可以整合一个基本的读取HBase数据的代码框架。同时,我们需要注意,引用[1]中的代码在valueConv的字符串中有一个逗号写成了点(应该是笔误),我们这里修正一下。步骤:1.创建SparkConf和SparkContext。2.设置HBase配置,包括Zookeeper的地址和要读取的表。3.定义key和value的转换器(使用Spark自带的转换器)。4.使用`newAPIHadoopRDD`方法读取数据,得到RDD。5.对RDD进行操作(如count,collect等)。另外,引用[4]提到了一种使用SparkSQL读取HBase数据的方式,但需要特定的包。这里用户没有提供具体的包,所以我们先使用基本的方法。注意:使用这种方式读取HBase需要确保Spark的类路径中包含HBase的相关jar包。通常,在提交Spark作业时需要指定这些jar包。下面提供示例代码:</think> ### 使用 PySpark 读取 HBase 数据的解决方案 根据站内引用和最佳实践,以下是使用 Python Spark 读取 HBase 数据的完整示例代码,包含三种常用方式: #### 方式1:使用 `newAPIHadoopRDD` 基础读取(适合全表扫描) ```python #!/usr/bin/env python3 from pyspark import SparkConf, SparkContext # 初始化 Spark 环境 conf = SparkConf().setMaster("local").setAppName("HBaseReader") sc = SparkContext(conf=conf) # HBase 配置参数 hbase_conf = { "hbase.zookeeper.quorum": "localhost", # Zookeeper 地址 "hbase.mapreduce.inputtable": "student", # 目标表名 "hbase.scan.cache": "100", # 每次扫描缓存行数 "zookeeper.znode.parent": "/hbase" # HBase 根路径(集群配置) } # 键值转换器 key_conv = "org.apache.spark.examples.pythonconverters.ImmutableBytesWritableToStringConverter" value_conv = "org.apache.spark.examples.pythonconverters.HBaseResultToStringConverter" # 读取 HBase 数据 hbase_rdd = sc.newAPIHadoopRDD( inputFormatClass="org.apache.hadoop.hbase.mapreduce.TableInputFormat", keyClass="org.apache.hadoop.hbase.io.ImmutableBytesWritable", valueClass="org.apache.hadoop.hbase.client.Result", keyConverter=key_conv, valueConverter=value_conv, conf=hbase_conf ) # 数据处理示例 print("总记录数:", hbase_rdd.count()) for row_key, row_data in hbase_rdd.take(3): print(f"RowKey: {row_key}, Data: {row_data}") ``` #### 方式2:通过 Phoenix 高效查询(推荐生产环境) ```python from pyspark.sql import SparkSession spark = SparkSession.builder \ .appName("PhoenixReader") \ .config("spark.jars.packages", "org.apache.phoenix:phoenix-spark:5.0.0-HBase-2.0") \ .getOrCreate() # 构建 Phoenix 查询 df = spark.read \ .format("org.apache.phoenix.spark") \ .option("table", "student") \ .option("zkUrl", "localhost:2181:/hbase") \ .load() # 执行 SQL 查询 df.createOrReplaceTempView("students") result = spark.sql("SELECT name, age FROM students WHERE grade > 80") result.show(5) ``` #### 方式3:转换DataFrame(需添加数据处理) ```python from pyspark.sql import Row # 转换函数 def parse_hbase_record(row): cols = row[1].split(';') return Row( rowkey=row[0], name=cols[0].split(':')[1], age=int(cols[1].split(':')[1]) ) # 转换 RDD → DataFrame parsed_rdd = hbase_rdd.map(parse_hbase_record) df = spark.createDataFrame(parsed_rdd) df.printSchema() df.show() ``` ### 关键配置说明 1. **依赖配置**: - 必须包含 HBase 和 Phoenix 的 Jar 包 - 提交命令示例: ```shell spark-submit --packages org.apache.hbase:hbase-client:2.4.9,org.apache.phoenix:phoenix-spark:5.0.0-HBase-2.0 your_script.py ``` 2. **配置优化**: ```python # 增加扫描缓存提升性能 hbase_conf["hbase.client.scanner.caching"] = "1000" # 设置批量处理大小 hbase_conf["hbase.htable.threads.max"] = "8" ``` 3. **查询过滤**: ```python # 添加 RowKey 范围过滤 hbase_conf["hbase.mapreduce.scan.row.start"] = "user100" hbase_conf["hbase.mapreduce.scan.row.stop"] = "user200" ``` ### 常见问题解决 1. **ClassNotFound 错误**: 确保包含所有 HBase 相关依赖包[^1][^2] 2. **连接超时**: 检查 `hbase.zookeeper.quorum` 和 `zookeeper.znode.parent` 配置是否正确[^2] 3. **性能优化**: - 避免全表扫描,使用 RowKey 范围查询 - 批量读取设置合适的缓存大小[^1][^2] > 注意:直接读取 HBase 适合批量处理,实时查询推荐 Phoenix 方案[^3][^4]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值