记录一下maven使用过程中遇到的几个问题

环境:win7+eclipese-mars+maven3.3.9

卡死在building workspace

这个问题网上我找了好多,原因不一而足。有一种解决办法就是,先停止它的building,然后项目右键–properties,在左边选择builder,然后把Maven Project Builder的选项去掉就行。

builder

这个方法堪称是鸵鸟战法,只是让eclipse没再卡在building workspace的状态中了,之后该干什么还是得干什么。

我接下来就继续maven install了,把依赖包都下下来了,但是一看Maven Dependencies,什么都没有。。可到本地的repository看看,依赖包确实是下载了啊。

好吧,我又把Maven Project Builder的选项勾选回来了,然后打开pom.xml,随便打了一个空格,保存,依赖包神奇的包含进来了。

reload maven project出错,eclipse打不开

这个问题原因同样很多。我就是因为等不及maven卡在那里,eclipse又关不了,直接暴力在任务管理器中关掉eclipse了,然后发现eclipse再也打不开了,错误信息是

"An internal error occurred during: "reload maven project".java.lang.NullPointerException"

估计的某些文件没弄下来,然后被我直接关了,没保存好,就启动出错了。

简单粗暴的解决方法:到你eclipse的workspace目录下,把.metadata文件夹删掉,然后重启eclipse就可以正常打开了。

代价是:要重新导入原来的项目,但是项目本身还是在那里的,相比于看log来找错误信息,这个解决问题的方式虽然比较粗暴,但胜在速度比较快。

使用开源中国的maven中央仓库

国外的maven中央仓库相对来说还是比较慢的,好在国内的开源中国有做这方面的优化,他们将国外的仓库搬过来了,一天一更新,基本上也是同步的,速度快多了,推荐使用他们的mirror。

官方教程:http://maven.oschina.net/help.html

仓库搜索:http://maven.oschina.net/home.html

记录一下windows下panda的安装过程

搞大数据开发,就是和数据打交道,具体怎么处理数据,也需要深究,python有很多很好用的库,其中pandas是比较出名的。下面是简单的介绍:

Pandas是python的一个数据分析包,最初由AQR Capital Management于2008年4月开发,并于2009年底开源出来,目前由专注于Python数据包开发的PyData开发team继续开发和维护,属于PyData项目的一部分。Pandas最初被作为金融数据分析工具而开发出来,因此,pandas为时间序列分析提供了很好的支持。 Pandas的名称来自于面板数据(panel data)和python数据分析(data analysis)。panel data是经济学中关于多维数据集的一个术语,在Pandas中也提供了panel的数据类型。

官网:http://pandas.pydata.org/

我刚开始以为直接pip就能安装pandas了。事实证明我太天真了。下面还是记录一下我的安装过程吧。

利用pycharm直接安装pandas

pycharm的包管理工具挺好用的,直接可以在里面搜索到很多可以用的包,然后直接安装。安装pandas也不例外。

首先打开pycharm,直接在setting里面找到编译器的选项

pycharm中编译器设置

可以看到本地已经安装的包,点击右边的+号,就可以安装新的包了。想安装pandas,直接搜索pandas就是了,记得别少了s,是pandas

搜索后安装即可。pandas是依赖于别的包的,根据提示,如果还需要安装别的包,继续搜索安装就行。

在windows下用pip安装pandas

官网推荐的是直接使用Anoconda,它集成了pandas,可以直接使用。安装挺简单的,有windows下的安装包。

如果不想安装庞大的Anoconda,那就一步一步用pip来安装pandas。

如果直接pip install pandas,可能会出现一系列的问题,为了稳妥起见,我先把依赖包都一个个安装下来,最后再安装pandas,就没有问题了。

官网说pandas需要以下几个依赖:

setuptools
NumPy: 1.7.1 or higher
python-dateutil 1.5 or higher
pytz

一个个来。首先setuptools,这个和pip本身在新一点的python下是默认安装了的。我的python版本是2.7.11

然后pip install numpy

安装numpy

安装到一般,居然出错了。错误如下:

Microsoft Visual C++ 9.0 is required Unable to find vcvarsall.bat

原因:windows下使用pip安装包的时候需要机器装有vs2008,VS2012都不行,如果不想装VS2008的话,可以安装一个Micorsoft Visual C++ Compiler for Python 2.7的包。
下载地址:http://www.microsoft.com/en-us/download/details.aspx?id=44266

如果还是不行的话,就直接去官网找windows下的安装包。

官网:http://sourceforge.net/projects/numpy/files/

我找的1.9.2版本:http://sourceforge.net/projects/numpy/files/NumPy/1.9.2/

有windows下针对python2.7的安装包,文件名为numpy-1.9.2-win32-superpack-python2.7.exe

下载安装即可。

搞定了numpy,接下来安装python-dateutil,命令:pip install python-dateutil
很顺利。

