Spark(五)

使用Spark进行SQL与NoSQL编程

Spark SQL简介

结构化查询语言(SQL)是最常用的定义和表达数据问题的语言.许多数据分析师拥有把复杂问题解构为一系列SQL数据操作语言(Data Manipulation Language,DML),也就是SELECT语句的能力.

Hive简介

大数据处理平台上很多SQL抽象都基于Hive,Spark就是其中之一.对于Spark SQL这样的项目来说,Hive和Hive元数据库是不可或缺的组件

Apache Hive项目是2010年由Facebook发起,在Hadoop的MapReduce之上提供高层的类SQL抽象.Hive引入了一种新的语言,称为Hive查询语言.

  1. Hive对象和Hive元数据库
    Hive实现了HDFS上对象的表格抽象,在编程模型中把目录和其中所有的文件当作数据表对待.和传统的关系型数据库一样,数据表中的各列都预先定义,并指定了数据类型.HDFS上的数据可以像传统的数据库管理系统一样通过SQL的DML语句访问.然而,Hive与传统数据库系统的相似之处也就仅止于此,毕竟Hive平台是读时系统,且下层存储HDFS是不可变的文件系统.因为Hive只是对HDFS上的原始文件实现了SQL表格抽象,所以和传统的关系型数据库平台有下列几点关键区别:
  • 并不真正支持UPDATE操作.尽管HiveQL中有UPDATE语句,但HDFS是不可变的文件系统,因此UPDATE会是一个粗粒度操作,而在传统关系型数据库中真正的UPDATE操作是只会修改一条记录的细粒度操作.
  • 没有事务、日志、回滚和真正的事务隔离级别。
  • 没有声明引用完整性(DRI),也就是没有主键和外键的概念.
  • 格式错误的数据,比如输入错误或数据错误,只是作为空值传给客户端

数据表与HDFS目录位置的对应关系,以及表中所包含的列和列的定义,都由Hive元数据库维护.元数据库是供Hive客户端读写的数据库.对象定义中还包含文件的输入、输出格式,由表对象和序列化-反序列化方式表示,它们告诉Hive如何从文件中获取记录和其中的字段.
元数据库可以是内嵌的Derby数据库(默认情况),也可以是本地或远程的数据库,比如MySQL或者Postgres.大多数情况下,用户会选择共享的数据库,这可以让开发人员和分析师共享对象定义.

  1. 访问Hive
    Hive提供了命令行界面(CLI)客户端,可以接收并解析所输入的HiveQL命令.这是执行即席查询的常见方式.
    当Hive客户端或驱动器应用以及元数据库连接都部署于本地机器时,会使用Hive CLI.对于大规模部署来说,客户端/服务器的方式更合适,因为这样只要有一台服务器端的机器维护元数据库的连接细节,元数据库的访问权限也可以限定到集群内.这种方式要使用Hive的服务器组件HiveServer2.

  2. Hive数据类型与数据定义语言(DDL)
    和大多数数据库系统类似,Hive支持大多数常见的原生数据类型,以及几种复杂数据类型.
    TINYINT:原生类型,占1字节的有符号整数
    SMALLINT:原生类型,占2字节的有符号整数
    INT:原生类型,占4字节的有符号整数
    BIGINT:原生类型,占8字节的有符号整数
    FLOAT:原生类型,占4字节的单精度浮点数
    DOUBLE:原生类型,占8字节的双精度浮点数
    BOOLEAN:原生类型,真/假
    STRING:原生类型,字符串
    BINARY:原生类型,字节数组
    TIMESTAMP:原生类型,纳秒精度的时间戳
    DATE:原生类型,年/月/日,格式为YYYYMMDD
    ARRAY:复杂类型,由同类型字段组成的有序集合
    MAP:复杂类型,由键值对组成的无序集合
    STRUCT:复杂类型,由不同类型的具名字段组成的集合

