项目使用Hbase进行数据快速查询的代码案例
正文前先来一波福利推荐:
福利一:
百万年薪架构师视频,该视频可以学到很多东西,是本人花钱买的VIP课程,学习消化了一年,为了支持一下女朋友公众号也方便大家学习,共享给大家。
福利二:
毕业答辩以及工作上各种答辩,平时积累了不少精品PPT,现在共享给大家,大大小小加起来有几千套,总有适合你的一款,很多是网上是下载不到。
获取方式:
微信关注 精品3分钟 ,id为 jingpin3mins,关注后回复 百万年薪架构师 ,精品收藏PPT 获取云盘链接,谢谢大家支持!
------------------------正文开始---------------------------
之前项目中对于数据详情的查询使用的ddb技术,由于成本过高,现考虑使用开源的hbase框架,借此机会进行hbase的代码案例记录,之前已经对
hbase的原理进行介绍,介绍了hbase中的rowkey,列,列族,以及存储原理等,可以参考之前的博客,现只针对hbase的java Api进行分析。
一、连接配置,拿到 connection
/**
* 声明静态配置
*/
private Configuration conf = null;
private Connection connection = null; /**
* 构造函数
*/
public HBaseService(Configuration conf)
{
this.conf = conf;
try {
connection = ConnectionFactory.createConnection(conf);
} catch (IOException e) {
log.error("获取HBase连接失败");
}
}
@Value("${HBase.nodes}")
private String nodes; @Value("${HBase.maxsize}")
private String maxsize; @Bean
public HBaseService getHbaseService(){
org.apache.hadoop.conf.Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum",nodes );
conf.set("hbase.client.keyvalue.maxsize",maxsize);
conf.setInt(HConstants.HBASE_CLIENT_SCANNER_TIMEOUT_PERIOD, 60000);
conf.setInt("hbase.rpc.timeout", 20000);
conf.setInt("hbase.client.operation.timeout", 30000);
conf.setInt("hbase.client.scanner.timeout.period", 20000);
conf.setInt("hbase.client.pause", 50);
conf.setInt("hbase.client.retries.number", 15); return new HBaseService(conf);
}
创建表:
/**
* 创建表
* @author gxy
* @date 2018/7/3 17:50
* @since 1.0.0
* @param tableName 表名
* @param columnFamily 列族名 list表
* @return void
*/
public boolean creatTable(String tableName, List<String> columnFamily)
{
Admin admin = null;
try {
admin = connection.getAdmin(); //一个表中可以存在多个列族
List<ColumnFamilyDescriptor> familyDescriptors = new ArrayList<>(columnFamily.size()); for(String cf : columnFamily) //遍历所有列族
{
familyDescriptors.add(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf)).build()); //添加列族的描述
} TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)) //添加表的描述
.setColumnFamilies(familyDescriptors)
.build(); if (admin.tableExists(TableName.valueOf(tableName))) {
log.debug("table Exists!");
} else {
admin.createTable(tableDescriptor);
log.debug("create table Success!");
}
} catch (IOException e) {
log.error(MessageFormat.format("创建表{0}失败",tableName),e);
return false;
}finally {
close(admin,null,null);
}
return true;
} /**
* 预分区创建表
* @param tableName 表名
* @param columnFamily 列族名的集合
* @param splitKeys 预分期region
* @return 是否创建成功
*/
public boolean createTableBySplitKeys(String tableName, List<String> columnFamily, byte[][] splitKeys) {
Admin admin = null;
try {
if (StringUtils.isBlank(tableName) || columnFamily == null || columnFamily.size() == 0)
{
log.error("===Parameters tableName|columnFamily should not be null,Please check!===");
return false;
}
admin = connection.getAdmin();
if (admin.tableExists(TableName.valueOf(tableName))) {
return true;
} else {
List<ColumnFamilyDescriptor> familyDescriptors = new ArrayList<>(columnFamily.size()); for(String cf : columnFamily)
{
familyDescriptors.add(ColumnFamilyDescriptorBuilder.newBuilder(Bytes.toBytes(cf)).build());
} TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(TableName.valueOf(tableName)).setColumnFamilies(familyDescriptors).build(); //指定splitkeys
admin.createTable(tableDescriptor, splitKeys);
log.info("===Create Table " + tableName + " Success!columnFamily:" + columnFamily.toString() + "===");
}
} catch (IOException e) {
log.error("",e);
return false;
}finally {
close(admin,null,null);
} return true;
} /**
* 自定义获取分区splitKeys
*/
public static byte[][] getSplitKeys(String[] keys){
if(keys==null){
//默认为10个分区
keys = new String[] { "1|", "2|", "3|", "4|", "5|", "6|", "7|", "8|", "9|" };
}
byte[][] splitKeys = new byte[keys.length][];
//升序排序
TreeSet<byte[]> rows = new TreeSet<byte[]>(Bytes.BYTES_COMPARATOR);
for(String key : keys){
rows.add(Bytes.toBytes(key));
} Iterator<byte[]> rowKeyIter = rows.iterator();
int i=0;
while (rowKeyIter.hasNext()) {
byte[] tempRow = rowKeyIter.next();
rowKeyIter.remove();
splitKeys[i] = tempRow;
i++;
}
return splitKeys;
}
增加、跟新数据:
/**
* 为表添加 or 更新数据
* @author gxy
* @date 2018/7/3 17:26
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @param familyName 列族名
* @param columns 列名数组
* @param values 列值得数组
*/
public void putData(String tableName,String rowKey, String familyName, String[] columns, String[] values) {
// 获取表
Table table= null;
try {
table=getTable(tableName);
putDataIntoHbase(table,rowKey,tableName,familyName,columns,values); } catch (Exception e) {
log.error(MessageFormat.format("为表添加 or 更新数据失败,tableName:{0},rowKey:{1},familyName:{2}"
,tableName,rowKey,familyName),e);
}finally {
close(null,null,table);
}
} /**
* 为表添加 or 更新数据 -- 多列
* @author gxy
* @date 2018/7/3 17:26
* @since 1.0.0
* @param table Table
* @param rowKey rowKey
* @param tableName 表名
* @param familyName 列族名
* @param columns 列名数组
* @param values 列值得数组
*/
private void putDataIntoHbase(Table table, String rowKey, String tableName, String familyName, String[] columns, String[] values) {
try {
//设置rowkey
Put put = new Put(Bytes.toBytes(rowKey)); if(columns != null && values != null && columns.length == values.length){
for(int i=0;i<columns.length;i++){
if(columns[i] != null && values[i] != null){
put.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columns[i]), Bytes.toBytes(values[i]));
}else{
throw new NullPointerException(MessageFormat.format("列名和列数据都不能为空,column:{0},value:{1}"
,columns[i],values[i]));
}
}
} table.put(put);
log.debug("putData add or update data Success,rowKey:" + rowKey);
table.close();
} catch (Exception e) {
log.error(MessageFormat.format("为表添加 or 更新数据失败,tableName:{0},rowKey:{1},familyName:{2}"
,tableName,rowKey,familyName),e);
}
} /**
* 为表的某个单元格赋值 -- 单列
* @author gxy
* @date 2018/7/4 10:20
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @param familyName 列族名
* @param column1 列名
* @param value1 列值
*/
public void setColumnValue(String tableName, String rowKey, String familyName, String column1, String value1){
Table table=null;
try {
// 获取表
table=getTable(tableName);
// 设置rowKey
Put put = new Put(Bytes.toBytes(rowKey));
put.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(column1), Bytes.toBytes(value1)); table.put(put);
log.debug("add data Success!");
}catch (IOException e) {
log.error(MessageFormat.format("为表的某个单元格赋值失败,tableName:{0},rowKey:{1},familyName:{2},column:{3}"
,tableName,rowKey,familyName,column1),e);
}finally {
close(null,null,table);
}
}
删除数据:
/**
* 删除指定的单元格
* @author gxy
* @date 2018/7/4 11:41
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @param familyName 列族名
* @param columnName 列名
* @return boolean
*/
public boolean deleteColumn(String tableName, String rowKey, String familyName, String columnName)
{
Table table=null;
Admin admin = null;
try {
admin = connection.getAdmin(); if(admin.tableExists(TableName.valueOf(tableName))) //判断表是存在的
{
//获取表
table=getTable(tableName);
Delete delete = new Delete(Bytes.toBytes(rowKey));
// 设置待删除的列
delete.addColumns(Bytes.toBytes(familyName), Bytes.toBytes(columnName)); //精确到列名 table.delete(delete);
log.debug(MessageFormat.format("familyName({0}):columnName({1})is deleted!",familyName,columnName));
} }catch (IOException e) {
log.error(MessageFormat.format("删除指定的列失败,tableName:{0},rowKey:{1},familyName:{2},column:{3}"
,tableName,rowKey,familyName,columnName),e);
return false;
}finally {
close(admin,null,table);
}
return true;
} /**
* 根据rowKey删除指定的行
* @author gxy
* @date 2018/7/4 13:26
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @return boolean
*/
public boolean deleteRow(String tableName, String rowKey) {
Table table=null;
Admin admin = null;
try {
admin = connection.getAdmin(); if(admin.tableExists(TableName.valueOf(tableName))){
// 获取表
table=getTable(tableName);
Delete delete = new Delete(Bytes.toBytes(rowKey)); //精确到rowKey table.delete(delete);
log.debug(MessageFormat.format("row({0}) is deleted!",rowKey));
}
}catch (IOException e) {
log.error(MessageFormat.format("删除指定的行失败,tableName:{0},rowKey:{1}"
,tableName,rowKey),e);
return false;
}finally {
close(admin,null,table);
}
return true;
} /**
* 根据columnFamily删除指定的列族
* @author gxy
* @date 2018/7/4 13:26
* @since 1.0.0
* @param tableName 表名
* @param columnFamily 列族
* @return boolean
*/
public boolean deleteColumnFamily(String tableName, String columnFamily) {
Admin admin = null;
try {
admin = connection.getAdmin(); if(admin.tableExists(TableName.valueOf(tableName)))
{
admin.deleteColumnFamily(TableName.valueOf(tableName), Bytes.toBytes(columnFamily)); //精确到表明中的列族名
log.debug(MessageFormat.format("familyName({0}) is deleted!",columnFamily));
}
}catch (IOException e) { log.error(MessageFormat.format("删除指定的列族失败,tableName:{0},columnFamily:{1}",tableName,columnFamily),e);
return false;
}finally {
close(admin,null,null);
}
return true;
} /**
* 删除表
* @author gxy
* @date 2018/7/3 18:02
* @since 1.0.0
* @param tableName 表名
*/
public boolean deleteTable(String tableName){
Admin admin = null;
try {
admin = connection.getAdmin(); if(admin.tableExists(TableName.valueOf(tableName)))
{
admin.disableTable(TableName.valueOf(tableName)); //首先disable掉table
admin.deleteTable(TableName.valueOf(tableName));
log.debug(tableName + "is deleted!");
}
}catch (IOException e) {
log.error(MessageFormat.format("删除指定的表失败,tableName:{0}"
,tableName),e);
return false;
}finally {
close(admin,null,null);
}
return true;
}
查询数据:
/**
* 获取table
* @param tableName 表名
* @return Table
* @throws IOException IOException
*/
private Table getTable(String tableName) throws IOException
{
return connection.getTable(TableName.valueOf(tableName));
} /**
* 查询库中所有表的表名
*/
public List<String> getAllTableNames()
{
List<String> result = new ArrayList<>(); Admin admin = null;
try {
admin = connection.getAdmin();
TableName[] tableNames = admin.listTableNames(); for(TableName tableName : tableNames)
{
result.add(tableName.getNameAsString());
}
}catch (IOException e) {
log.error("获取所有表的表名失败",e);
}finally {
close(admin,null,null);
} return result;
} /**
* 遍历查询指定表中的所有数据
* @author gxy
* @date 2018/7/3 18:21
* @since 1.0.0
* @param tableName 表名
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScanner(String tableName){
Scan scan = new Scan();
return this.queryData(tableName,scan);
} /**
* 根据startRowKey和stopRowKey遍历查询指定表中的所有数据
* @author gxy
* @date 2018/7/4 18:21
* @since 1.0.0
* @param tableName 表名
* @param startRowKey 起始rowKey
* @param stopRowKey 结束rowKey
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScanner(String tableName, String startRowKey, String stopRowKey){
Scan scan = new Scan(); if(StringUtils.isNoneBlank(startRowKey) && StringUtils.isNoneBlank(stopRowKey)){
scan.withStartRow(Bytes.toBytes(startRowKey));
scan.withStopRow(Bytes.toBytes(stopRowKey));
} return this.queryData(tableName,scan);
} /**
* 通过行前缀过滤器查询数据
* @author gxy
* @date 2018/7/4 18:21
* @since 1.0.0
* @param tableName 表名
* @param prefix 以prefix开始的行键
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScannerPrefixFilter(String tableName, String prefix){
Scan scan = new Scan(); if(StringUtils.isNoneBlank(prefix)){
Filter filter = new PrefixFilter(Bytes.toBytes(prefix));
scan.setFilter(filter);
} return this.queryData(tableName,scan);
} /**
* 通过列前缀过滤器查询数据
* @author gxy
* @date 2018/7/4 18:21
* @since 1.0.0
* @param tableName 表名
* @param prefix 以prefix开始的列名
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScannerColumnPrefixFilter(String tableName, String prefix){
Scan scan = new Scan(); if(StringUtils.isNoneBlank(prefix)){
Filter filter = new ColumnPrefixFilter(Bytes.toBytes(prefix));
scan.setFilter(filter);
} return this.queryData(tableName,scan);
} /**
* 查询行键中包含特定字符的数据
* @author gxy
* @date 2018/7/4 18:21
* @since 1.0.0
* @param tableName 表名
* @param keyword 包含指定关键词的行键
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScannerRowFilter(String tableName, String keyword){
Scan scan = new Scan(); if(StringUtils.isNoneBlank(keyword)){
Filter filter = new RowFilter(CompareOperator.GREATER_OR_EQUAL,new SubstringComparator(keyword));
scan.setFilter(filter);
} return this.queryData(tableName,scan);
} /**
* 查询列名中包含特定字符的数据
* @author gxy
* @date 2018/7/4 18:21
* @since 1.0.0
* @param tableName 表名
* @param keyword 包含指定关键词的列名
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
public Map<String,Map<String,String>> getResultScannerQualifierFilter(String tableName, String keyword){
Scan scan = new Scan(); if(StringUtils.isNoneBlank(keyword)){
Filter filter = new QualifierFilter(CompareOperator.GREATER_OR_EQUAL,new SubstringComparator(keyword));
scan.setFilter(filter);
} return this.queryData(tableName,scan);
} /**
* 通过表名以及过滤条件查询数据
* @author gxy
* @date 2018/7/4 16:13
* @since 1.0.0
* @param tableName 表名
* @param scan 过滤条件
* @return java.util.Map<java.lang.String,java.util.Map<java.lang.String,java.lang.String>>
*/
private Map<String,Map<String,String>> queryData(String tableName,Scan scan){
//<rowKey,对应的行数据>
Map<String,Map<String,String>> result = new HashMap<>(); ResultScanner rs = null;
// 获取表
Table table= null;
try {
table = getTable(tableName);
rs = table.getScanner(scan);
for (Result r : rs) {
//每一行数据
Map<String,String> columnMap = new HashMap<>();
String rowKey = null;
for (Cell cell : r.listCells()) {
if(rowKey == null){
rowKey = Bytes.toString(cell.getRowArray(),cell.getRowOffset(),cell.getRowLength());
}
columnMap.put(Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()), Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
} if(rowKey != null){
result.put(rowKey,columnMap);
}
}
}catch (IOException e) {
log.error(MessageFormat.format("遍历查询指定表中的所有数据失败,tableName:{0}"
,tableName),e);
}finally {
close(null,rs,table);
} return result;
} /**
* 根据tableName和rowKey精确查询一行的数据
* @author gxy
* @date 2018/7/3 16:07
* @since 1.0.0
* @param tableName 表名
* @param rowKey 行键
* @return java.util.Map<java.lang.String,java.lang.String> 返回一行的数据
*/
public Map<String,String> getRowData(String tableName, String rowKey){
//返回的键值对
Map<String,String> result = new HashMap<>(); Get get = new Get(Bytes.toBytes(rowKey));
// 获取表
Table table= null;
try {
table = getTable(tableName);
Result hTableResult = table.get(get); //table通过封装rowKey的Get 获得具体的行 拿到 Cell
if (hTableResult != null && !hTableResult.isEmpty()) {
for (Cell cell : hTableResult.listCells()) {
// System.out.println("family:" + Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength()));
// System.out.println("qualifier:" + Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()));
// System.out.println("value:" + Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
// System.out.println("Timestamp:" + cell.getTimestamp());
// System.out.println("-------------------------------------------");
result.put(Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength()), Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
}
}
}catch (IOException e) {
log.error(MessageFormat.format("查询一行的数据失败,tableName:{0},rowKey:{1}"
,tableName,rowKey),e);
}finally {
close(null,null,table);
} return result;
} /**
* 根据tableName、rowKey、familyName、column查询指定单元格的数据
* @author gxy
* @date 2018/7/4 10:58
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @param familyName 列族名
* @param columnName 列名
* @return java.lang.String
*/
public String getColumnValue(String tableName, String rowKey, String familyName, String columnName){
String str = null;
Get get = new Get(Bytes.toBytes(rowKey));
// 获取表
Table table= null;
try {
table = getTable(tableName);
Result result = table.get(get);
if (result != null && !result.isEmpty()) {
Cell cell = result.getColumnLatestCell(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
if(cell != null){
str = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
}
}
} catch (IOException e) {
log.error(MessageFormat.format("查询指定单元格的数据失败,tableName:{0},rowKey:{1},familyName:{2},columnName:{3}"
,tableName,rowKey,familyName,columnName),e);
}finally {
close(null,null,table);
} return str;
} /**
* 根据tableName、rowKey、familyName、column查询指定单元格多个版本的数据
* @author gxy
* @date 2018/7/4 11:16
* @since 1.0.0
* @param tableName 表名
* @param rowKey rowKey
* @param familyName 列族名
* @param columnName 列名
* @param versions 需要查询的版本数
* @return java.util.List<java.lang.String>
*/
public List<String> getColumnValuesByVersion(String tableName, String rowKey, String familyName, String columnName,int versions) {
//返回数据
List<String> result = new ArrayList<>(versions); // 获取表
Table table= null;
try {
table = getTable(tableName);
Get get = new Get(Bytes.toBytes(rowKey));
get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName));
//读取多少个版本
get.readVersions(versions);
Result hTableResult = table.get(get);
if (hTableResult != null && !hTableResult.isEmpty()) {
for (Cell cell : hTableResult.listCells()) {
result.add(Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength()));
}
}
} catch (IOException e) {
log.error(MessageFormat.format("查询指定单元格多个版本的数据失败,tableName:{0},rowKey:{1},familyName:{2},columnName:{3}"
,tableName,rowKey,familyName,columnName),e);
}finally {
close(null,null,table);
} return result;
}
关闭流:
/**
* 关闭流
*/
private void close(Admin admin, ResultScanner rs, Table table)
{
if(admin != null){
try {
admin.close(); //关闭 admin
} catch (IOException e) {
log.error("关闭Admin失败",e);
}
} if(rs != null){ //关闭 ResultScanner
rs.close();
} if(table != null){
try {
table.close(); //关闭 table
} catch (IOException e) {
log.error("关闭Table失败",e);
}
}
}
项目使用Hbase进行数据快速查询的代码案例的更多相关文章
- 《深度访谈:华为开源数据格式 CarbonData 项目,实现大数据即席查询秒级响应》
深度访谈:华为开源数据格式 CarbonData 项目,实现大数据即席查询秒级响应 Tina 阅读数:146012016 年 7 月 13 日 19:00 华为宣布开源了 CarbonData ...
- 为什么Hbase能实现快速的查询
你的快速是指什么? 是根据亿级的记录中快速查询,还是说以实时的方式查询数据. A:如果快速查询(从磁盘读数据),hbase是根据rowkey查询的,只要能快速的定位rowkey, 就能实现快速的查询 ...
- 快速查询List中指定的数据
时间:2017/5/15 作者:李国君 题目:快速查询List中指定的数据 背景:当List中保存了大量的数据时,用传统的方法去遍历指定的数据肯定会效率低下,有一个方法就是类似于数据库查询那样,根据索 ...
- 万亿级日志与行为数据存储查询技术剖析——Hbase系预聚合方案、Dremel系parquet列存储、预聚合系、Lucene系
转自:http://www.infoq.com/cn/articles/trillion-log-and-data-storage-query-techniques?utm_source=infoq& ...
- 【hbase】——HBase 写优化之 BulkLoad 实现数据快速入库
1.为何要 BulkLoad 导入?传统的 HTableOutputFormat 写 HBase 有什么问题? 我们先看下 HBase 的写流程: 通常 MapReduce 在写HBase时使用的是 ...
- HBase 写优化之 BulkLoad 实现数据快速入库
在第一次建立Hbase表的时候,我们可能需要往里面一次性导入大量的初始化数据.我们很自然地想到将数据一条条插入到Hbase中,或者通过MR方式等.但是这些方式不是慢就是在导入的过程的占用Region资 ...
- HBase高性能复杂条件查询引擎
转自:http://blog.csdn.net/bluishglc/article/details/31799255 mark 写在前面 本文2014年7月份发表于InfoQ,HBase的PMC成员T ...
- 免费报名 | 汇聚HBase&大数据最前沿 Apache HBaseConAsia2019盛会火热来袭
Apache HBase介绍 Apache HBase是基于Apache Hadoop构建的一个高可靠性.高性能.可伸缩的分布式存储系统,它提供了大数据背景下的高性能的随机读写能力,HBase是Goo ...
- 大量数据快速导出的解决方案-Kettle
1.开发背景 在web项目中,经常会需要查询数据导出excel,以前比较常见的就是用poi.使用poi的时候也有两种方式,一种就是直接将集合一次性导出为excel,还有一种是分批次追加的方式适合数据量 ...
随机推荐
- Codeforces Good Bye 2017 908F F. New Year and Rainbow Roads
题 OvO http://codeforces.com/contest/908/problem/F CF 908F 解 需要注意细节的模拟题. 如果三种颜色都存在,则记每两个相邻的G组成一个段,对每个 ...
- selenium+pyquery爬取淘宝商品信息
import re from selenium import webdriver from selenium.common.exceptions import TimeoutException fro ...
- P2502 [HAOI2006]旅行 最小生成树
思路:枚举边集,最小生成树 提交:1次 题解:枚举最长边,添加较小边. #include<cstdio> #include<iostream> #include<algo ...
- PHP mysqli_info() 函数
定义和用法 mysqli_info() 函数返回有关最近执行查询的信息. 该函数作用于下列查询类型: INSERT INTO...SELECT... INSERT INTO...VALUES (... ...
- nodejs的npm命令无反应的解决方案
这二天用npm下载模块的时候输入npm命令完全无反应,不是加载的那种状态而是下标不停地在哪里闪...之后找解决方案,说要删除npmrc文件.强调:不是nodejs安装目录npm模块下的那个npmrc文 ...
- HDU 4635 Strongly connected ——(强连通分量)
好久没写tarjan了,写起来有点手生,还好1A了- -. 题意:给定一个有向图,问最多添加多少条边,让它依然不是强连通图. 分析:不妨考虑最大时候的临界状态(即再添加一条边就是强连通图的状态),假设 ...
- Android学习——MediaProvider与Music模块
一.MediaProvider数据库介绍 1. 关系型数据库 关系模型的物理表示是一个二维表格,由行和列组成. 2. MediaProvider数据库存储位置 /data/data/com.a ...
- Java核心复习 —— ArrayList源码阅读
一.ArrayList 介绍 ArrayList是List接口可变数组的实现. 特点 非线程安全 查找和修改效率高 二.ArrayList 使用方法 remove元素 @Test public voi ...
- 微服务RESTful 接口设计规范
1.RESTful发展背景及简介 网络应用程序,分为前端和后端两个部分.当前的发展趋势,就是前端设备层出不穷(手机.平板.桌面电脑.其他专用设备......).因此,必须有一种统一的机制,方便不同的前 ...
- 从char到QChar
char类型是c/c++中内置的类型,描述了1个字节的内存信息的解析.比如: char gemfield=’g’; 那么在由gemfield标记的这块内存的大小就是1个字节,信息就是01100111, ...