然后安装pytz,命令:pip install pytz
也很顺利。

最后!直接安装pandas就行了,命令:pip install pandas

安装pandas

大功告成,真是折腾。

利用bootstrap的滚动监听+affix做一个侧导航landingpage

前段时间有个小的需求,要做一个带侧边导航的landingpage。这种页面直观点来说,就是类似百度百科一样,随着页面的滚动,在旁边的导航栏会跟踪你的页面,作为一个活动书签。如图,红框就是侧导航:

百度百科侧边导航

要是直接重新写的话,也是一件有工作量的事情,所以干脆直接用bootstrap框架,里面js插件有滚动监听和affix,结合起来就可以做出来类似的效果。

ps:用的是bootstrap3

滚动监听

bootstrap的scroll.js是用来滚动监听的,而使用起来最便利的方法是直接引用在html代码里加data属性。

滚动监听都需要被监听的组件是position: relative; 即相对定位方式。大多数时候是监听 元素,所以直接在body的style里面加上这个属性即可。

然后继续在body里面加data属性,一个是data-spy,一个是data-target
data-spy的值直接设置成"scroll"即可,而data-target则要设置成导航栏的id。实例代码如下:

<body style="position: relative;" data-spy="scroll" data-target="#navbar-example">
  ...



<div id="navbar-example">



<ul class="nav nav-tabs" role="tablist">
      ...
    </ul>



  </div>



  ...
</body>

affix固定侧导航

affix的英文意思粘贴的意思,顾名思义,它的作用就是是网页中的元素固定粘贴在某个位置,而我们的侧边栏恰好就是要这样的效果。

使用方法也很简单,在侧导航加一个data-spy="affix"属性就可以了,可选项为data-offset,可以是data-offset-top或者data-offset-bottom,比如data-offset-top="60",效果就是当页面距离顶部60像素之后,才开始固定这个元素(侧导航),如果不用这个可选项,则侧导航是一直黏在固定位置的。

侧导航landingpage例子

效果是这样的:https://www.lookfor404.com/langding-page-example.html

全程都是用的data属性,其中,affix的属性,我没有加上data-offset,另外就是对“返回顶端”写了几行jquery,返回顶端的时候有滚动效果,代码如下:

<script type="text/javascript">
    $(function(){  
            $("#back-to-top").click(function(){  
                $('body,html').animate({scrollTop:0},1000);  
                return false;  
            });  
      });
    </script> 

完整代码直接在网页右键–查看源代码就行了,这里就不贴出来了。

python爬虫–抓取ajax更新的内容

虽然很多情况下,直接对一个url发出请求,就能得到页面的源代码,但是我们还得考虑这么一种情况,就是有的网站为了用户体验,采用了ajax技术–即不刷新页面而改变页面内容,那么我们该怎么获取这些内容呢?

从本质出发,ajax技术也就是这么一个过程:利用js来发起一个post请求–然后接收返回的数据–js改变页面内容。在大多数情况下,我们都是点击一个按钮,然后页面就更新了。从原理上来看,点击某个按钮,就会发送一个post请求(当然还有滚动鼠标发送请求的),服务器再返回结果,再将结果直接更新到页面上。我们的思路是–用爬虫发送同样的post请求,从而获得返回来的数据。

简单点说,对于爬虫而言,在获取数据上,get和post并无太多异样,只是get的话,我们只需要对某个链接发送请求就行,而post,则需要一些表单内容。那么,我们怎么知道该post什么内容过去,又能获得什么响应呢?