比较Hive中的内部表与外部表
在Hive中建表时,默认创建的是Hive内部表.Hive管理内部表的目录,对内部表运行DROP TABLE语句会从HDFS上删除对应文件.推荐在CREATE TABLE语句中指定EXTERNAL 关键字创建外部表.这种建表语句需要提供表结构和HDFS上对应对象的路径.此时,DROP TABLE操作不会删除相应目录和文件.

Spark SQL架构

Spark SQL针对其基于RDD的存储、调度、执行模型,提供了基本兼容HiveQL的SQL抽象.Spark SQL包含Spark项目核心的很多关键特性,包括惰性执行和中间查询容错.另外,Spark SQL可以在一个应用中与Spark核心API一起使用.
Spark SQL为了优化关系型数据的典型访问模式,对核心API添加了一些关键扩展.具体包括如下所列:

  • DAG部分执行(PDE):PDE让我们可以在执行时根据处理过程中发现的一些数据,动态修改和优化DAG.DAG修改包括优化表连接操作、处理数据倾斜、调整Spark使用的并行度.
  • 分区统计信息:Spark SQL维护各数据分区的统计信息,这些统计信息可以在PDE中使用,也可以用于裁剪映射任务(根据分区内各列的统计信息,过滤或裁剪要加载的分区)和优化通常代价较大的连接操作.
  • DataFrame API
  • 列式存储:Spark SQL在内存中存储数据时使用列式存储,也就是把数据按列存储,而不是按行存储.这对不同SQL访问模式有显著的性能影响.

SparkSession入口
使用Spark核心API的应用以SparkContext对象作为程序主入口,而Spark SQL应用则以SparkSession对象作为程序主入口.

SparkSession与SQLContext
你可能还是会在各种示例程序中发现对SQLContext对象的引用,它的实例通常名为sqlContext.该对象可以在交互式Spark shell中使用,并且可以与spark对象互换使用.一般来说,使用SparkSession的对象实例更好,因为SQLContext可能会在将来的版本中被废弃.

DataFrame 入门

Spark SQL的DataFrame表示记录的分布式集合,有着同样的预定义结构,在概念上类似于关系型数据库中的共享表.Spark SQL中的DataFrame前身为SchemaRDD对象,采纳了R语言中数据框结构和Pandas(Python中用于数据操作与分析的库)的一些设计思想.
DataFrame是Spark RDD的抽象.然而,DataFrame有别于原生RDD,区别于DataFrame维护表结构,并且对许多常见的SQL函数和关系型操作符提供了原生支持.而DataFrame和RDD的相似之处包括它们都是作为DAG求值,都是用惰性求值,并且都提供了谱系和容错性.

Dataframe可以由很多不同方式创建,包括如下所列几种:

  • 已有的RDD
  • JSON文件
  • 文本文件、Parquet文件,或ORC文件
  • Hive表
  • 外部数据库中的表
  • Spark临时表

接下来会介绍使用已有的SparkSession对象构建DataFrame的一些常见方法

  1. 从已有RDD创建DataFrame
    createDataFrame()
    1
    SparkSession.createDataFrame(data,schema=None,samplingRatio=None)

createDataFrame()方法从已有RDD创建DataFrame对象.参数data接收由元组或列表元素组成的RDD对象.参数schema表示要对DataFrame对象投影的表结构.如果需要推断表结构,参数samplingRatio用于设置数据采样率。

1
2
myrdd=sc.parallelize([('Jeff',48),('Kellie',45)])
spark.createDataFrame(myrdd).collect()

  1. 从Hive表创建DataFrame
    要从Hive表加载数据到Spark SQL的DataFrame中,需要先创建HiveContext实例.
    HiveContext会读取Hive客户端配置来获取Hive元数据库的连接信息.这使得Spark应用可以无缝访问Hive表.从Hive表创建DataFrame的方法有好几种,包括使用sql()方法或table()方法
    (1)sql()
    1
    SparkSession.sql(sqlQuery)

