python 连接hbase存、取图片

  连接hbase1.0.4需要使用Thrift,我用的是python2.6。
  安装thrift。下载地址https://dist.apache.org/repos/dist/release/thrift/0.9.0/thrift-0.9.0.tar.gz解压后安装命令。
在hbase服务器上,确保hbase服务已经启动。在thrift目录中,用管理员运行一下命令安装。
./configure
make
make install

  安装完毕生成hbase的client代码命令格式如下,
thrift –gen
登陆到hbase的权限进入
$ cd hbase/src/main/resources/org/apache/hadoop/hbase/thrift

生成python的
$ thrift –gen py Hbase.thrift
再生成一个C的学习备用,与本文无关
$ thrift –gen c_glib Hbase.thrift

将gen-py文件夹下的hbase文件夹拷贝到要连接hbase的服务器的python目录下,我用的是python2.6,自己手动安装的。命令如下
cp -R hbase /usr/local/lib/python2.6/site-packages/

拷贝完毕用import导入 hbase成功。开始写代码了。参考hbase里的例子在hbase/src/examples/中。

  我的任务就是把某个目录下,以jpg结尾的图片放到hbase里,因为图片名没有重复,所以用图片名做row name。hbase手动建表’hbase(main):013:0> create ‘img’, ‘data:”。

  首先统计一下照片的数量。这个image目录下只有jpg的图片,使用匹配只是备将来使用。下面只是测试脚本,不关心业务逻辑。

# find /image/ -name \*.jpg -type f |wc -l
13140

# du -s -h /image
303M /image/

  本地共有13140张照片共303M,写入hbase测试脚本如下:

#!/bin/bash 
# -------------------------------
# Revision:
# Date:        2012-12-11 
# Author:      simonzhang 
# Email:       simon-zzm@163.com 
# Web:         www.simonzhang.net 
# -------------------------------

import os
import re

from thrift.transport import TSocket  
from thrift.transport import TTransport  
from thrift.protocol import TBinaryProtocol  
   
from hbase import Hbase  
from hbase.ttypes import *

#### base set
find_path=(r'/image/',
           )

class HbaseWrite():
    def __init__(self):
        self.tableName = 'img'
        self.transport = TSocket.TSocket('192.168.100.100', 9090)
        self.transport = TTransport.TBufferedTransport(self.transport)
        self.transport.open()
        self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
        self.client = Hbase.Client(self.protocol)

    def createTable(self, tableName):
        col1 = ColumnDescriptor(name="data:",maxVersions=1)
        self.client.createTable(tableName,[col1])

    def write(self, PicPath, PicName):
        row = PicName.split('.')[0]
        _data = PicName.split('.')[1]
        PicData = open('%s/%s' % (PicPath, PicName), 'rb').read()
        # 此处需要注意格式,网上的格式报错,少个参数报错如下
        # TypeError: mutateRow() takes exactly 5 arguments (4 given)
        self.client.mutateRow(self.tableName, row, [Mutation(column="data:%s" % _data, value=PicData)], {})

    def read(self, tableName, PicName):
        row = PicName.split('.')[0]
        data_type = PicName.split('.')[1]
        get_data = self.client.get(tableName, row, 'data:%s' % data_type, {})[0]
        if get_data:
            return get_data.value
        else:
            return "Error"


def main(_path):
    WHB = HbaseWrite()
    WHB.createTable()
    find_file=re.compile(r"^[0-9a-z]*.jpg$")
    find_walk=os.walk(_path)
    for path,dirs,files in find_walk:
        for f in files:
            if find_file.search(f):
                path_name=path
                file_name=f
                WHB.write(path_name, file_name)


if __name__ == "__main__":
    for get_path in find_path:
        main(get_path)

开始测试脚本
# time python hbase_test.py

real 1m15.471s
user 0m4.881s
sys 0m2.867s

到hbase里查看写入的数量,证明已经完全写入。
hbase(main):001:0> count ‘img’
:
:
:
13140 row(s) in 10.2780 seconds

2013-5-16. 因为对hadoop理解不足。以下写的有问题,提醒大家注意。

hbase使用hadoop进行存储,查看hadoop的磁盘使用量。
26K namenode1/
298M u01/

  我的内存给namenode可以使用25G。根据以上数据计算结果如下:
