HBase Shell 基本操作 查询过滤 命令

0.进入hbase shell

# hbase shell
hbase > help
hbase > help “get” #查看单独的某个命令的帮助

1. 一般命令

  1. status 查看状态

  2. version 查看版本

2.DDL(数据定义语言Data Definition Language)命令

    1. 创建表

        create ‘表名称’,’列名称1’,’列名称2’,’列名称3’ 

create 'student','info','grade'

    2.列出所有的表

list 
blob.png

list ‘abc.*’ #显示abc开头的表

    3.获得表的描述

describe ‘table_name’ 

blob.png

blob.png

Table student is ENABLED
student
COLUMN FAMILIES DESCRIPTION
{
NAME => 'grade', 
BLOOMFILTER => 'ROW', # bloom filter的作用是对一个region下查找记录所在的hfile有用。一个region下hfile数量越多,bloom filter的作用越明显。
VERSIONS => '1', # 版本 需要历史版本数据的应用通常可以设置为 3
IN_MEMORY => 'false', # 内存缓存
KEEP_DELETED_CELLS =>'FALSE',  
DATA_BLOCK_ENCODING => 'NONE', 
TTL => 'FOREVER', 
COMPRESSION => 'NONE', # 文件压缩处理
MIN_VERSIONS => '0',
BLOCKCACHE => 'true', 
BLOCKSIZE => '65536', 
REPLICATION_SCOPE => '0'
}

    4.删除一个列族 

alter,disable, enable

disable 'member'
# 删除列族时必须先将表给disable
alter 'member',{NAME=>'member_id',METHOD=>'delete'}
# 删除后继续
enable 'member'enable 'member'

    5.删除表

disable 'table_name'drop 'table_name'

blob.png

    6.查询表是否存在

exists 'table_name'1

    7.判断表是否enabled

is_enabled 'table_name'1

    8.更改表名

//快照 
//需要开启快照功能,在hbase-site.xml文件中添加如下配置项:

<property>
<name>hbase.snapshot.enabled</name>
<value>true</value>
</property>

//命令
hbaseshell> disable 'tableName'
hbaseshell> snapshot 'tableName', 'tableSnapshot'
hbaseshell> clone_snapshot 'tableSnapshot', 'newTableName'
hbaseshell> delete_snapshot 'tableSnapshot'
hbaseshell> drop 'tableName'

3.DML(data manipulation language)操作

    1.插入

blob.png

在ns1:t1或者t1表里的r1行,c1列中插入值,ts1是时间
  # t是table 't1'表的引用
  t.put 'r1','c1','value',ts1,{ATTRIBUTES=>{'mykey'=>'myvalue'}}

blob.png

    2.获取一条数据

get <table>,<rowkey>,[<family:column>,….]

blob.png

# 获取一个id的所有数据
get 'table_name','row_index'

# 获取一个id,一个列族的所有数据
get 'table_name','row_index','info'

# 获取一个id,一个列族中一个列的所有数据
get 'table_name','row_index','info:age'

blob.png

    3.更新一条记录

通过 put 覆盖列值

put 'table_name','row_index','info:column','value'

    4.通过timestrap来获取两个版本的数据

# 得到某个时间版本的记录
get'table_name','row',{COLUMN=>'info:column',TIMESTRAP=>1321586238965}

# 得到另一个个时间版本的记录
get'table_name','row',{COLUMN=>'info:column',TIMESTRAP=>1321586271843}

    5.全表扫描

scanner 相当于:select * from table_name

scan <table>, {COLUMNS => [ <family:column>,.... ], LIMIT => num}
# 另外,还可以添加STARTROW、TIMERANGE和FITLER等高级功能

2018-01-22_234806.png