sql()方法根据提供的sqlQuery参数,从Hive表或对Hive表执行的DML操作创建DataFrame对象.如果要操作的表在Hive当前所使用的数据库之外,则需要使用.这样的格式引用该表.sqlQuery参数可以接收任意有效的HiveQL语句,包括带有WHERE子句或JOIN谓词的SELECT*或SELECT语句.

1
2
3
4
sql_cmd="""SELECT name,lat,long FROM stations WHERE landmark='San Jose'"""
df=spark.sql(sql_cmd)
df.count()
df.show(5)

(2)table()

1
SparkSession.table(tableName)

table()方法从Hive表创建DataFrame对象.与sql方法的区别是,table()方法不允许对原始表的列进行裁剪,也不允许使用WHERE子句过滤部分行.整张表都会加载到DataFrame中

1
2
3
df=spark.table('stations')
df.columns
df.count()

  1. 从JSON对象创建DataFrame
    JSON是在网络服务响应中经常使用的一种常见的、标准的、人类可读的序列化方式或数据传输格式.
    因为JSON是一种包含结构信息的半结构化数据源,Spark SQL内建支持JSON格式.
    read.json()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    DataFrameReader.read.json(path
    schema=None,
    primitivesAsString=None,
    prefersDecimal=None,
    allowComments=None,
    allowUnquotedFieldNames=None,
    allowSingleQuotes=None,
    allowNumericLeadingZero=None,
    allowBackslashEscapingAnyCharacter=None,
    mode=None,
    columnNameOfCorruptRecord=None,
    dateFormat=None,
    timestampFormat=None,
    multiLine=None)

DataFrameReader的json()方法从JSON文件创建DataFrame对象.

4.从普通文件创建DataFrame
DataFrameReader也可以用于从其他类型的文件读取DataFrame,比如CSV文件,或者外部的SQL和NoSQL数据源.下面分别介绍了从纯文本文件以及Parquet、ORC等一些列式存储格式的文件,创建DataFrame的示例
(1)text()

1
DataFrameReader.read.text(path)

DataFrameReader的text()方法用于从外部文件系统(本地文件系统、NFS、HDFS、S3等)上的文本文件读取DataFrame.该方法的行为类似于RDD中等价的sc.textFile()方法.参数path指代的路径可以是一个文件,也可以是目录,或是文件通配符。

1
2
3
4
df=spark.read.text('file:///opt/spark/data/bike-share/stations/stations.csv')
df.take(1)
df=spark.read.text('file:///opt/spark/data/bike-share/stations/')
df.count()

注意文本文件中的每一行会返回一个对应的Row对象,该对象包含一个字符串,即文件中对应的整行数据.

(2)parquet()

1
DataFrameReader.read.parquet(paths)

DataFrameReader的parquet()方法用于读取以Parquet列式存储格式存储的文件.这些文件通常来自其他进程的输出,比如前一个Spark进程的输出.参数paths指向单个或多个Parquet文件,或是Parquet文件组成的目录.
Parquet格式将表的结构信息与数据封装在一个结构中,因此DataFrame可以使用文件中的表结构.

1
2
3
df=spark.read.parquet('hdfs:///user/hadoop/stations.parquet')
df.printSchema()
df.take(1)

(3)orc()

1
DataFrameReader.read.orc(path)

DataFrameReader的orc()方法用于从单个ORC格式文件或由多个ORC格式文件组成的目录读取DataFrame.ORC是一种来自Hive项目的格式.参数path指向一个包含ORC文件的目录,一般与Hive仓库中以ORC格式存储的一张表相关联.

1
2
3
df=spark.read.orc('hdfs:///user/hadoop/stations_orc/')
df.printSchema()
df.take(1)