((25*1000*1000)/26)*298= 286538461M = 286538G = 286 T

  如果每台服务器有三块1T存储硬盘,此集群可以有95台服务器。共存储此类照片大约为12634615360张。内网测试,写入速度3.9M。

  注:有一点需要注意,写入的数据删除后磁盘空间也不会释放,原理应该改和mongodb一样,但是没有仔细查看。

4 thoughts on “python 连接hbase存、取图片

  1. 图片是二进制的,hbase字段是字符串的,这样写进去的图片读出来不一致啊,请问你怎么做到一致呢?能留个联系方式吗?

    • 只要用二进制打开文件就可以,具体转换不用担心。这部分已经在hadoop私有云和阿里云都做个测试。我把我的私有云接口也贴上来大家看看,方便大家可以直接调用。因为编辑器和浏览器问题可能造成代码格式有误,自己检查一下。或者邮件发送给你。获取图片部分,可以参看我之前的“python 获取阿里OSS存储图片,在内存中处理图片”部分
      #!/bin/env python
      # -*- coding:utf-8 -*-
      # --------------------------------
      # Filename:
      # Revision: 1.0
      # Date: 2012-3-20
      # Web: www.simonzhang.net
      # Author: simon-zzm
      # Email: simon-zzm@163.com
      # --------------------------------
      import os
      import re
      import Image
      import hashlib

      from thrift.transport import TSocket
      from thrift.transport import TTransport
      from thrift.protocol import TBinaryProtocol

      from hbase import Hbase
      from hbase.ttypes import *

      #### 私有云设置
      private_yun_HOST = '192.168.1.99'
      private_yun_POST = 9090

      class PrivateHbase(object):
      def __init__(self):
      self.transport = TSocket.TSocket(private_yun_HOST, private_yun_POST)
      # 高效传输方式
      self.transport = TTransport.TBufferedTransport(self.transport)
      self.transport.open()
      self.protocol = TBinaryProtocol.TBinaryProtocol(self.transport)
      # 客户端
      self.client = Hbase.Client(self.protocol)

      # 根据当前命名规则,图片,声音均可以使用文件名做列,版本默认为1。
      def createTable(self, tableName):
      col1 = ColumnDescriptor(name="data:",maxVersions=1)
      self.client.createTable(tableName,[col1])

      #写入数据,将数据名做row,用后缀描述数据
      #此处需要注意,有些数据可能没有后缀,可以根据实际情况修改
      def put_file(self, tableName, DataPath, DataName, MD5):
      row = DataName
      data_type = DataName.split('.')[1]
      Data = open('%s' % DataPath, 'rb').read()
      self.client.mutateRow(tableName, \
      row, \
      [Mutation(column='data:%s' % data_type, value=Data), \
      Mutation(column='data:md5', value=MD5)], \
      {})

      # 读取数据,直接将读取的数据返回,不做任何处理
      def get_data(self, tableName, DataName):
      row = DataName
      data_type = DataName.split('.')[1]
      get_data = self.client.get(tableName, row, 'data:%s' % data_type, {})[0]
      if get_data:
      return get_data.value
      else:
      return "Error"

      # 读取数据的md5信息
      def data_md5(self, tableName, DataName):
      _md5_value = ''
      row = DataName
      try:
      get_md5 = self.client.get(tableName, row, 'data:md5', {})[0]
      except IndexError,e:
      if ('%s' % e) == 'list index out of range':
      _md5_value = ''
      try:
      _md5_value = get_md5.value
      except:
      _md5_value = ''
      return _md5_value

      # 删除整行数据,需要小心
      def deleteall(self, tableName, DataName):
      row = DataName
      data_type = DataName.split('.')[1]
      get_data = self.client.deleteall(tableName, row, 'data:%s' % data_type, {})[0]

      def main():
      print '''
      save to private yun.
      '''

      if __name__ == "__main__":
      main()

  2. 你好,请问一下我想将读取的数据导入到本地文件夹中应该怎么做呢,因为编程能力有限,所以也不知道怎么写

wanwan进行回复 取消回复

电子邮件地址不会被公开。 必填项已用*标注