scan 'hbase:meta'
scan 'hbase:meta',{COLUMNS => 'info:regioninfo'}
scan 'ns1:t1',{COLUMNS=>['c1','c2'],LIMIT=>10,STARTROW=>'xyz'}
scan 't1',{COLUMNS=>'c1',TIMERANGE=>[1303668804,1303668904]}
scan 't1',{REVERSED=>true}
scan 't1',{
    ROWPREFIXFILTER=>'row2',
    FILTER=>"(QualifierFilter(>=,'binary:xyz')) 
    AND (TimestampsFilter(123,456))"}
scan 't1',{FILTER => org.apache.hadoop.hbase.filter.ColumnPaginationFilter.new(1,0)}
scan 't1',{CONSISTENCY=>'TIMELINE'}

# 设置操作属性:
scan 't1',{COLUMNS => ['c1','c2'],ATTRIBUTES=>{'mykey'=>'myvalue'}}
scan 't1',{COLUMNS=>['c1','c2'],AUTHORIZATIONS=>['PRIVATE','SECRET']}
有个额外的选项:CACHE_BLOCKS,默认为true
还有个选项:RAW,返回所有cells(包括删除的markers和uncollected deleted cells,不能用来选择特定的columns,默认为default)
如:scan 't1',{RAW=>true,VERSIONS=>10}

blob.png

    6.删除记录

blob.png

# 删除指定rowkey的 'info:age' 字段
delete 'table_name','row_index','info:age'

# 删除整行
deleteall 'table_name','row_index'

blob.png

    7.查询表中有多少行

 hbase> count 'ns1:t1'  # namespace命名空间分组
 hbase> count 't1'
 hbase> count 't1', INTERVAL => 100000 # 每隔多少行显示一次count,默认是1000
 hbase> count 't1', CACHE => 1000 # 每次去取的缓存区大小,默认是10,调整该参数可提高查询速度
 
 hbase> count 't1', INTERVAL => 10, CACHE => 1000

    8.清空表

truncate 'students'
先删除表,再重建

truncate 日志:
hbase shell>truncate 'students'
Truncating 'students' table (it may take a while):
- Disabling table...
- Dropping table...
- Creating table ...

5.高级 scan 查询

  1.限制条件

限制查找列:

scan ‘table_name’,{COLUMNS=> 'column-familyinfo’}  # 列族
scan ‘table_name’,{COLUMNS=> 'info:regioninfo’}    # 字段
scan ‘table_name’,{COLUMNS=>[‘c1’,’c2’]}    # 多个列、字段

blob.png

限制查找条数:

scan 'table_name', {COLUMNS => [ 'c'], LIMIT => n}

blob.png

限制时间范围:

scan 'table_name', {TIMERANGE=>[ minStamp, maxStamp]}

blob.png

  2.FILTER 过滤器

    1.rowkey过滤

PrefixFilter:

行键前缀过滤器

scan 'table_name',{FILTER => "PrefixFilter('rowkey_prefix')"}

blob.png

    2.列族过滤

QuanlifierFilter:

列名限定符过滤器

scan 'table_name',{FILTER => "QualifierFilter(CompareOp,'BinaryComparator')"} 
# 参数是关系比较运算符 和 二进制比较器

blob.png

ColumnPrexfixFilter:

列名前缀过滤器

scan 'table_name',{FILTER => "ColumnPrefixFilter('colunm')"}

blob.png

MultipleColumnPrexfixFilter:

多个列名前缀过滤器

scan 'table_name',{FILTER => "MultipleColumnPrefixFilter('c1','c2')" }

blob.png

    3.列值过滤

SingleColumnValueFilter:

列值过滤器

# 需要导入类
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter
import org.apache.hadoop.hbase.filter.CompareFilter
import org.apache.hadoop.hbase.filter.SubstringComparator

scan 'table_name',{FILTER => SingleColumnValueFilter.new(
  Bytes.toBytes('info'),  # 列族
  Bytes.toBytes('column'),    # 字段
  CompareFilter::CompareOp.valueOf('EQUAL'), # 比较器
  Bytes.toBytes('my value')) # 值
}

blob.png

参数

有两个参数类在各类Filter中常常出现。统一介绍下:

(1)比较运算符 CompareFilter.CompareOp
EQUAL                      相等
GREATER                    大于
GREATER_OR_EQUAL           大于等于
LESS                       小于
LESS_OR_EQUAL              小于等于
NOT_EQUAL                  不等于

(2)比较器  
BinaryComparator           匹配完整字节数组 
BinaryPrefixComparator     匹配字节数组前缀 
RegexStringComparator      正则表达式匹配
SubstringComparator        子串匹配

    4.组合过滤器

    多个过滤器可以通过 AND OR 连接进行组合过滤

# 列如:
hbase(main):008:0> scan 'emp', {FILTER => "(MultipleColumnPrefixFilter('sal','COMM','deptno'))
 AND (SingleColumnValueFilter('empinfo','deptno',=,'substring:20'))"}

blob.png

本文地址: 

  http://www.52xjava.cn/2018/01/23/hbase-shell-command/

参考文章: 

https://www.cnblogs.com/mengfanrong/p/5337799.html

https://www.cnblogs.com/skyl/p/4807793.html

http://blog.csdn.net/power0405hf/article/details/49824579

http://blog.csdn.net/qq_27078095/article/details/56482010

Validate 表单验证插件

    说明:

required:true 必须输入的字段。
remote:"check.php" 使用 ajax 方法调用 check.php 验证输入值。
email:true 必须输入正确格式的电子邮件。
url:true 必须输入正确格式的网址。
date:true 必须输入正确格式的日期。日期校验 ie6 出错,慎用。
dateISO:true 必须输入正确格式的日期(ISO),例如:2009-06-23,1998/01/22。只验证格式,不验证有效性。
number:true 必须输入合法的数字(负数,小数)。
digits:true 必须输入整数。
creditcard: 必须输入合法的信用卡号。
equalTo:"#field" 输入值必须和 #field 相同。
accept: 输入拥有合法后缀名的字符串(上传文件的后缀)。
maxlength:5 输入长度最多是 5 的字符串(汉字算一个字符)。
minlength:10 输入长度最小是 10 的字符串(汉字算一个字符)。
rangelength:[5,10] 输入长度必须介于 5 和 10 之间的字符串(汉字算一个字符)。
range:[5,10] 输入值必须介于 5 和 10 之间。
max:5 输入值不能大于 5。
min:10 输入值不能小于 10。

    还可以自定义验证规则

    addMethod:name, method, message
$.validator.addMethod("checkUsername",function(value,element,params){
    var flag = false;
    $.ajax({
        async:false, //改为同步  
        type:"POST",
        url:"${pageContext.request.contextPath}/check",
        data:{"username":value},
        dataType:"json",
        success:function(data){
            flag = data.isExist;
            return !flag;
        }
    });
    return !flag;
})

    debug,只验证不提交表单

    如果这个参数为true,那么表单不会提交,只进行检查,调试时十分方便。

$().ready(function(){
    $("#myForm").validate({
        debug:true
    })
});

    案例:

<!-- 引入jQuery核心js文件 -->
<script src="${pageContext.request.contextPath }/js/jquery-1.11.3.min.js"></script>
<!-- 引入validate插件 -->
<script src="${pageContext.request.contextPath }/js/jquery.validate.js"></script>
<style>
body {
    margin-top: 20px;
    margin: 0 auto;
}

font {
    color: #666;
    font-size: 22px;
    font-weight: normal;
    padding-right: 17px;
}
.error{
    color:red;
    font-size: 12pt;
}
</style>
<script type="text/javascript">
$(function(){

       //定义校验用户名是否存在的方法
       $.validator.addMethod("checkUsername",function(value,element,params){
           var flag = false;
           $.ajax({
               async:false, //改为同步  
               type:"POST",
               url:"${pageContext.request.contextPath}/check",
               data:{"username":value},
               dataType:"json",
               success:function(data){
                   flag = data.isExist;
                   return !flag;
               }
           });
           return !flag;
       })
                         
       $.validator.addMethod("telephone",function(value,element,params){
           //定义一个手机号码的正则
           var reg = /^1[3|4|5|8][0-9]\d{4,8}$/;
           return reg.test(value);
       });
       
       $("#regForm").validate({
           rules:{
               "username":{
                   "required":true,
                   "checkUsername":true
               },
               "password":{
                   "required":true,
                   "rangelength":[6,12]
               },
               "confirmpwd":{
                   "equalTo":"#password"
               },
               "name":{
                   "required":true
               },
               "email":{
                   "required":true,
                   "email":true
               },
               "telephone":{
                   "telephone":true
               },
                "validateCode"{
                    "required":true
               }
           },
           messages:{
               "username":{
                   "required":"用户名不能为空",
                   "checkUsername":"用户名已经存在"
               },
               "password":{
                   "required":"密码不能为空",
                   "rangelength":"密码长度应为6-12位"
               },
               "confirmpwd":{
                   "equalTo":"两次输入的密码不一致"
               },
               "name":{
                   "required":"姓名不能为空"
               },
               "email":{
                   "required":"邮箱不能为空",
                   "email":"邮箱格式不正确"
               },
               "telephone":{
                   "telephone":"手机格式不正确"
               },
                "validateCode":{
                   "telephone":"验证码不能为空"
               }
           }
       });
   })
</script>
<form id="regForm" class="form-horizontal" style="margin-top:5px;" 
   action="${pageContext.request.contextPath }/regist" method="post">
       <div class="form-group">
           <label for="username" class="col-sm-3 control-label">用户名</label>
           <div class="col-sm-8">
<input type="text" class="form-control" name="username" id="username" placeholder="请输入用户名">
</div>
       </div>
       <div class="form-group">
           <label for="password" class="col-sm-3 control-label">密码</label>
           <div class="col-sm-8">
               <input type="password" class="form-control" name="password" id="password" placeholder="请输入密码">
           </div>
       </div>
       <div class="form-group">
           <label for="confirmpwd" class="col-sm-3 control-label">确认密码</label>
           <div class="col-sm-8">
               <input type="password" class="form-control" name="confirmpwd" id="confirmpwd" placeholder="请输入确认密码">
           </div>
       </div>
       <div class="form-group">
           <label for="email" class="col-sm-3 control-label">Email</label>
           <div class="col-sm-8">
               <input type="text" class="form-control" name="email" id="email" placeholder="Email">
           </div>
       </div>
       <div class="form-group">
           <label for="name" class="col-sm-3 control-label">姓名</label>
           <div class="col-sm-8">
               <input type="text" class="form-control" name="name" id="name" placeholder="请输入姓名">
           </div>
       </div>
       <div class="form-group">
           <label for="telephone" class="col-sm-3 control-label">联系电话</label>
           <div class="col-sm-8">
               <input type="text" class="form-control" id="telephone" name="telephone">
           </div>
       </div>

       <div class="form-group">
           <label for="validateCode" class="col-sm-3 control-label">验证码</label>
           <div class="col-sm-4">
               <input type="text" class="form-control" id="validateCode" name="validateCode">
           </div>
           <div class="col-sm-2">
                <img id="loginform:vCode" src="${pageContext.request.contextPath }/validatecode.jsp"
               onclick="vCode()" />
           </div>
       </div>

       <div class="form-group">
           <div class="col-sm-offset-1 col-sm-10">
               <input class="btn btn-success btn-block" type="submit"  value="立即注册" />
           </div>
       </div>
</form>

本文地址:

 http://www.52xjava.cn/2018/01/15/validate-form-validation-plugin/

JavaMail 通过QQ邮箱发送邮件

您需要把依赖的 JavaMail mail.jarmail.zip 添加到项目

工具类

import java.security.GeneralSecurityException;
import java.util.Properties;

import javax.mail.Authenticator;
import javax.mail.Message;
import javax.mail.MessagingException;
import javax.mail.PasswordAuthentication;
import javax.mail.Session;
import javax.mail.Transport;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMessage.RecipientType;

import com.sun.mail.util.MailSSLSocketFactory;

public class MailUtils {

	/**
	 * 发送邮件
	 * @param email 收件人邮箱
	 * @param emailMsg 发送的内容
	 * @throws AddressException
	 * @throws MessagingException
	 * @throws GeneralSecurityException
	 */
	public static void sendMail(String email, String emailMsg)
			throws AddressException, MessagingException, GeneralSecurityException {
			
		// 1.创建一个程序与邮件服务器会话对象 Session
		Properties props = new Properties();
		props.setProperty("mail.transport.protocol", "SMTP");
		props.setProperty("mail.smtp.host", "smtp.qq.com");
		props.setProperty("mail.smtp.auth", "true");// 指定验证为true
		
		//  关于QQ邮箱,还要设置SSL加密,加上以下代码即可
		MailSSLSocketFactory sf = new MailSSLSocketFactory();
	        sf.setTrustAllHosts(true);
	        props.put("mail.smtp.ssl.enable", "true");
	        props.put("mail.smtp.ssl.socketFactory", sf);

		// 创建验证器
		Authenticator auth = new Authenticator() {
			public PasswordAuthentication getPasswordAuthentication() {
			//发信人的账号 密码
			return new PasswordAuthentication(gwk_87@qq.com, smtp的验证码);
			}
		};

		Session session = Session.getInstance(props, auth);

		// 2.创建一个Message,它相当于是邮件内容
		
		// 创建默认的 MimeMessage 对象
		Message message = new MimeMessage(session);
		
		// 设置发送者
		message.setFrom(new InternetAddress(gwk_87@qq.com)); 
		
		// 设置发送方式与接收者
		message.setRecipient(Message.RecipientType.TO, new InternetAddress(email)); 

		// 设置消息头
		message.setSubject("请激活邮件以完成注册");
		
		// 设置消息体 -- 普通文字
                // message.setText(emailMsg);
		
		//设置消息体 -- 发送 HTML 消息
		message.setContent("这是一封激活邮件,<br>"
				+ "<a href='#'>请访问点击,激活账号</a>", "text/html;charset=utf-8");

		// 3.创建 Transport用于将邮件发送
		Transport.send(message);
	}
}

Mapper 判断输入数据的文件名

很多时候我们在一个map-reduce任务中,会用到Join,这样整个job的输入可能就是两个以上的文件了(换句话说:mapper要处理两个以上的文件)。

mapper的输入可以是一个文件夹:

    FileInputFormat.setInputPaths(conf, new Path("/tmp/"));

1.在java代码中获取文件名

在java代码中获取文件名,需要得到input split 所在的文件名,需要从map函数中的context参数着手。

    // 获取 input split 所在的文件名
    private String getFileName(MapContext context) { 
        org.apache.hadoop.mapreduce.lib.input.FileSplit inputSplit = (FileSplit) context.getInputSplit();
        return inputSplit.getPath().getName();      
    }

如果需要获得在hdfs上的绝对路径,可以用以下代码实现:

String filepath = ((FileSplit)context.getInputSplit()).getPath().toString();

获取文件名的大致流程为:Context(map函数里) → InputSplit → FileSplit → Path → String(file name)。

2.在streaming中获取文件名

实际中经常用python开发streaming程序,在python代码中可以用如下方式获得文件名:

import os
filepath = os.environ["mapreduce_map_input_file"]

通过上面的代码即可达到获取文件名的目的,通过代码也很容易看出,文件名保存在名为mapreduce_map_input_file的环境变量中。

需要稍微注意的地方有两点: 
1.filepath保存的是文件在hdfs上的完整路径。 
2.新版本的api为mapreduce_map_input_file,老版本的api为map_input_file,在集群上尝试了老版本的api,代码会报错