也可以使用DataFrameReader和spark.read.jdbc()方法从MySQL、Oracle之类的外部数据源读取数据.

  1. 把DataFrame转为RDD
    可以使用rdd()方法轻松地把DataFrame转化原生的RDD

    1
    2
    3
    4
    stationsdf=spark.read.parquet('hdfs:///user/hadoop/stations.parquet')
    stationsrdd=stationsdf.rdd
    stationsrdd
    stationsrdd.take(1)
  2. DataFrame数据模型:原生类型
    DataFrame API的数据模型是基于Hive的数据模型设置的 .DataFrame中使用的数据类型与Hive中的等价类型直接对应.这些类型包括所有常见的原生类型,以及等价于列表、字典和元组的复杂嵌套类型

  3. DataFrame数据模型:复杂类型
    Spark SQL可以原生使用基于HiveQL的操作符访问复杂嵌套类型

ArrayType:等价于Hive类型ARRAY,等价于Python list,tuple或array
MapType:等价于Hive类型的MAP,等价于Python dict
StructType:等价于Hive类型的STRUCT,等价于Python的list或tuple

  1. 推断DataFrame表结构
    在Spark SQL中,DataFrame的表结构可以显式定义,也可以隐式推断.
    Spark SQL使用反射来推断DataFrame对象的表结构.反射会检查对象来判断其组成结构,可以在把RDD转为DataFrame时生成相应的表结构.在这种情况下,RDD的每条记录都会生成一个对应的Row对象,并且每个字段都会分配一个数据类型.各字段的数据类型是从第一条记录推断而来的,因此第一条记录必须要具有代表性,而且所有的字段都不能为空.
    1
    2
    rdd=sc.textFile('file:///home/hadoop/stations.csv').map(lambda x:x.split(',')).map(lambda x:(int(x[0]),str(x[1]),float(x[2]),float(x[3]),int(x[4]),str(x[5]),str(x[6])))
    rdd.take(1)

注意字段的命名使用了_的惯例,而nullable属性都被设置为True,这意味着这些值都可以为空.还要注意到推断时使用的都是范围更大的类型.

9.定义DataFrame表结构
在代码中显式定义DataFrame的表结构,比隐式推断更好.你需要创建一个包含一组StructField对象的StructType对象,以创建表结构.然后就可以在创建DataFrame时使用该表结构.

使用DataFrame

DataFrame API是目前Spark项目中发展最快的部分之一.每个小版本发布都会包含明显的新特性与函数.Spark SQL的DataFrame模型还有一些扩展,比如Datasets API.这些扩展也以同样的速度告诉发展.事实上,Spark SQL及其核心组件 DataFrame API就足以单独撑起一整本书.

  1. DataFrame元数据操作
    DataFrame API提供了几个元数据函数.这些函数返回的是关于数据结构的信息,而不是数据本身.
    (1)columns()
    1
    DataFrame.columns()

columns()方法返回由给定DataFrame的列名组成的列表.
(2)dtypes()

1
DataFrame.dtypes()

dtypes()方法返回由二元组组成的列表.其中每个二元组包含给定DataFrame对象的一个列名和该列的数据类型.

  1. DataFrame基本操作
    因为DataFrame是RDD的列式抽象,所以它们有很多相似的函数,比如一些转化操作和行动操作都是直接来自RDD的方法.DataFrame还有一些额外的关系型方法,比如select()、drop()和where().像count()、collect()、take()和foreach()这样的核心函数,与RDD API中的同名函数,无论是功能上还是句法上都保持一致.与RDD API一样,有些方法中的行动操作会触发DataFrame及其谱系的求值
    与行动操作collect()和take()一样,之前的例子中,我们使用了一个替代方法show().show()是行动操作,如果DataFrame在缓存中不存在,他会触发DataFrame的求值
    (1)show()
    1
    DataFrame.show(n=20,truncate=True)

show()方法将DataFrame的前n行打印到控制台上.与collect()或take(n)不同,show()并不把结果返回到变量.
(2)select()