以虎嗅网(http://www.huxiu.com/)为例,我用python写了一个爬取它利用ajax更新的数据。

我们打开它的首页,拉到最下面,发现有个“点击加载更多”的按钮,颜色很浅。

点击它,就会有新的内容出现。

虎嗅网底部

我们要做的,就是看看点击这个按钮会发生什么。

我这里以遨游浏览器为例,大多数浏览器(比如chrome,Firefox)应该都有类似的功能,在网页上,点击右键–审查元素,在弹出的窗口菜单栏点击“网络”一栏,在这里,我们可以监控一些get,post等行为。

刚开始是空的。

此时,回到网页上去,点击“点击加载更多”按钮。然后再回到开发者工具那里,会发现,出现了很多的请求:

点击加载更多

其中,有个请求的方法是POST,这就是我们要找的。点进去,可以看到http报头、预览、响应和cookies。

从中,我们可以获得一些头部信息,以及post的表单数据。

  • 头部信息

不同网站对头部信息的要求不同,有的不需要头部信息都能响应,有的则需要头部信息的一部分,虎嗅是不需要头部信息的。

  • 表单数据

从开发者工具里面看,虎嗅需要的表单数据有两个,一个是’huxiu_hash_code‘,这个是用来防止csrf的,一个是page,代表页数,我们把huxiu_hash_code复制下来。

构造一个请求过去,会得到一个json格式的响应,内容有msg,total_page,result和data,要的文章数据在data里面。我的程序把data里面的标题都提取出来,打印到屏幕下,下面贴上代码:

#-*- coding:utf-8 -*-
__author__ = '李鹏飞'
import urllib2
import urllib
import json
import re
url = 'http://www.huxiu.com/v2_action/article_list'
user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
data = {'huxiu_hash_code':'322cf76eec54c4e275d7c8122028a3b2','page':2}
data = urllib.urlencode(data)
try:
    request = urllib2.Request(url=url,data=data)
    response = urllib2.urlopen(request)
    #解析json
    result = json.loads(response.read())
    print result['msg']
    content = result['data']
    #匹配文章标题
    pattern = re.compile('
<div class="mob-ctt">.*?target="_blank">(.*?)</a>',re.S)
    #虎嗅文章标题
    items = re.findall(pattern,content)
    for item in items:
        print item
except urllib2.URLError, e:
    if hasattr(e,"code"):
        print e.code
    if hasattr(e,"reason"):
        print e.reason

这样子的话,大部分网页就能抓了,管他是post还是get。

Linux下升级python版本-2.7.9

我用的centos,预装着python,版本比较低,是2.6的,而2.7.9以上的版本自带pip,easy_instll和wheel,为了省去安装这些东西的麻烦,我干脆直接重新装一个python2.7.9好了。

这里记录一下升级安装的过程。

首先去官网下载对应的python的tgz文件,在linux下可以直接wget,在windows下直接下载就行,网址:https://www.python.org/ftp/python/2.7.9/Python-2.7.9.tgz

若网址失效,请移步python官网下载。

在linux下,将下载的tgz文件解压到指定目录,运行以下命令:

tar -xvzf Python-2.7.9.tgz -C /home 

解压完成,切换到解压的目录下,运行命令:

./configure

这个命令完成后,会生成makefile文件,供下一步使用。

接下来编译源代码,运行命令:

make

再运行最后一个命令,自动把文件分发的系统的关键位置,命令如下:

make install

等到处理完成,不需要任何更改,直接在命令行输入python,看到如下提示即安装成功:
python升级成功

2.7.9以及以上版本的python都预装了pip,eazy_install,很是方便,之后安装别的包就比较简单了。

cloudera-quickstart-vm-集成了大数据平台的虚拟机镜像

前几天和朋友聊天,他告诉我有一个cloudera-quickstart,这是一个集成了大部分大数据组件的虚拟机镜像系统,反正就是–不用配置了,包括hadoop,hbase,hive,hue,spark,zookeeper等等,是cloudera定制的版本,还有cloudera的管理组件。我们只需要把镜像下下来,直接在visualbox或者vmvare里面运行就行。

于是我就自己尝试了一下vmvare的版本,不过出了问题,主要是内存不足。在这里也提醒一下想用quickstart-vm的朋友,你得保证你的电脑至少有8g的内存,配置越高越好,不然会很卡。

下面记录一下自己运行cloudera-quickstart-vm的vmvare版本

下载地址:http://www.cloudera.com/downloads.html

第一个就是quickstart-vm:

quickstart-vm下载

点击download下载。我下载的是vmvare的版本。PS:下载的时候可能会要求你登陆账号,注册一个就好。我得到的下载链接是:https://downloads.cloudera.com/demo_vm/vmware/cloudera-quickstart-vm-5.5.0-0-vmware.zip

整个zip大小4g多,本地用迅雷下载速度也快不到哪里去,于是我用百度网盘离线下载,秒下,然后再从百度云下到本地。

下载完成,解压。

打开vmvare,点击菜单栏上的文件–打开,找到刚才解压的路径,就能发现有一个vmx文件,打开它。

quickstart-vm虚拟机文件

打开之后,vmvare是这样的:

打开vmx文件的vmvare

先别急着运行,要先更改虚拟机的配置,你需要把这台虚拟机设置到至少8g内存(这意味着你的电脑需要至少需要8g内存,没有的话,会非常非常卡,而且一堆错误),处理器设置成至少两个。

vmvare内存和处理器的设置

这时候,可以启动这台虚拟机了。启动之后,它会自动启动火狐浏览器,打开一个初始页面:

quickstart初始界面

怎么进入管理界面呢?

运行桌面的cloudera express命令脚本即可。

如果出现以下错误,说明你的虚拟机没有设置到8g内存和两个处理器,请设置完毕再重新打开这个虚拟机。

quickstart错误

想强制启动的话,可以在终端运行以下命令:

sudo /home/cloudera/cloudera-manager --express --force

不出意外的话,启动成功了:

cloudera-quickstart管理组件启动成功

接下来可以去浏览器直接管理了。

打开内置的火狐,输入网址:http://quickstart.cloudera:7180

登录账号:cloudera
登录密码:cloudera

登陆之后,就可以看到管理界面了:

cloudera管理界面

可以看到,左边是整合的大数据工具,点击对应的下拉按钮,就可以启动,关闭,管理这些组件了。

PS:由于电脑内存太小,所以这个整合了所有单机版大数据工具的系统,我用的并不顺手,这里仅把过程记录下来,供大家参考。

PPS:还是乖乖搭环境去了

 

简易python爬虫–爬取冷笑话

今天闲来无事,就想接触一下爬虫的基本知识,搞大数据,没有数据是万万不可的,而数据的来源,有很大一部分是通过网络爬虫来抓取的。

关于爬虫,似乎python的框架会比较多,比如scrapy。不过刚开始接触,用python一些原生的库就可以完成一些简单的小爬虫程序了,就比如我刚刚写的冷笑话爬虫。

在这之前,得大概搞清楚爬虫的工作原理,其实也很简单。首先是对你的目标网站发出http请求,目标网站会返回一个html文档给你,也就是我们俗称的网页,原本,这些文档都是由一大堆标签构成的,但浏览器配合上css,js,就形成了我们看到的各种各样的网页。但我们的爬虫不需要这些外衣,我们只需要内容,所以爬虫接下来的工作是处理这个html文档,提取我们要的信息,然后继续爬取下一个网页,如此往复循环。

不多说,先上我写的一段python脚本,爬取<我们爱讲冷笑话>的随机页面,网址为:http://lengxiaohua.com/random,这个页面每次刷新都有20则不同的随机冷笑话,我的程序功能是:输入数字1到20看对应的笑话,输入new重新爬取另外20则新笑话,输入quit退出程序。代码如下:

#-*- coding:utf-8 -*-
__author__ = '李鹏飞'
import urllib2
import re

class randomJoke:

    #初始化方法
    def __init__(self):
        self.url = 'http://lengxiaohua.com/random'
        self.user_agent = 'Mozilla/4.0 (compatible; MSIE 5.5; Windows NT)'
        #初始化headers
        self.headers = { 'User-Agent' : self.user_agent }
        #笑话内容
        self.content = []

    #获取网页源代码
    def getSourceCode(self):
        try:
            request = urllib2.Request(url = self.url, headers=self.headers)
            response = urllib2.urlopen(request)
            sourceCode = response.read().decode('utf-8')
            return sourceCode
        except urllib2.URLError, e:
            if hasattr(e,"reason"):
                print u"网络错误...",e.reason
                return None

    #获取笑话
    def setContent(self):
        sourceCode = self.getSourceCode()
        if not sourceCode:
            print('获取网页内容失败~!')
            quit()
        pattern = re.compile(' <pre.*?js="joke_summary".*?"first_char">(.*?)</span>(.*?)</pre>

.*?class="user_info">.*?<a.*?>(.*?)</a>.*?

(.*?)

',re.S)
        items = re.findall(pattern,sourceCode)
        self.content = items
        print u"已经爬取源代码...正在解析源代码..."

    #返回笑话
    def getContent(self):
        return self.content

    #打印一则笑话
    def printAJoke(self,number):
        joke = self.content[number]
        print u"作者:%s" %(joke[2])
        print u'发表于:'+ joke[3]
        #item[0]和item[1]组成完整的内容
        print joke[0]+joke[1]

randomJoke = randomJoke()
notQuit = True
print u"你好,这里是随机笑话!"
print u"---------------------"
randomJoke.setContent()
print u"...."
print u"笑话池已经装满,20/20"
print u"输入1到20看笑话~~,输入quit退出,输入new重新爬取新笑话"
while notQuit:
    input = raw_input()
    if input == "quit" :
        print u"bye!"
        notQuit = False
    elif input == "new":
        randomJoke.setContent()  #重新抓取笑话内容
        print u"...."
        print u"笑话池已经装满,20/20"
        print u"输入1到20看笑话~~,输入quit退出,输入new重新爬取新笑话"
    else:
        input = int(input)
        randomJoke.printAJoke(input-1)
        print u"--------------------------------------------------"
        print u"输入1到20看笑话~~,输入quit退出,输入new重新爬取新笑话"
print u"您已经成功退出!"
quit()

保存这段脚本,运行,效果如下:

运行冷笑话爬虫

说明一下,有些笑话是带图片的,而我没有抓取图片,仅仅抓取了作者,发表日期,和内容。

下面对程序稍微进行一下解释:

引入了urllib2re两个模块,urllib2是用来发送http请求的,re是正则表达式的相关模块。

randomJoke是程序的主要部分,下面就所有的方法,进行简单的说明。

__init__方法

位置:9-15行

这个是初始化方法,定义了四个变量,url为目标网址;user_agent是我们发送http请求的时候伪造的头部的一个客户端信息;headers是头部信息,这里只把user_agent信息加进去就行了;content[]是一个列表,用来存放笑话内容。

getSourceCode方法

位置:18-27行

这个方法是用来获取网页的源代码的。在第20行,发起一个http请求,接着读取返回的源代码,并return源代码。

setContent方法

位置:30-44行

这个方法是比较关键的一个方法,主要是利用正则表达式匹配源代码,并把我们需要的内容爬取下来。第35-41行代码就是正则表达式的匹配模式,我们要抓取网页中的20个笑话,其中的.*?是匹配任意字符,多一个括号,即(.*?)表示匹配的内容是我们需要的内容,在这个片段当中,出现了4(.*?),因此,程序的第36行,item表示的是一个列表,这个列表的形式是这样的:[[[item1-1],[item1-2],[item1-3],[item1-4]],[…],[…],…[[item20-1],[item20-2],[item20-3],[item20-4]]]。即这个列表有20个元素(代表这个网页的20个笑话),每个元素又是一个列表–列表中有4个元素(代表爬取的4个内容,对应前面说的4个(.*?)。这里附上其中的一小部分网页源代码,对应着网页的html源代码,我们就能感受到这个简单的正则表达式的作用了:


<pre js="joke_summary"><span class="first_char">来</span>表哥家吃饭,小侄子一边看西游记一边手舞足蹈上蹦下跳学猴哥。
我哥:“傻儿子,你是孙悟空吗?”
侄子:“正是,你孙爷爷在此。”
打到现在还在哭。</pre>
</div>
<div class="para_info clearfix">
<div class="user_info">
                        <img src="http://joke-image.b0.upaiyun.com/img/user/cover/630347-299927_40x40.jpg" class="left corner4px" height="40" width="40"/>
                        <a href="/user/630347">离愁▍ Feast aw</a>
                        <p>15天前</p>

一共有20个类似的html片段,正则表达式的作用就是把笑话内容,作者和发表日期提取出来。

printAJoke方法

位置:51-56行

打印一则笑话,在这里我们更能感受到content[]的结构了,因为printAJoke这个方法需要传一个number参数进来,范围是1到20,我们就可以读取对应的笑话了,比如content[0]代表第一则笑话,和java中的数组类似。

53行以后就是程序运行的基本逻辑了,比较简单,就不多解释了。

就这样,一个简单的爬虫就完成了!

hbase的基本概念以及shell命令的基本用法【转载】

作为入门,这篇文章写得挺好的,在文章的后半部分,是hbase的shell的简单使用,我们可以通过shell来更好的了解一下hbase,实践出真知。

简介

HBase是一个分布式的、面向列的开源数据库,源于google的一篇论文《bigtable:一个结构化数据的分布式存储系统》。HBase是Google Bigtable的开源实现,它利用Hadoop HDFS作为其文件存储系统,利用Hadoop MapReduce来处理HBase中的海量数据,利用Zookeeper作为协同服务。

HBase的表结构

HBase以表的形式存储数据。表有行和列组成。列划分为若干个列族/列簇(column family)。

Row Key

column-family1

column-family2

column-family3

column1

column2

column1

column2

column3

column1

key1

t1:abc

t2:def

t4:lookfor404

t3:hello

t2:world

key2

t3:abc

t1:lipengfei

t4:java

t3:hello

t2:hadoop

t3:hbase

key3

t2:dfadfasd

t1:dfdasddsf

t2:hi

t1:fine

如上图所示,key1,key2,key3是三条记录的唯一的row key值,column-family1,column-family2,column-family3是三个列族,每个列族下又包括几列。比如column-family1这个列族下包括两列,名字是column1和column2,t1:abc,t2:def是由row key1和column-family1-column1唯一确定的一个单元cell。这个cell中有两个数据,abc和def。两个值的时间戳不一样,分别是t1,t2, hbase会返回最新时间的值给请求者。

这些名词的具体含义如下:

 (1)Row Key

与nosql数据库们一样,row key是用来检索记录的主键。访问hbase table中的行,只有三种方式:

          1.通过单个row key访问

          2.通过row key的range

          3.全表扫描

Row key行键 (Row key)可以是任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在hbase内部,row key保存为字节数组。

存储时,数据按照Row key的字典序(byte order)排序存储。设计key时,要充分排序存储这个特性,将经常一起读取的行存储放到一起。(位置相关性)

注意:

字典序对int排序的结果是1,10,100,11,12,13,14,15,16,17,18,19,2,20,21,…,9,91,92,93,94,95,96,97,98,99。要保持整形的自然序,行键必须用0作左填充。

行的一次读写是原子操作 (不论一次读写多少列)。这个设计决策能够使用户很容易的理解程序在对同一个行进行并发更新操作时的行为。

(2)列族 column family

hbase表中的每个列,都归属与某个列族。列族是表的chema的一部分(而列不是),必须在使用表之前定义。列名都以列族作为前缀。例如courses:history , courses:math 都属于 courses 这个列族。

访问控制、磁盘和内存的使用统计都是在列族层面进行的。实际应用中,列族上的控制权限能帮助我们管理不同类型的应用:我们允许一些应用可以添加新的基本数据、一些应用可以读取基本数据并创建继承的列族、一些应用则只允许浏览数据(甚至可能因为隐私的原因不能浏览所有数据)。

(3) 单元 Cell

HBase中通过row和columns确定的为一个存贮单元称为cell。由{row key, column( =<family> + <label>), version} 唯一确定的单元。cell中的数据是没有类型的,全部是字节码形式存贮。

(4) 时间戳 timestamp

每个cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。

HBase shell的基本用法

hbase提供了一个shell的终端给用户交互。通过执行 help get 可以看到命令的帮助信息。进入shell很简单,切换目录到hbase的bin下,运行命令:
./hbase shell
以网上的一个学生成绩表的例子来演示hbase的用法。

name

grade

course

math

art

zkb

5

97

87

baoniu

4

89

80

这里grade对于表来说是一个列,course对于表来说是一个列族,这个列族由两个列组成math和art,当然我们可以根据我们的需要在course中建立更多的列族,如computer,physics等相应的列添加入course列族。图中需要注意的是90这个值,列族下面的列也是可以没有名字的。

(1) 建立一个表格scores  具有两个列族grade 和courese

键入命令:
create 'scores','grade', 'course'

(2) 查看当前HBase中具有哪些表

键入命令:
list

(3) 查看表的构造

键入命令:
describe 'scores'

(4) 加入一行数据,行名称为zkb 列族为grade,列名为””(空),值为5

键入命令:
put 'scores','zkb','grade:','5'

(5) 给zkb这一行的数据的列族course添加一列<math,97>

键入命令:
put 'scores','zkb','course:math','97'

(6) 给zkb这一行的数据的列族course添加一列<art,87>

键入命令:
put'scores','zkb','course:art','87'

(7) 加入一行数据,行名称为baoniu 列族为grade,列名为””(空), 值为4

键入命令:
put'scores','baoniu','grade:','4'

(8) 给baoniu这一行的数据的列族course添加一列<math,89>

键入命令:
put'scores','baoniu','course:math','89'

(9) 给Jerry这一行的数据的列族course添加一列<art,80>

键入命令:
put'scores','baoniu','course:art','80'

(10) 查看scores表中zkb的相关数据

键入命令:
get'scores','zkb'

(11) 查看scores表中所有数据
注意:scan命令可以指定startrow,stoprow来scan多个row,例如:scan 'user_test',{COLUMNS =>'info:username',LIMIT =>10, STARTROW => 'test',STOPROW=>'test2'}

键入命令:
scan'scores'

(12) 查看scores表中所有数据courses列族的所有数据

键入命令:
scan'scores',{COLUMNS => 'course'}

(13) 删除scores表

键入命令:
disable'scores'
drop'scores'

总结下,hbase shell常用的操作命令有create,describe,disable,drop,list,scan,put,get,delete,deleteall,count,status等,通过help可以看到详细的用法。

转自http://blog.csdn.net/smcwwh/article/details/7468672,有些许修改,感谢原作者!

hbase的配置以及遇到的问题

这几天在熟悉学习hbase,记录一下配置过程,以及出现的问题。

首先,hbase是什么?先来一段摘抄:

HBase是一个分布式的、面向列的开源数据库,该技术来源于 Fay Chang 所撰写的Google论文“Bigtable:一个结构化数据的分布式存储系统”。就像Bigtable利用了Google文件系统(File System)所提供的分布式数据存储一样,HBase在Hadoop之上提供了类似于Bigtable的能力。HBase是Apache的Hadoop项目的子项目。HBase不同于一般的关系数据库,它是一个适合于非结构化数据存储的数据库。另一个不同的是HBase基于列的而不是基于行的模式。

反正这款数据库在大数据领域是比较出名的,nosql、面向列,都是它的特点。

在安装之前,我们首先最好查看一下hbase和hadoop对应的版本是否兼容。官方文档地址:http://hbase.apache.org/book.html

看到“4. Basic Prerequisites”,往下拉到hadoop那里,有一个表格,表明了hadoop和hbase的兼容情况:

HBase-0.94.x HBase-0.98.x (Support for Hadoop 1.1+ is deprecated.) HBase-1.0.x (Hadoop 1.x is NOT supported) HBase-1.1.x HBase-1.2.x

Hadoop-1.0.x

X

X

X

X

X

Hadoop-1.1.x

S

NT

X

X

X

Hadoop-0.23.x

S

X

X

X

X

Hadoop-2.0.x-alpha

NT

X

X

X

X

Hadoop-2.1.0-beta

NT

X

X

X

X

Hadoop-2.2.0

NT

S

NT

NT

NT

Hadoop-2.3.x

NT

S

NT

NT

NT

Hadoop-2.4.x

NT

S

S

S

S

Hadoop-2.5.x

NT

S

S

S

S

Hadoop-2.6.0

X

X

X

X

X

Hadoop-2.6.1+

NT

NT

NT

NT

S

Hadoop-2.7.0

X

X

X

X

X

Hadoop-2.7.1+

NT

NT

NT

NT

S

我下载的是hbase-0.98.16.1-hadoop2-bin.tar.gz。

下面讲一下配置:

分布式配置

解压文件:
tar -zxvf  hbase-0.98.16.1-hadoop2-bin.tar.gz -C /env/

切换到 hbase目录下的conf目录,编辑hbase-env.sh
vim hbase-env.sh
修改以下两行,并把原有的#去掉,第一行换上你jdk的目录,第二行表示使用hbase自带的zookeeper。

export JAVA_HOME=/usr/java/jdk1.7.0_79/
export HBASE_MANAGES_ZK=true

再修改hbase-site.xml
vim hbase-site.xml
改为以下内容,其中的主机名不要搞错,要在/etc/hosts里面有相应的映射。

<configuration>

  <property>
    <name>hbase.rootdir</name>
    <value>hdfs://main:49002/hbase</value>
    <description>The directory shared byRegionServers.
    </description>
  </property>

  <property>
    <name>hbase.cluster.distributed</name>
    <value>true</value>
  </property>

    <property>
      <name>hbase.zookeeper.property.clientPort</name>
      <value>2222</value>
    </property>

    <property>
      <name>hbase.zookeeper.quorum</name>
      <value>main,slave1,slave2</value>
    </property>

    <property>
      <name>hbase.zookeeper.property.dataDir</name>
      <value>/home/hadoop/zookeeper</value>
    </property>

</configuration>

修改regionservers,我把slave1和slave2加进去
vim regionservers
内容修改为

slave1
slave2

一个节点占一行,保存。
把配置好的hbase复制到另外两台主机上

scp -r /env/hbase-0.98.16.1-hadoop2/ root@slave1:/env/
scp -r /env/hbase-0.98.16.1-hadoop2/ root@slave2:/env/

先启动hadoop的hdfs,然后再启动hbase即可。
在bin目录下,输入以下命令
./start-hbase.sh

不过,我是在虚拟机上弄的分布式环境,在运行hbase的shell的时候,HMaster老是自动退出,查看日志,看到是zookeeper的错误,错误如下:

zookeeper.ClientCnxn: Opening socket connection to server main/192.168.254.100:2299. Will not attempt to authenticate using SASL (unknown error)
2016-01-11 05:23:12,267 WARN [main-SendThread(main:2299)] zookeeper.ClientCnxn: Session 0x0 for server null, unexpected error, closing socket connection and attempting reconnect
java.net.ConnectException: Connection refused

有点郁闷,找了好多解决方法,都不行,后来转念一想,既然是想熟悉一下hbase,运行一下它的shell,就不搞那么复杂了,重新配个单机版,单机版的配置非常简单。

单机版配置

和分布式配置的步骤基本一致,只需要把hbase-site.xml改为简易版的就行,内容如下:

<configuration>
  <property>
    <name>hbase.rootdir</name>
    <value>/home/hbase</value>
    <description>The directory shared byRegionServers.
    </description>
  </property>
</configuration>

改为单机版之后,首先还是得运行hadoop的hdfs,然后再运行./start-hbase.sh,此时jps一下,看到hadoop的namenode启动了,hbase的Hmaster也启动了,此时再运行./hbase shell就正常了。下一篇转一篇文章,学习一下如何直接在shell操作数据库。

啊啊啊赶在12点断网之前。

在java中使用dom4j进行xml文件的解析

之前在做文本挖掘实验的时候,千辛万苦要到这份duc2002的语料库之后,就要对它进行处理了,它是存在xml文件里的。

一直在用java进行相关的处理,所以这次也不例外,java中,关于xml文件解析的框架有很多,在网上也看了很多,最终选择了dom4j这个框架。下面就简单记录一下使用的过程。

首先去下载,我下载的是dom4j1.6.1。下载地址:http://sourceforge.net/projects/dom4j/files/

下载之后解压就行。然后在工程的buildpath里面添加一个external jars,选择刚才解压之后根目录下的dom4j-1.6.1.jar文件。

我的这个xml文件的层级比较多,对照我要需要的内容,这里就列举一下一部分的内容:

<corpus>
	<cluster cid="d061j">
		<title>d061j</title>
		<topics>
		  <topic>d061j</topic>
		</topics>
		<queries/>
		<documents>
		  <document docid="AP880911-0016">
			<title> Hurricane Gilbert Heads Toward Dominican Coast</title>
			<text>
				<s sid="9"> Hurricane Gilbert swept toward the Dominican Republic Sunday, and the Civil Defense alerted its heavily populated south coast to prepare for high winds, heavy rains and high seas.</s>
				<s sid="10"> The storm was approaching from the southeast with sustained winds of 75 mph gusting to 92 mph.</s>
				<s sid="11"> ``There is no need for alarm,'' Civil Defense Director Eugenio Cabral said in a television alert shortly before midnight Saturday.</s>
				<s sid="12"> Cabral said residents of the province of Barahona should closely follow Gilbert's movement.</s>
				<s sid="13"> An estimated 100,000 people live in the province, including 70,000 in the city of Barahona, about 125 miles west of Santo Domingo.</s>
				<s sid="14"> Tropical Storm Gilbert formed in the eastern Caribbean and strengthened into a hurricane Saturday night.</s>
				<s sid="15"> The National Hurricane Center in Miami reported its position at 2 a.m. Sunday at latitude 16.1 north, longitude 67.5 west, about 140 miles south of Ponce, Puerto Rico, and 200 miles southeast of Santo Domingo.</s>
				<s sid="16"> The National Weather Service in San Juan, Puerto Rico, said Gilbert was moving westward at 15 mph with a ``broad area of cloudiness and heavy weather'' rotating around the center of the storm.</s>
				<s sid="17"> The weather service issued a flash flood watch for Puerto Rico and the Virgin Islands until at least 6 p.m. Sunday.</s>
				<s sid="18"> Strong winds associated with the Gilbert brought coastal flooding, strong southeast winds and up to 12 feet feet to Puerto Rico's south coast.</s>
				<s sid="19"> There were no reports of casualties.</s>
				<s sid="20"> San Juan, on the north coast, had heavy rains and gusts Saturday, but they subsided during the night.</s>
				<s sid="21"> On Saturday, Hurricane Florence was downgraded to a tropical storm and its remnants pushed inland from the U.S. Gulf Coast.</s>
				<s sid="22"> Residents returned home, happy to find little damage from 80 mph winds and sheets of rain.</s>
				<s sid="23"> Florence, the sixth named storm of the 1988 Atlantic storm season, was the second hurricane.</s>
				<s sid="24"> The first, Debby, reached minimal hurricane strength briefly before hitting the Mexican coast last month .</s>
			</text>
		  </document>
		</documents>
	</cluster>
</corpus>

每个cluster有自己的title,接下来,documents是和cluster同级的,ducuments里面又有若干document,每个document下有title,text,text下有p标签,p标签下又有各个句子,标签是s。

我的任务是,将每一篇document的内容输出到一个文本文件,命名格式为:”cl”+cid+”-“+”docid”+docid,其中cid和docid分别是cluster和document的一个属性。

PS:我把文本文件duc2002.xml已经复制到本项目的scr下了。

下面贴上源代码:

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.util.Iterator;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

public class MyTest {
	public static void main(String[] args) throws Exception {
		SAXReader reader = new SAXReader();
		Document thedocument = reader.read(new File("./src/duc2002.xml"));
		Element root = thedocument.getRootElement();
		System.out.println(root);
		Iterator it = root.elementIterator();
		int count = 0;
		for (Iterator i = root.elementIterator("cluster"); i.hasNext();) {
			Element cluster = (Element) i.next();
			System.out.println("cluster id:"
					+ cluster.attribute("cid").getText()); // cluster的id
			Element documents = cluster.element("documents");
			for (Iterator j = documents.elementIterator("document"); j
					.hasNext();) {
				Element document = (Element) j.next();
				Element title = document.element("title");
				for (Iterator k = document.element("models").elementIterator(
						"model"); k.hasNext();) {
					Element model = (Element) k.next();
				}
				File file = new File("F:\\xmltest\\" + "cl"
						+ cluster.attribute("cid").getText() + "-" + "docid"
						+ document.attribute("docid").getText() + ".txt");
				file.createNewFile();
				BufferedWriter bw = new BufferedWriter(new FileWriter(file,
						true));
				bw.write("title:" + title.getText());
				bw.newLine();

				for (Iterator l = document.element("text").element("p")
						.elementIterator("s"); l.hasNext();) {
					Element sentence = (Element) l.next();
					bw.write(sentence.getText().trim());
					bw.newLine();
				}
				bw.close();
			}
			count++;
			System.out.println(count + "finished!");
		}
		
	}
}

这段程序在F盘的xmltest文件夹下不断生成文本文件,我就拿列举的那部分内容生成的文本文件做例子,输出结果是这样的:

xml文件输出为txt结果

对照程序,再简单整理一下dom4j基本的xml解析功能:

  • 第13-15行,初始化解析器,读入xml文件,获得根节点
  • 第19行,用root.elementIterator("cluster")来迭代获得root节点下的cluster
  • 第20行,用Element cluster = (Element) i.next();来获得每一个cluster,如果要获得属性,比如xml文件第2行的cid,可以用第22行的cluster.attribute("cid").getText());
  • 用element方法获得子节点,如23行的Element documents = cluster.element("documents");
  • 获得节点的内容,直接用getText()方法,如第38行,获得<title>的内容