基于Hbase的微博案例
需求
1、 发布微博内容
a. 在微博内容表中 添加一条数据(发布者)
b. 在微博内容接收邮件箱表对所有粉丝用户添加数据(订阅者)
scan 'weibo:receive-content-email',{VERSIONS=>5}
2、添加关注用户
a. 在微博用户关系表中 添加新的好友关注(attends)
b. 从被关注用户角度来说, 新增粉丝用户(fans)
c. 微博邮件箱表添加关注用户发布的微博内容
3、移除或者取消关注用户
a. 在微博用户关系表中 移除新的好友关注(attends)
b. 从被关注用户角度来说, 删除粉丝用户(fans)
c. 微博邮件箱表删除关注用户发布的微博内容
4、获取关注用户发布的微博内容
a. 从微博内容邮件表中获取该用户其关注用户的微博内容的rowkey
b. 根据上面获取到的微博内容的rowkey 获取微博内容
微博展示的内容信息:
message: 发布者ID , 时间戳 , content
表的设计
分析微博:
用户群体: 关注用户 和用户粉丝
用户行为: 发布微博、添加或者移除关注用户
数据存储: 分布式 mysql 数据库
考虑因素:响应时间 妙级 无延迟
对你的技术团队就是一个很大的考验
引出hbase 数据库存储 来实现响应时间 妙级 无延迟 、
hbase 是hadoop 的分布式数据库
使用数据库的时候
拦路虎: 表的设计(合理的来设计 因素多元化)
命名空间(类似于传统关系型数据库中的schema): 区分不同的业务表
namespace name:weibo
设计那些表:
a.微博内容表
xxx 发布 xx 内容
table name : weibo:content
rowkey: 被关注用户ID_时间戳
columnfamily: cf
colunmnlabel: (任意变化的)
图片
内容
标题
version: 只需要一个版本
rowkey:
a.唯一性 每条数据是唯一的
b.长度 (<=64 kb 建议 10-100 byte 最佳 8-16 byte)表 rowkey 是hbase中数据产生冗余的因素
c.散列原则
举例:
时间戳_用户ID 作为rowkey
大量的用户在同一时刻 发布微博内容
121_001
121_002
121_003
121_004
===>
集中到某个region 会造成单独几个region 负载量偏大 而其他 region 完全没有负载
d. 业务相关的设计规范:
方便查询 尽可能将查询知道放到 rowkey
列簇设计:
Hbase 是面向列簇存储 region start rowkey 到 stop rowkey 范围内的一个列簇下的数据 对应一个hdfs file 称为StoreFile 也可以称为HFile 所以如果跨列查询 速度相对来说就会慢很多 so 设计hbase 表 列簇的是 一般1-2个,(1个最佳)
b.用户关系表
用户id fans attends
table name : weibo:relations
rowkey: 用户ID(发布者的用户ID)
columnfamily: attends、fans
colunmnlabel:
关注用户ID
粉丝用户ID
colunmnvalue: 关注用户ID
粉丝用户ID
version: 只需要一个版本
c.用户微博内容接收邮件箱表
table name : weibo:receive-content-email
rowkey: 用户ID(粉丝用户ID)
columnfamily: cf
colunmnlabel:
用户ID(发布者ID 被关注用户ID)
colunmnvalue:
取微博内容的rowkey
version: 1000
10001: cf_001_yyyyy
10001: cf_001_xxxxx
hbase 常用命令:
1. disable 'weibo:content': 禁用表
2. drop 'weibo:content': 删除表
3.truncate 'weibo:relations' :清空表数据
- Disabling table...
- Dropping table...
- Creating table...
list_namespace: 查看命名空间
list: 查看表的列表信息
default: 默认使用的命名空间
hbase : 系统默认使用命名空间
drop_namespace 'weibo': 删除指定的命名空间
代码实现
package com.ibeifeng.hbase.weibo.hbase_weibo;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.MasterNotRunningException;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.ZooKeeperConnectionException;
import org.apache.hadoop.hbase.client.Delete;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.client.HConnection;
import org.apache.hadoop.hbase.client.HConnectionManager;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.RowFilter;
import org.apache.hadoop.hbase.filter.SubstringComparator;
import org.apache.hadoop.hbase.util.Bytes;public class WeiBo {
private Configuration conf =HBaseConfiguration.create();
private static final byte[] CONTENT=Bytes.toBytes("weibo:content");
private static final byte[] RELATIONS=Bytes.toBytes("weibo:relations");
private static final byte[] RECEIVE_CONTENT_EMAIL=Bytes.toBytes("weibo:receive-content-email");//创建 命名空间(库) public void initNameSpace(){ HBaseAdmin admin=null; try { admin=new HBaseAdmin(conf); /** * 命名空间(类似于传统关系型数据库中的schema): 区分不同的业务表 namespace name:weibo */ NamespaceDescriptor weibo=NamespaceDescriptor.create("weibo") .addConfiguration("creator", "beifeng")// .addConfiguration("createTime", System.currentTimeMillis()+"") .build(); admin.createNamespace(weibo); } catch (MasterNotRunningException e) { e.printStackTrace(); } catch (ZooKeeperConnectionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=admin){ try { admin.close(); } catch (IOException e) { e.printStackTrace(); } } } } // 建表 public void initTable(){ createContent(); createRelations(); createReceiveContentEmails(); } private void createContent() { /** * a.微博内容表: xxx 发布 xx 内容 table name : weibo:content rowkey: 用户ID_时间戳 columnfamily: cf colunmnlabel: 图片 内容 标题 version: 只需要一个版本 */ HBaseAdmin admin=null; try { admin=new HBaseAdmin(conf); HTableDescriptor content=new HTableDescriptor(TableName.valueOf(CONTENT)); HColumnDescriptor c_cf=new HColumnDescriptor(Bytes.toBytes("cf")); c_cf.setBlockCacheEnabled(true); //推荐是计算后的值 c_cf.setBlocksize(2097152); // 一定事先配置好 // c_cf.setCompressionType(Algorithm.SNAPPY); c_cf.setMaxVersions(1); c_cf.setMinVersions(1); content.addFamily(c_cf); admin.createTable(content); } catch (MasterNotRunningException e) { e.printStackTrace(); } catch (ZooKeeperConnectionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=admin){ try { admin.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void createRelations() { /** * b.用户关系表: 用户id fans attends table name : weibo:relations rowkey: 用户ID columnfamily: attends、fans colunmnlabel: 关注用户ID 粉丝用户ID colunmnvalue: 用户ID version: 只需要一个版本 */ HBaseAdmin admin=null; try { admin=new HBaseAdmin(conf); HTableDescriptor relations=new HTableDescriptor(TableName.valueOf(RELATIONS)); HColumnDescriptor attends=new HColumnDescriptor(Bytes.toBytes("attends")); attends.setBlockCacheEnabled(true); attends.setBlocksize(2097152); attends.setMaxVersions(1); attends.setMinVersions(1); HColumnDescriptor fans=new HColumnDescriptor(Bytes.toBytes("fans")); fans.setBlockCacheEnabled(true); fans.setBlocksize(2097152); fans.setMaxVersions(1); fans.setMinVersions(1); relations.addFamily(attends); relations.addFamily(fans); admin.createTable(relations); } catch (MasterNotRunningException e) { e.printStackTrace(); } catch (ZooKeeperConnectionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=admin){ try { admin.close(); } catch (IOException e) { e.printStackTrace(); } } } } private void createReceiveContentEmails() { /** * c.用户微博内容接收邮件箱表: table name : weibo:receive-content-email rowkey: 用户ID columnfamily: cf colunmnlabel: 用户ID colunmnvalue: 取微博内容的rowkey version: 1000 */ HBaseAdmin admin=null; try { admin=new HBaseAdmin(conf); HTableDescriptor receive_content_email=new HTableDescriptor(TableName.valueOf(RECEIVE_CONTENT_EMAIL)); HColumnDescriptor rce_cf =new HColumnDescriptor(Bytes.toBytes("cf")); rce_cf.setBlockCacheEnabled(true); rce_cf.setBlocksize(2097152); rce_cf.setMaxVersions(1000); rce_cf.setMinVersions(1000); receive_content_email.addFamily(rce_cf); admin.createTable(receive_content_email); } catch (MasterNotRunningException e) { e.printStackTrace(); } catch (ZooKeeperConnectionException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=admin){ try { admin.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 发布微博内容: * a. 在微博内容表中 添加一条数据(发布者) b. 在微博内容接收邮件箱表对所有粉丝用户添加数据(订阅者) * @param uid * 发布者ID * @param content * 发布微博内容 */ public void publishContent(String uid,String content){ HConnection connection=null; try { connection=HConnectionManager.createConnection(conf); //a. 在微博内容表中 添加一条数据(发布者) HTableInterface contentTBL=connection.getTable(TableName.valueOf(CONTENT)); long timestamp=System.currentTimeMillis(); String rowkey=uid+"_"+timestamp; Put put = new Put(Bytes.toBytes(rowkey)); //四个值分别代表colfamily,columnlabel,timestamp,value put.add(Bytes.toBytes("cf"), Bytes.toBytes("content"),timestamp, Bytes.toBytes(content)); contentTBL.put(put); //b. 在微博内容接收邮件箱表对所有粉丝用户添加数据(订阅者) // 1. 查询 用户关系表 获取该用户的粉丝用户 HTableInterface relationsTBL=connection.getTable(TableName.valueOf(RELATIONS)); // get 'tablename','rowkey','cf','cq' //rowkey Get get=new Get(Bytes.toBytes(uid)); //cf get.addFamily(Bytes.toBytes("fans")); Result result = relationsTBL.get(get); List<byte[]> fans = new ArrayList<byte[]>(); //设置uid用户下所有的粉丝 for (Cell cell : result.rawCells()) { //RELATIONS表里的columnlabel成为RECEIVE_CONTENT_EMAIL的rowkey fans.add(CellUtil.cloneQualifier(cell)); } // 数据判断 if(fans.size() <= 0) return ; // 获取微博内容邮件箱表 HTableInterface rceTBL=connection.getTable(RECEIVE_CONTENT_EMAIL); List<Put> puts=new ArrayList<Put>(); for (byte[] fan : fans) { Put fanPut=new Put(fan); //设置rowkey fanPut.add(Bytes.toBytes("cf"), Bytes.toBytes(uid),timestamp, Bytes.toBytes(rowkey)); puts.add(fanPut); } rceTBL.put(puts); /** * cell : primary key {rowkey , column(family+label),version(timestamp)}:value */ } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=connection){ try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 添加关注用户: * a. 在微博用户关系表中 添加新的好友关注(attends) b. 从被关注用户角度来说, 新增粉丝用户(fans) c. 微博邮件箱表添加关注用户发布的微博内容 * @param uid * 粉丝 ID * @param attends * 被关注用户ID */ public void addAttends(String uid, String ...attends){ //参数过滤 if(attends==null||attends.length<=0) return; /** * a.在微博用户关系表中 添加新的好友关注(attends) * (0001) ,(0002,0003) * rowkey column value * 0001 attends:0002,0002 * 0001 attends:0003,0003 * * rowkey column value * 0003 fans:0001,0001 * 0002 fans:0001,0001 * */ HConnection connection=null; try { connection=HConnectionManager.createConnection(conf); HTableInterface realtionsTBL=connection.getTable(RELATIONS); List<Put> puts=new ArrayList<Put>(); //a. 在微博用户关系表中 添加新的好友关注(attends) Put attendsPut=new Put(Bytes.toBytes(uid)); for (String attend : attends) { attendsPut.add(Bytes.toBytes("attends"), Bytes.toBytes(attend), Bytes.toBytes(attend)); //b. 从被关注用户角度来说, 新增粉丝用户(fans) Put fansPut=new Put(Bytes.toBytes(attend)); fansPut.add(Bytes.toBytes("fans"), Bytes.toBytes(uid), Bytes.toBytes(uid)); puts.add(fansPut); } puts.add(attendsPut); realtionsTBL.put(puts); //c. 微博邮件箱表添加关注用户发布的微博内容的rowkey /** * 1. 首先查询被关注用户ID发布的微博内容的rowkey * 单个被关注用户ID, --查询content ->微博内容的rowkey * 0001_xxx * 0001_aaa * 0002_yyy * 0002_zzz * 2. 将前面获取的rowkey列表 遍历出来在微博内容邮件表中正式添加数据 * */ HTableInterface contentTBL= connection.getTable(CONTENT); Scan scan =new Scan(); List<byte[]> rowkeys=new ArrayList<byte[]>(); for(String attend: attends){ //扫描表的rowkey,含有字符串("被关注用户ID_") RowFilter filter=new RowFilter(CompareOp.EQUAL, new SubstringComparator(attend+"_")); scan.setFilter(filter); ResultScanner result=contentTBL.getScanner(scan); // 迭代器遍历 Iterator<Result> itearor=result.iterator(); while(itearor.hasNext()){ Result r=itearor.next(); for(Cell cell:r.rawCells()){ rowkeys.add(CellUtil.cloneRow(cell)); } } } if(rowkeys.size()<= 0) return; // 2. 将前面获取的rowkey列表 遍历出来在微博内容邮件表中正式添加数据 HTableInterface rceTBL=connection.getTable(RECEIVE_CONTENT_EMAIL); List<Put> rcePuts=new ArrayList<Put>(); for (byte[] rk : rowkeys) { Put put =new Put(Bytes.toBytes(uid)); String rowkey=Bytes.toString(rk); // substring 包前不包后 String attend=rowkey.substring(0, rowkey.indexOf("_")); long timestamp=Long.parseLong(rowkey.substring(rowkey.indexOf("_")+1)); put.add(Bytes.toBytes("cf"), Bytes.toBytes(attend),timestamp, rk); rcePuts.add(put); } rceTBL.put(rcePuts); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=connection){ try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** *移除或者取消关注用户 a. 在微博用户关系表中 移除新的好友关注(attends) b. 从被关注用户角度来说, 删除粉丝用户(fans) c. 微博邮件箱表删除关注用户发布的微博内容 * @param uid * 粉丝用户ID * @param attends * 被关注用户ID */ public void removeAttends(String uid,String ...attends){ //参数过滤 if(attends==null||attends.length<=0) return; HConnection connection=null; try { connection=HConnectionManager.createConnection(conf); //a. 在微博用户关系表中 移除新的好友关注(attends) HTableInterface relationsTBL=connection.getTable(RELATIONS); List<Delete> deletes=new ArrayList<Delete>(); Delete attendsDelete =new Delete(Bytes.toBytes(uid)); for (String attend : attends) { attendsDelete.deleteColumn(Bytes.toBytes("attends"), Bytes.toBytes(attend)); //b. 从被关注用户角度来说, 删除粉丝用户(fans) Delete fansDelete=new Delete(Bytes.toBytes(attend)); fansDelete.deleteColumn(Bytes.toBytes("fans"), Bytes.toBytes(uid)); deletes.add(fansDelete); } deletes.add(attendsDelete); relationsTBL.delete(deletes); //c. 微博邮件箱表删除关注用户发布的微博内容 HTableInterface rceTBL=connection.getTable(RECEIVE_CONTENT_EMAIL); Delete rceDelete=new Delete(Bytes.toBytes(uid)); for(String attend:attends){ /** * Delete the latest version of the specified column. */ // rceDelete.deleteColumn(Bytes.toBytes("cf"), Bytes.toBytes(attend)); // Delete all versions of the specified column with a timestamp less than rceDelete.deleteColumns(Bytes.toBytes("cf"), Bytes.toBytes(attend), System.currentTimeMillis()+Integer.MAX_VALUE); } rceTBL.delete(rceDelete); } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=connection){ try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } } /** * 粉丝用户 去获取关注用户发布的微博内容: * a. 从微博内容邮件表中获取该用户其关注用户的微博内容的rowkey b. 根据上面获取到的微博内容的rowkey 获取微博内容 * @param uid * 粉丝用户ID */ public List<Message> getAttendsContens(String uid){ HConnection connection=null; List<Message> messages=new ArrayList<Message>(); try { connection=HConnectionManager.createConnection(conf); //a. 从微博内容邮件表中获取该用户其关注用户的微博内容的rowkey HTableInterface rceTBL=connection.getTable(RECEIVE_CONTENT_EMAIL); Get get=new Get(Bytes.toBytes(uid)); get.setMaxVersions(5); List<byte[]> rowkeys=new ArrayList<byte[]>(); Result result=rceTBL.get(get); for(Cell cell:result.rawCells()){ //CellUtil.cloneValue 获取value //CellUtil.cloneRow 获取rowkey //CellUtil.cloneQualifier 获取列名 //CellUtil.cloneFamily 获取到列族名 rowkeys.add(CellUtil.cloneValue(cell)); } //b. 根据上面获取到的微博内容的rowkey 获取微博内容 HTableInterface contentTBL =connection.getTable(CONTENT); List<Get> gets=new ArrayList<Get>(); for (byte[] rk : rowkeys) { Get g=new Get(rk); gets.add(g); } Result[] results=contentTBL.get(gets); for (Result res : results) { for(Cell cell:res.rawCells()){ Message message=new Message(); String rowkey=Bytes.toString(CellUtil.cloneRow(cell)); String userid=rowkey.substring(0, rowkey.indexOf("_")); String timestamp=rowkey.substring(rowkey.indexOf("_")+1); String content=Bytes.toString(CellUtil.cloneValue(cell)); message.setUid(userid); message.setTimestamp(timestamp); message.setContent(content); messages.add(message); } } } catch (IOException e) { e.printStackTrace(); }finally{ if(null!=connection){ try { connection.close(); } catch (IOException e) { e.printStackTrace(); } } } return messages; } public static void testInit(WeiBo wb){ wb.initNameSpace(); wb.initTable(); } public static void testPublishContent(WeiBo wb){ wb.publishContent("0001", "Tomorrow will be better!"); wb.publishContent("0001", "Tomorrow will be better!"); } public static void testAddAttends(WeiBo wb){ wb.publishContent("0008", "今天天气真不错!!!"); wb.publishContent("0009", "今天天气真不错!!!"); wb.addAttends("0001","0008","0009"); } public static void testRemoveAttends(WeiBo wb){ wb.removeAttends("0001", "0009"); } public static void testGetAttendsContents(WeiBo wb){ List<Message> messages=wb.getAttendsContens("0001"); for (Message message : messages) { System.out.println(message); } } public static void main(String[] args) { WeiBo wb=new WeiBo(); //testInit(wb); //testPublishContent(wb); testAddAttends(wb); //testRemoveAttends(wb); }
}
- 1.
- 2.
- 3.
- 4.
- 5.
- 6.
- 7.
- 8.
- 9.
- 10.
- 11.
- 12.
- 13.
- 14.
- 15.
- 16.
- 17.
- 18.
- 19.
- 20.
- 21.
- 22.
- 23.
- 24.
- 25.
- 26.
- 27.
- 28.
- 29.
- 30.
- 31.
- 32.
- 33.
- 34.
- 35.
- 36.
- 37.
- 38.
- 39.
- 40.
- 41.
- 42.
- 43.
- 44.
- 45.
- 46.
- 47.
- 48.
- 49.
- 50.
- 51.
- 52.
- 53.
- 54.
- 55.
- 56.
- 57.
- 58.
- 59.
- 60.
- 61.
- 62.
- 63.
- 64.
- 65.
- 66.
- 67.
- 68.
- 69.
- 70.
- 71.
- 72.
- 73.
- 74.
- 75.
- 76.
- 77.
- 78.
- 79.
- 80.
- 81.
- 82.
- 83.
- 84.
- 85.
- 86.
- 87.
- 88.
- 89.
- 90.
- 91.
- 92.
- 93.
- 94.
- 95.
- 96.
- 97.
- 98.
- 99.
- 100.
- 101.
- 102.
- 103.
- 104.
- 105.
- 106.
- 107.
- 108.
- 109.
- 110.
- 111.
- 112.
- 113.
- 114.
- 115.
- 116.
- 117.
- 118.
- 119.
- 120.
- 121.
- 122.
- 123.
- 124.
- 125.
- 126.
- 127.
- 128.
- 129.
- 130.
- 131.
- 132.
- 133.
- 134.
- 135.
- 136.
- 137.
- 138.
- 139.
- 140.
- 141.
- 142.
- 143.
- 144.
- 145.
- 146.
- 147.
- 148.
- 149.
- 150.
- 151.
- 152.
- 153.
- 154.
- 155.
- 156.
- 157.
- 158.
- 159.
- 160.
- 161.
- 162.
- 163.
- 164.
- 165.
- 166.
- 167.
- 168.
- 169.
- 170.
- 171.
- 172.
- 173.
- 174.
- 175.
- 176.
- 177.
- 178.
- 179.
- 180.
- 181.
- 182.
- 183.
- 184.
- 185.
- 186.
- 187.
- 188.
- 189.
- 190.
- 191.
- 192.
- 193.
- 194.
- 195.
- 196.
- 197.
- 198.
- 199.
- 200.
- 201.
- 202.
- 203.
- 204.
- 205.
- 206.
- 207.
- 208.
- 209.
- 210.
- 211.
- 212.
- 213.
- 214.
- 215.
- 216.
- 217.
- 218.
- 219.
- 220.
- 221.
- 222.
- 223.
- 224.
- 225.
- 226.
- 227.
- 228.
- 229.
- 230.
- 231.
- 232.
- 233.
- 234.
- 235.
- 236.
- 237.
- 238.
- 239.
- 240.
- 241.
- 242.
- 243.
- 244.
- 245.
- 246.
- 247.
- 248.
- 249.
- 250.
- 251.
- 252.
- 253.
- 254.
- 255.
- 256.
- 257.
- 258.
- 259.
- 260.
- 261.
- 262.
- 263.
- 264.
- 265.
- 266.
- 267.
- 268.
- 269.
- 270.
- 271.
- 272.
- 273.
- 274.
- 275.
- 276.
- 277.
- 278.
- 279.
- 280.
- 281.
- 282.
- 283.
- 284.
- 285.
- 286.
- 287.
- 288.
- 289.
- 290.
- 291.
- 292.
- 293.
- 294.
- 295.
- 296.
- 297.
- 298.
- 299.
- 300.
- 301.
- 302.
- 303.
- 304.
- 305.
- 306.
- 307.
- 308.
- 309.
- 310.
- 311.
- 312.
- 313.
- 314.
- 315.
- 316.
- 317.
- 318.
- 319.
- 320.
- 321.
- 322.
- 323.
- 324.
- 325.
- 326.
- 327.
- 328.
- 329.
- 330.
- 331.
- 332.
- 333.
- 334.
- 335.
- 336.
- 337.
- 338.
- 339.
- 340.
- 341.
- 342.
- 343.
- 344.
- 345.
- 346.
- 347.
- 348.
- 349.
- 350.
- 351.
- 352.
- 353.
- 354.
- 355.
- 356.
- 357.
- 358.
- 359.
- 360.
- 361.
- 362.
- 363.
- 364.
- 365.
- 366.
- 367.
- 368.
- 369.
- 370.
- 371.
- 372.
- 373.
- 374.
- 375.
- 376.
- 377.
- 378.
- 379.
- 380.
- 381.
- 382.
- 383.
- 384.
- 385.
- 386.
- 387.
- 388.
- 389.
- 390.
- 391.
- 392.
- 393.
- 394.
- 395.
- 396.
- 397.
- 398.
- 399.
- 400.
- 401.
- 402.
- 403.
- 404.
- 405.
- 406.
- 407.
- 408.
- 409.
- 410.
- 411.
- 412.
- 413.
- 414.
- 415.
- 416.
- 417.
- 418.
- 419.
- 420.
- 421.
- 422.
- 423.
- 424.
- 425.
- 426.
- 427.
- 428.
- 429.
- 430.
- 431.
- 432.
- 433.
- 434.
- 435.
- 436.
- 437.
- 438.
- 439.
- 440.
- 441.
- 442.
- 443.
- 444.
- 445.
- 446.
- 447.
- 448.
- 449.
- 450.
- 451.
- 452.
- 453.
- 454.
- 455.
- 456.
- 457.
- 458.
- 459.
- 460.
- 461.
- 462.
- 463.
- 464.
- 465.
- 466.
- 467.
- 468.
- 469.
- 470.
- 471.
- 472.
- 473.
- 474.
- 475.
- 476.
- 477.
- 478.
- 479.
- 480.
- 481.
- 482.
- 483.
- 484.
- 485.
- 486.
- 487.
- 488.
- 489.
- 490.
- 491.
- 492.
- 493.
- 494.
- 495.
- 496.
- 497.
- 498.
- 499.
- 500.
- 501.
- 502.
- 503.
- 504.
- 505.
- 506.
- 507.
- 508.
- 509.
- 510.
- 511.
- 512.
- 513.
- 514.
- 515.
- 516.
- 517.
- 518.
- 519.
- 520.
- 521.
- 522.
- 523.
- 524.
- 525.
- 526.
- 527.
- 528.
- 529.
- 530.
- 531.
- 532.
- 533.
- 534.
- 535.
- 536.
- 537.
- 538.
- 539.
- 540.
- 541.
- 542.
- 543.
- 544.
- 545.
- 546.
- 547.
- 548.
- 549.
- 550.
- 551.
- 552.
- 553.
- 554.
- 555.
- 556.
- 557.
- 558.
- 559.
- 560.
- 561.
原文链接:https://blog.51cto.com/u_13270164/11214513 标签:toBytes,Bytes,用户,案例,微博,rowkey,new,Hbase From: https://www.cnblogs.com/sunny3158/p/18370054