1
DataFrame.select(*cols)

select()方法根据cols参数指定的列返回一个新的DataFrame对象.你可以使用星号(* )选出DataFrame中所有的列而不进行任何操作
(3)drop()

1
DataFrame.drop(col)

drop()方法返回一个删去了col参数指定的列的新DataFrame.
(4)filter()

1
DataFrame.filter(condition)

filter()方法返回仅包含满足给定条件的行的新DataFrame,筛选条件由condition参数提供,求值结果为True或False.

1
2
df=spark.read.parquet('hdfs:///user/hadoop/stations.parquet')
df.filter(df.name=='St James Park').select(df.name,df.lat,df.long).show()

(5)distinct()

1
DataFrame.distinct()

distinct()方法返回包含输入DataFrame中不重复的行的新的DataFrame,本质就是过滤掉重复的行.当同一个DataFrame中一行数据的所有列的值都与另一行相同,我们就把它看作重复的行.

1
2
3
rdd=sc.parallelize([('Jeff',48),('Kellie',45),('Jeff',48)])
df=spark.createDataFrame(rdd)
df.show()

注意drop_duplicates()方法具有类似功能,还可以让用户选择仅过滤选定列的重复数据.
另外,map()和flatMap()可以分别通过DataFrame.rdd.map()和DataFrame.rdd.flatMap()使用.

从概念上来说,这些方法和他们在RDD API中同名的方法功能类似.不过,在处理各列有名字的DataFrame时,lambda函数稍有不同.

1
2
3
4
df=spark.read.parquet('hdfs:///user/hadoop/stations.parquet')
rdd=df.rdd.map(lambda r:r.name)
rdd
rdd.take(1)

Spark SQL的DataFrame API中还有其他一些操作值得介绍.sample()方法he sampleBy()方法与RDD API中的等价操作效果类似,而limit()函数则会创建一个包含原始DataFrame中指定数量的任意行的新DataFrame。
explain()也是一个在开发时有帮助的函数.它返回查询计划,包含对DataFrame进行求值时使用的逻辑计划和物理计划.在排查问题或优化Spark SQL程序时,会用到这个函数.

探索文档可以对DataFrame API中提供的所有函数有更多了解.值得注意的是,Python语言的Spark SQL API的所有函数都包含docstring.你可以使用它们探索Spark SQL中任意函数的语法和用法,也可以探索Spark 的Python语言API提供的其他函数.

1
2
from pyspark.sql import DataFrame
print(DataFrame.sample.__doc__)

  1. DataFrame内建函数
    Spark SQL中有大量可供使用的函数,包含其他常见的数据库管理系统的SQL中所有支持的大多数函数。
    字符串函数:startswith、substr、concat、lower、upper、regexp_extract、regexp_replace
    数学函数:abs、ceil、floor、log、round、sqrt
    统计函数:avg、max、min、mean、stddev
    日期函数:date_add、datediff、from_utc_timestamp
    哈希函数:md5、sha1、sha2
    算法函数:soundex、levenshtein
    窗口函数:over、rank、dense_rank、lead、lag、ntile

  2. 在DataFrame API中实现用户自定义函数
    如果现成的函数中找不到能满足需求的,你可以在Spark SQL中创建用户自定义函数(user-defined function,即UDF).你可以通过使用udf()方法,创建列级别的UDF,把所需操作整合到Spark程序中.

    1
    pyspark.sql.function.udf(func,returnType=StringType)

udf()方法创建表示用户自定义函数的列表达式.func参数可以是具名函数或使用lambda语法的匿名函数,它对DataFrame中单行内的一列进行操作.returnType参数制定函数返回对象的数据类型.

  1. 多DataFrame操作
    join()、union()等集合操作是DataFrame的常见需求,因为它们都是关系型SQL编程中不可或缺的操作.
    DataFrame的连接操作支持RDD API和HiveQL所支持的所有连接操作,包括内连接、外连接以及左半连接.
    (1)join()
    1
    DataFrame.join(other,on=None,how=None)

(2)orderBy()

1
DataFrame.orderBy(cols,ascending)

orderBy()方法根据cols参数指定的列对DataFrame进行排序,生成新的DataFrame。
ascending是布尔型的参数,默认为True.

(3)groupBy()

1
DataFrame.groupBy(cols)

groupBy()方法将输入的DataFrame按照cols参数指定的列进行分组,使用分组结果创建新的DataFrame.

DataFrame缓存、持久化与重新分区

DataFrame API支持缓存、持久化与重新分区,所用方法类似于Spark RDD API中的对应操作.
缓存与持久化DataFrame的方法包括cache()、persist()和unpersist(),它们与用于RDD的同名函数作用类似.此外,Spark SQL还添加了cacheTable()方法,用于在内存中缓存Spark SQL或Hive中的表.clearCache()方法可以从内存中删除缓存的表。DataFrame也支持使用coalesce()和repartition()方法进行重新分区.

保存DataFrame输出

DataFrameWriter是用来把DataFrame写到文件系统或数据库等外部存储系统的接口.DataFrameWriter可以通过DataFrame.write()访问.

  1. 数据写入Hive表
    saveAsTable()函数实现此功能

    1
    DataFrame.write.saveAsTable(name,format=None,mode=None,patitionBy=None)
  2. 数据写入文件
    DataFrame中的数据写入的文件可以位于所支持的任意文件系统:本地文件系统、网络文件系统或分布式文件系统.输出会作为目录写出,每个分区对应生成一个文件,这和前面的RDD输出示例颇为相似.
    逗号分割值(CSV)是一种常见的文件导出格式.DataFrame可以通过使用DataFrameWriter.write.csv()方法导出到CSV文件

Parquet是一种流行的列式存储格式,并且转为Spark SQL进行了优化.通过使用DataFrameWriter.write.parquet()方法,你可以把DataFrame以Parquet格式写出去
(1) write.csv()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
DataFrameWriter.write.csv(path,
mode=None,
compression=None,
sep=None,
quote=None,
escape=None,
header=None,
nullValue=None,
escapeQuotes=None,
quoteAll=None,
dataFormat=None,
timestampFormat=None,
ignoreLeadingWhiteSpace=None,
ignoreTrailingWhiteSpace=None
)

DataFrameWriter类的write.csv()方法可以通过DataFrame.write.csv()接口访问,把DataFrame的内容以CSV文件的形式写入path参数所指定的路径。mode参数定义了如果目标目录在操作时已经存在的行为,其有效值为append(追加写)、overwrite(覆盖)、ignore(忽略)和error(报错,为默认值).mode参数在所有的DataFrame.write()方法中都适用.

(2)parquet()

1
DataFrameWriter.write.parquet(path,mode=None,partitionBy=None)

write.parquet()方法把DataFrame中的数据以Parquet格式写入指定目录.文件压缩的设置来自当前SparkContext中压缩相关的配置属性.mode参数指定当目录或文件不存在时的行为,其有效值为append(追加写),overwrite(覆盖),ignore(忽略)和error(报错,为默认值)。PartitionBy参数指定了作为输出文件的分区依据的列的名字(使用哈希分区)
保存DataFrame为Parquet文件

1
2
3
spark=SparkSession.builder.config("spark.sql.parquet.compression.codec.","snappy").getOrCreate()
stations=spark.table("stations")
stations.select([stations.station_id,stations.name]).write.parquet("file:///home/hadoop/stations.parquet",mode='overwrite')

ORC文件可以使用orc方法写出,该方法的用法与parquet()类似.JSON文件也可以使用json()方法写出.

在Spark中使用NoSQL系统

NoSQL是一种新的数据范式,允许用户以单元格的形式查看数据,而不是智能使用表格、行、列这种关系型范式.

NoSQL简介

  1. NoSQL系统特点
    NoSQL系统有具体的定义特征
    所有类型的NoSQL系统共有的属性如下所列:
  • NoSQL系统中没有静态表结构,是运行时才有表结构的读时系统:这意味着NoSQL系统中没有预定义的列,列是在每次PUT或INSERT操作时创建的。每条记录、每个文档、每个数据都可以有不同于其他实例的结构.
  • 数据与其他对象之间不存在预定义的关联:这意味着NoSQL系统中没有外键和参照完整性的概念.不论是在声明中还是其他地方.数据对象或实例之间可以存在关联,但是这些关联只能在运行时发现和使用,而不可以在设计表时定义.
  • 一般避免表连接操作:在大多数NoSQL实现中,表连接功能很弱,甚至完全不支持.这一般需要通过对数据进行非正则化实现,通常要以存储重复数据为代价.不过,大多数NoSQL实现都使用了高性价比的硬件或云端基础设施,由于在访问数据时不需要执行多余的表连接操作,节省出来的计算开销可以弥补存储多花费的开销.

另外,NoSQL系统一般都是分布式的,并且支持快速查找.写操作比起传统的关系型数据库系统,一般也更快和更具伸缩性,因为免去了传统的关系型数据库系统中一些导致额外开销的过程,比如数据类型检查或域检查、原子/阻塞性事务,以及对事务隔离级别的管理.

  1. NoSQL系统的类别
    NoSQL系统出现了一些变种.它们可以分为如下几类:键值对存储、文档存储、图数据存储。

Spark中使用HBase

HBase是Hadopp生态系统的项目,用于提供基于HDFS的分布式大规模可伸缩的键值对存储.

  1. HBase简介
    HBase把数据存储为稀疏的多维有序映射表.映射表根据键(行键)进行索引,值则存储在单元格中,每个单元格由列键和列值组成.行键和列键是字符串,而列值是未解释的字节数组,可以表示任何基本数据类型或复杂数据类型.HBase是多维的,也就是说每个单元格都带有时间戳的版本号.
    在设计表时会定义一个或多个列族.在列数据的物理存储中,数据按所属列族分组存储.不同的列族可以使用不同的物理存储属性,比如区块大小、压缩设置,还有要留存的单元格版本数量.
    虽然有些项目(比如Hive和Phoenix)可以用类SQL的方式访问HBase上的数据,但访问和更新HBase数据的自然方法本质上可以归结为get(查)、put(增)、scan(扫描)和delete(删除)这几种.HBase包含了一个shell程序,以及支持多种语言的编程接口.

HBase支持稀疏数据.也就是说,并非所有列都要在表内的每一行存在,而且不存储空值.
虽然HBase的数据存储在HDFS这个不可变的文件系统上,HBase依然支持对HBase表中的单元格进行原地更新.当列键已经存在时,HBase会创建带有新时间戳的新版本的单元格,然后后台的合并进程会将多个文件合并为数量更少、占空间更大的文件.

HBase数据以HFile对象的形式存储在HDFS上.HFile对象是列族(存储分组)和行键顺序范围的交集.行键的范围被称为分区,在其他实现中也别称为分片.HBase把分区数据放到分区服务器上.分区可以提供快速的行键查询,因为给定行键属于哪个分区是HBase已知的.HBase按需拆分或合并分区,作为其常规操作的一部分.无关行键的查询速度较慢,比如查询满足某种标准的列键和值.不过,HBase会使用布隆过滤器来加快搜索速度.

  1. HBase与Spark
    使用Python API 从Spark读写HBase最可靠的方法是使用Python软件包HappyBase.HappyBase是为访问和操作HBase集群上的数据而构建的Python库.要使用HappyBase,必须先使用pip或easy_install安装对应的Python软件包.
-------------本文结束感谢您的阅读-------------