首页 文章 精选 留言 我的

精选列表

搜索[快速入门],共10000篇文章
优秀的个人博客,低调大师

ZooKeeper分布式入门实战(一)-基本安装配置等

1.1 zookeeper 简介 中间件,提供协调服务 作用于分布式系统,发挥其优势,可以为大数据服务 支持 Java, 提供 Java 和 C语言的客户端 API 1.2 什么是分布式系统 很多台计算机组成一个整体,一个整体一致对外并且处理同一请求 内部的每台计算机都可以相互通信(REST/RPC) 客户端到服务端的一次请求到响应结束会经历多台计算机 1.3 分布式系统的瓶颈 1.3.1 zookeeper 的特性 一致性 数据一致性,数据按照顺序分批入库 原子性 事务要么成功要么失败,不会局部化 单一视图 客户端连接集群中的任一 zk 节点,数据都是一致的 可靠性 每次对 zk的操作状态都会保存在服务端 实时性 客户端可以读取到 zk 服务端的最新数据 21 安装 JDK 2.2 zookeeper下载、安装以及配置环境变量 2.2.1 单机 zookeeper 安装 linux etc/profile

优秀的个人博客,低调大师

Python机器学习算法入门之简单感知器学习算法

问题背景 考虑一个问题:现在我们有一些过往核发信用卡的资料,包括用户个人信息和审核结果。根据这些资料,我们希望预测能不能给下一个用户发信用卡。用户基本信息如下: 这些基本信息组成了一个向量。不同的信息有不同的权重,设权重向量。我们希望构造一个函数来给用户的信用打分,并且,如果信用分超过了某个阈值,我们就认为这个客户是可靠的,可以给他发信用卡: 能发: 不能: 通过阶跃函数,进一步将这个过程函数化: 所以,当,通过;当,拒绝;当,忽略。 其中: 整理该方程如下: 具体到二维空间 简化上面的问题,假设用户只有两个属性,就可以用二维空间的一个点来表示一个用户。如下所示,蓝圈表示通过,红叉表示拒绝。注意到直线的两边,一边大于0,一边小于0,也就是一边都是蓝圈,一边都是红叉。所以现在的目标就是,找到一条直线,可以将已知的蓝圈和红叉完美区分开。 基础知识回顾 简

优秀的个人博客,低调大师

Python机器学习算法入门之梯度下降法实现线性回归

1. 背景 文章的背景取自An Introduction to Gradient Descent and Linear Regression,本文想在该文章的基础上,完整地描述线性回归算法。部分数据和图片取自该文章。没有太多时间抠细节,所以难免有什么缺漏错误之处,望指正。 线性回归的目标很简单,就是用一条线,来拟合这些点,并且使得点集与拟合函数间的误差最小。如果这个函数曲线是一条直线,那就被称为线性回归,如果曲线是一条二次曲线,就被称为二次回归。数据来自于GradientDescentExample中的data.csv文件,共100个数据点,如下图所示: 我们的目标是用一条直线来拟合这些点。既然是二维,那么y=b+mx这个公式相信对于中国学生都很熟悉。其中b是直线在y轴的截距(y-intercept),m是直线的斜率(slope)

优秀的个人博客,低调大师

android TraceView (图形化性能测试工具)使用入门笔记

创建你TraceView 1.在开始使用TraceView你要注意: 你的设备和模拟器必须设置SD card 和 你的程序拥有对SD card 具有读写操作的权限( <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />) 2.在你的程序中使用TraceView //开始跟踪然后自动保存到"/sdcard/test.trace" Debug.startMethodTracing("test"); //... //停止跟踪 Debug.stopMethodTracing(); 使用traceView就只需要这两个方法了… 举个例子我们可以在: //onCreate方法中调用 onCreate(){Debug.startMethodTracing("test");} //............. //onPause方法中结束 onPause{Debug.stopMethodTracing();} 当然,你Debug的位置你可以随便设置,只要符合要求就行 然后,结束调试好,你会在eclipse 中的file explorer 中看到生成的文件 选择 把我们要的trace文件拿出来 这里注意,文件路径要大全,不然,无法显示… 时间片面板(Timeline panel) 分析面板(Profile panel) 以下是翻译 文档中提及一个dmtracdedump 的工具 要预装Graphviz ,而且,还要写pytho脚本才能用… 效果就是这样,有兴趣的可以参考: http://blog.csdn.net/zjujoe/article/details/6080738 本文转自 liam2199 博客,原文链接:http://blog.51cto.com/youxilua/772691 如需转载请自行联系原作者

优秀的个人博客,低调大师

【Java入门提高篇】Day13 Java中的反射机制

前一段时间一直忙,所以没什么时间写博客,拖了这么久,也该更新更新了。最近看到各种知识付费的推出,感觉是好事,也是坏事,好事是对知识沉淀的认可与推动,坏事是感觉很多人忙于把自己的知识变现,相对的在沉淀上做的实际还不够,我对此暂时还没有什么想法,总觉得,慢慢来,会更快一点,自己掌握好节奏就好。 好了,言归正传。 反射机制是Java中的一个很强大的特性,可以在运行时获取类的信息,比如说类的父类,接口,全部方法名及参数,全部常量和变量,可以说类在反射面前已经衣不遮体了(咳咳,这是正规车)。先举一个小栗子,大家随意感受一下: public void testA(){ String name = "java.lang.String"; try{ Class cl = Class.forName(name); Class supercl = cl.getSuperclass(); String modifiers = Modifier.toString(cl.getModifiers()); if (modifiers.length() > 0){ System.out.print(modifiers + " "); } System.out.print(name); if (supercl != null && supercl != Object.class){ System.out.print(" extents " + supercl.getName()); } System.out.print("{\n"); printFields(cl); System.out.println(); printConstructors(cl); System.out.println(); printMethods(cl); System.out.println("}"); }catch (ClassNotFoundException e){ e.printStackTrace(); } System.exit(0); } private static void printConstructors(Class cl){ Constructor[] constructors = cl.getDeclaredConstructors(); for (Constructor c : constructors){ String name = c.getName(); System.out.print(" "); String modifiers = Modifier.toString(c.getModifiers()); if (modifiers.length() > 0){ System.out.print(modifiers + " "); } System.out.print(name + "("); Class[] paraTypes = c.getParameterTypes(); for (int j = 0; j < paraTypes.length; j++){ if (j > 0){ System.out.print(", "); } System.out.print(paraTypes[j].getSimpleName()); } System.out.println(");"); } } private static void printMethods(Class cl){ Method[] methods = cl.getDeclaredMethods(); for (Method m : methods){ Class retType = m.getReturnType(); String name = m.getName(); System.out.print(" "); String modifiers = Modifier.toString(m.getModifiers()); if (modifiers.length() > 0){ System.out.print(modifiers + " "); } System.out.print(retType.getSimpleName() + " " + name +"("); Class[] paramTypes = m.getParameterTypes(); for(int j = 0; j < paramTypes.length; j++){ if (j > 0){ System.out.print(", "); } System.out.print(paramTypes[j].getName()); } System.out.println(");"); } } private static void printFields(Class cl){ Field[] fields = cl.getFields(); for (Field f : fields){ Class type = f.getType(); String name = f.getName(); System.out.print(" "); String modifiers = Modifier.toString(f.getModifiers()); if (modifiers.length() > 0){ System.out.print(modifiers + " "); } System.out.println(type.getSimpleName() + " " + name +";"); } } 调用testA方法输出如下: public final java.lang.String{ public static final Comparator CASE_INSENSITIVE_ORDER; public java.lang.String(byte[], int, int); public java.lang.String(byte[], Charset); public java.lang.String(byte[], String); public java.lang.String(byte[], int, int, Charset); public java.lang.String(byte[], int, int, String); java.lang.String(char[], boolean); public java.lang.String(StringBuilder); public java.lang.String(StringBuffer); public java.lang.String(byte[]); public java.lang.String(int[], int, int); public java.lang.String(); public java.lang.String(char[]); public java.lang.String(String); public java.lang.String(char[], int, int); public java.lang.String(byte[], int); public java.lang.String(byte[], int, int, int); public boolean equals(java.lang.Object); public String toString(); public int hashCode(); public int compareTo(java.lang.String); public volatile int compareTo(java.lang.Object); public int indexOf(java.lang.String, int); public int indexOf(java.lang.String); public int indexOf(int, int); public int indexOf(int); static int indexOf([C, int, int, [C, int, int, int); static int indexOf([C, int, int, java.lang.String, int); public static String valueOf(int); public static String valueOf(long); public static String valueOf(float); public static String valueOf(boolean); public static String valueOf([C); public static String valueOf([C, int, int); public static String valueOf(java.lang.Object); public static String valueOf(char); public static String valueOf(double); public char charAt(int); private static void checkBounds([B, int, int); public int codePointAt(int); public int codePointBefore(int); public int codePointCount(int, int); public int compareToIgnoreCase(java.lang.String); public String concat(java.lang.String); public boolean contains(java.lang.CharSequence); public boolean contentEquals(java.lang.CharSequence); public boolean contentEquals(java.lang.StringBuffer); public static String copyValueOf([C); public static String copyValueOf([C, int, int); public boolean endsWith(java.lang.String); public boolean equalsIgnoreCase(java.lang.String); public static transient String format(java.util.Locale, java.lang.String, [Ljava.lang.Object;); public static transient String format(java.lang.String, [Ljava.lang.Object;); public void getBytes(int, int, [B, int); public byte[] getBytes(java.nio.charset.Charset); public byte[] getBytes(java.lang.String); public byte[] getBytes(); public void getChars(int, int, [C, int); void getChars([C, int); private int indexOfSupplementary(int, int); public native String intern(); public boolean isEmpty(); public static transient String join(java.lang.CharSequence, [Ljava.lang.CharSequence;); public static String join(java.lang.CharSequence, java.lang.Iterable); public int lastIndexOf(int); public int lastIndexOf(java.lang.String); static int lastIndexOf([C, int, int, java.lang.String, int); public int lastIndexOf(java.lang.String, int); public int lastIndexOf(int, int); static int lastIndexOf([C, int, int, [C, int, int, int); private int lastIndexOfSupplementary(int, int); public int length(); public boolean matches(java.lang.String); private boolean nonSyncContentEquals(java.lang.AbstractStringBuilder); public int offsetByCodePoints(int, int); public boolean regionMatches(int, java.lang.String, int, int); public boolean regionMatches(boolean, int, java.lang.String, int, int); public String replace(char, char); public String replace(java.lang.CharSequence, java.lang.CharSequence); public String replaceAll(java.lang.String, java.lang.String); public String replaceFirst(java.lang.String, java.lang.String); public String[] split(java.lang.String); public String[] split(java.lang.String, int); public boolean startsWith(java.lang.String, int); public boolean startsWith(java.lang.String); public CharSequence subSequence(int, int); public String substring(int); public String substring(int, int); public char[] toCharArray(); public String toLowerCase(java.util.Locale); public String toLowerCase(); public String toUpperCase(); public String toUpperCase(java.util.Locale); public String trim(); } 这里把String类型的所有方法和变量都获取到了,使用的仅仅是String类型的全名。当然,反射的功能不仅仅是获取类的信息,还可以在运行时动态创建对象,回想一下,我们正常的对象使用,都是需要在代码中先声明,然后才能使用它,但是使用反射后,就能在运行期间动态创建对象并调用其中的方法,甚至还能直接查看类的私有成员变量,还能获取类的注解信息,在泛型中类型判断时也经常会用到。反射可以说完全打破了类的封装性,把类的信息全部暴露了出来。 上面的代码看不太明白也没关系,只要稍微感受一下反射的能力就好了。介绍完了反射能做的事情,本篇教程就不再写一些玩具代码了,这次以一个实用型的代码为媒介来介绍反射。 在开发中,经常会遇到两个不同类对象之间的复制,把一个类中的字段信息get取出来,然后set到另一个类中,大部分情况下,两个类对应的字段是一样,每次这样使用是很麻烦的,那么利用反射就可以实现一个封装,只需要调用一个方法即可实现简单的类字段复制。 那么,先来想想,要复制一个类对象的所有字段信息到另一个类对象中,首先,怎么获取一个类的某个字段的值呢?我们先来编写一个方法: /** * 获取对象的指定字段的值 * @param obj 目标对象 * @param fieldName 目标字段 * @return 返回字段值 * @throws Exception 可能抛出异常 */ private static Object getFieldValue(Object obj, String fieldName) throws Exception{ //获取类型信息 Class clazz = obj.getClass(); //取对应的字段信息 Field field = clazz.getDeclaredField(fieldName); //设置可访问权限 field.setAccessible(true); //取字段值 Object value = field.get(obj); return value; } 这里使用了两个之前没有说过的类,一个是Class,是不是很眼熟,想一想,我们每次定义一个类的时候是不是都要用到它,哈哈,那你就想错了,那是class关键词,java是大小写的敏感的,这里的Class是一个类名,那这个类是干嘛用的呢? 虚拟机在加载每一个类的时候,会自动生成一个对应的Class类来保存该类的信息,可以理解为Class类是那个类的代理类,是连接实际类与类加载器的桥梁,可以通过它来获取虚拟机的类加载器引用,从而实现更多的骚操作。Class类是一个泛型类,每个类都有对应的一个Class类,比如String对应的Class类就是Class<String>。 Class有很多方法来获取更多关于类的信息,这里使用getDeclaredField方法来获取指定字段信息,返回的是Field类型对象,这个对象里存储着关于字段的一些信息,如字段名称,字段类型,字段修饰符,字段可访问性等,setAccessible方法可以设置字段的可访问性质,这样就能直接访问private修饰的字段了,然后使用get方法来获取指定对象的对应字段的值。 我们来测试一下: public void testB(){ try{ Employee employee = new Employee(); employee.setName("Frank"); employee.setSalary(6666.66); System.out.println((String)getFieldValue(employee,"name")); System.out.println((double)getFieldValue(employee,"salary")); }catch (Exception e){ e.printStackTrace(); } } 输出如下: Frank 6666.66 接下来,我们需要获取类中所有字段,然后在另一个类中查找是否有对应字段,如果有的话就设置字段的值到相应的字段中。 /** * 复制一个类对象属性到另一个类对象中 * @param objA 需要复制的对象 * @param objB 复制到的目标对象类型 * @return 返回复制后的目标对象 */ private static void parseObj(Object objA,Object objB) throws Exception{ if (objA == null){ return; } //获取objA的类信息 Class classA = objA.getClass(); Class classB = objB.getClass(); try { //获取objA的所有字段 Field[] fieldsA = classA.getDeclaredFields(); //获取objB的所有字段 Field[] fieldsB = classB.getDeclaredFields(); if (fieldsA == null || fieldsA.length <= 0 || fieldsB == null || fieldsB.length <= 0){ return; } //生成查询map Map<String,Field> fieldMap = new HashMap<>(); for (Field field:fieldsA){ fieldMap.put(field.getName(),field); } //开始复制字段信息 for (Field fieldB : fieldsB){ //查找是否在objB的字段中存在该字段 Field fielaA = fieldMap.get(fieldB.getName()); if (fielaA != null){ fieldB.setAccessible(true); fieldB.set(objB,getFieldValue(objA,fielaA.getName())); } } } catch (IllegalStateException e) { throw new IllegalStateException("instace fail: " ,e); } } 这里获取到classA和classB的所有字段之后,先生成了一个map用于查找,可以减少遍历次数,然后之后只需要遍历一次就可以判断相应字段是否存在,如果存在则取出对应值设置到相应的字段里去。 接下来测试一下: public void testB(){ try{ //生成Employee对象 Employee employee = new Employee("Frank",6666.66); //生成一个Manager对象 Manager manager = new Manager(); //复制对象 parseObj(employee,manager); System.out.println(manager.getName()); System.out.println(manager.getSalary()); }catch (Exception e){ e.printStackTrace(); } } public class Employee { private String name; private Double salary; public Employee(String name, Double salary) { this.name = name; this.salary = salary; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } } public class Manager { private String name; private Double salary; private Double bonus; public String getName() { return name; } public void setName(String name) { this.name = name; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } public Double getBonus() { return bonus; } public void setBonus(Double bonus) { this.bonus = bonus; } } 输出如下: Frank 6666.66 完美,这样我们就利用了反射机制完美的把相同的字段在不同类的对象之间进行了复制,这里仅仅是两个字段,所以可能好处不明显,但事实上,实际开发中,经常会有将BO转换为VO的操作,这时候,这个操作就很有必要了,简单的一行命令就可以代替一大堆的get和set操作。 当然,使用反射机制固然高端大气上档次,但是也是一把双刃剑,使用不当很可能会带来严重后果,而且使用反射的话,会占用更多资源,运行效率也会降低,上述工具类是用运行效率换开发效率。开发中不建议大量使用,还是那句话,技术只是手段,需要使用的时候再使用,不要为了使用而使用。 至于反射中的其他方法和姿势,大家尽可以慢慢去摸索,这里仅仅是抛砖引玉。 至此,本篇讲解完毕,欢迎大家继续关注。 真正重要的东西,用眼睛是看不见的。

优秀的个人博客,低调大师

【Java入门提高篇】Day12 Java代理——Cglib动态代理

今天来介绍另一种更为强大的代理——Cglib动态代理。 什么是Cglib动态代理? 我们先回顾一下上一篇的jdk动态代理,jdk动态代理是通过接口来在运行时动态创建委托类的代理对象,但是跟静态代理一样有一个缺点,就是必须和委托类实现相同的接口,当接口数量增加时,便需要增加代理类的数量才能满足需求,而且如果委托类是别人写的,而且没有实现任何接口,那么jdk动态代理就有些力不从心了。 这时候Cglib动态代理就脱颖而出了,Cglib并不依赖接口,可以直接生成委托类的代理对象,而且可以代理委托类的任意非final修饰的public和protected方法,我们可以先来看一个栗子。 先定义一个Programmer类: public class Programmer { private String name; public void setName(String name) { System.out.println("Setting Name."); this.name = name; }public void code(){ System.out.println(name + " is writing bugs."); } } 然后定义一个代理类: public class ProgrammerProxy implements MethodInterceptor { /** * 内部持有委托类对象的引用 */ private Object target; /** * 创建代理类对象 */ public Programmer createProxy(Programmer object){ target = object; //创建Enhancer对象 Enhancer enhancer = new Enhancer(); //设置要代理的目标类,以扩展功能 enhancer.setSuperclass(this.target.getClass()); //设置单一回调对象,在回调中拦截对目标方法的调用 enhancer.setCallback(this); //设置类加载器 enhancer.setClassLoader(object.getClass().getClassLoader()); //创建代理对象 return (Programmer)enhancer.create(); } /** * 回调方法:在代理实例上拦截并处理目标方法的调用,返回结果 * @param proxy 代理类 * @param method 被代理的方法 * @param params 该方法的参数数组 * @param methodProxy */ @Override public Object intercept(Object proxy, Method method, Object[] params, MethodProxy methodProxy) throws Throwable { //调用之前处理 doBefore(); //调用原方法 method.invoke(target,params); //调用之后处理 doAfter(); return null; } private void doAfter() { System.out.println("do after."); } private void doBefore() { System.out.println("do before."); } } 然后测试一下: public class ProxyTest { @Test public void testCglibProxy(){ //创建一个Programmer对象 Programmer programmerA = new Programmer(); programmerA.setName("Frank"); //创建代理对象 Programmer programmerProxyA = new ProgrammerProxy().createProxy(programmerA); programmerProxyA.code(); //修改代理对象 programmerProxyA.setName("Wang"); programmerProxyA.code(); //修改委托类对象 programmerA.setName("Song"); programmerProxyA.code(); } } 输出如下: Setting Name. do before. Frank is writing bugs. do after. do before. Setting Name. do after. do before. Wang is writing bugs. do after. Setting Name. do before. Song is writing bugs. do after. Cglib实现动态代理的步骤也不是很麻烦,先创建一个类实现MethodInterceptor接口,重写intercept方法,在intercep中可以截获委托类的所有非final修饰的public和protected方法,上例中,method.invoke(target,params);即为调用原对象的原方法,在代理类中保存了委托类对象的引用,这一点跟JDK动态代理是一样的。在调用原方法前先调用了doBefore方法,调用之后还调用了doAfter方法,从而实现了代理功能。至于createProxy方法,也只是一个固定步骤,先创建Enhance对象,然后将委托类的一些属性往里塞,然后调用create方法来动态生成代理对象。 在测试类中,为了更明显的说明代理类与委托类的关系,分别用代理类对象programmerProxyA和委托类对象programmerA对name字段进行修改,可以产生一样的效果。 下面来对比一下Cglib动态代理与JDK动态代理: 1.两者都是动态代理,都是运行时动态生成代理对象。 2.JDK动态代理利用的是接口信息来实现的代理,委托类必须实现某个或者某些接口,而Cglib则是利用继承关系,利用asm在运行时动态生成委托类的子类,从而实现对委托类的代理。因此不依赖接口。 3.Cglib由于是利用继承关系来实现代理的,因此无法代理被final修饰的类以及被final修饰的方法。 4.Cglib一般来说效率要比JDK动态代理效率更高,可以实现的代理也更为强大。 当然,具体情况具体分析,虽然Cglib比Jdk动态代理更强大,但并不一定各个地方都强行使用,有时候JDK动态代理相对来说更加简单粗暴。 至此,本篇完结,代理相关内容讲解完毕,欢迎大家继续关注。 jar包下载地址:http://download.csdn.net/download/qiuyingjia/10181844真正重要的东西,用眼睛是看不见的。

优秀的个人博客,低调大师

Android GIS开发系列-- 入门季(13)Gdal简单写个shp文件

Gdal是用来读写栅格与矢量数据的,在Gdal官网,可以下载相关的资源进行平台的编译。其实Arcgis底层也是用Gdal来读取shp文件的,那在Android中可以直接读写shp文件吗,是可以的。这里已经有人编译了Android端的so ,下载地址。也可以自己尝试编译相关so。 新建项目,将下载的so 与相关资源导入,相关目录结构如下: 注意gdal的相关包名不要修改,避免so读取不到相应的类。 简单写个shp,注意导包,要导入org.gdal下面相关的类: private void writeShp() throws UnsupportedEncodingException { //存放路径 String shpPath = basePath + "/my_line.shp"; ogr.RegisterAll(); gdal.SetConfigOption("GDAL_FILENAME_IS_UTF8", "NO"); // 不支持中文 gdal.SetConfigOption("SHAPE_ENCODING", ""); String strDriverName = "ESRI Shapefile"; org.gdal.ogr.Driver oDriver = ogr.GetDriverByName(strDriverName); if (oDriver == null) { System.out.println(" 驱动不可用!\n"); return; } // 创建数据源 DataSource oDS = oDriver.CreateDataSource(shpPath, null); if (oDS == null) { return; } // 创建一个84坐标系的图层 org.gdal.osr.SpatialReference sap = new org.gdal.osr.SpatialReference(); sap.SetWellKnownGeogCS("WGS84"); Layer oLayer = oDS .CreateLayer("TestPolygon", sap, ogr.wkbPolygon, null); if (oLayer == null) { System.out.println("图层创建失败!\n"); return; } // 下面创建属性表 // 先创建一个叫FieldID的整型属性 FieldDefn oFieldID = new FieldDefn("ID", ogr.OFTInteger); oLayer.CreateField(oFieldID, 1); // 再创建一个叫FeatureName的字符型属性,字符长度为50 FieldDefn oFieldName = new FieldDefn("name", ogr.OFTString); oFieldName.SetWidth(100); oLayer.CreateField(oFieldName, 1); FeatureDefn oDefn = oLayer.GetLayerDefn(); // 创建要素 Feature oFeatureTriangle = new Feature(oDefn); oFeatureTriangle.SetField(0, 0); oFeatureTriangle.SetField(1, "test"); Geometry geomTriangle = Geometry .CreateFromWkt("POLYGON ((112 45,112 30,140 30))"); oFeatureTriangle.SetGeometry(geomTriangle); oLayer.CreateFeature(oFeatureTriangle); //同步到文件中,一定要写 oLayer.SyncToDisk(); } 用Arcgis MapView加载shp文件效果: Gdal Java相关Api 没有整理与归纳的知识,一文不值!高度概括与梳理的知识,才是自己真正的知识与技能。 永远不要让自己的自由、好奇、充满创造力的想法被现实的框架所束缚,让创造力自由成长吧! 多花时间,关心他(她)人,正如别人所关心你的。理想的腾飞与实现,没有别人的支持与帮助,是万万不能的。 本文转自wenglabs博客园博客,原文链接http://www.cnblogs.com/arxive/p/7751997.html :,如需转载请自行联系原作者

优秀的个人博客,低调大师

Hadoop入门进阶课程10--HBase介绍、安装与应用案例

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,博主为石山园,博客地址为http://www.cnblogs.com/shishanyuan。该系列课程是应邀实验楼整理编写的,这里需要赞一下实验楼提供了学习的新方式,可以边看博客边上机实验,课程地址为https://www.shiyanlou.com/courses/237 【注】该系列所使用到安装包、测试数据和代码均可在百度网盘下载,具体地址为http://pan.baidu.com/s/10PnDs,下载该PDF文件 1、搭建环境 部署节点操作系统为CentOS,防火墙和SElinux禁用,创建了一个shiyanlou用户并在系统根目录下创建/app目录,用于存放Hadoop等组件运行包。因为该目录用于安装hadoop等组件程序,用户对shiyanlou必须赋予rwx权限(一般做法是root用户在根目录下创建/app目录,并修改该目录拥有者为shiyanlou(chown–R shiyanlou:shiyanlou /app)。 Hadoop搭建环境: l虚拟机操作系统:CentOS6.664位,单核,1G内存 lJDK:1.7.0_55 64位 lHadoop:1.1.2 2、HBase介绍 HBase–Hadoop Database,是一个高可靠性、高性能、面向列、可伸缩的分布式存储系统,利用HBase技术可在廉价PC Server上搭建起大规模结构化存储集群。 HBase是Google Bigtable的开源实现,类似Google Bigtable利用GFS作为其文件存储系统,HBase利用Hadoop HDFS作为其文件存储系统;Google运行MapReduce来处理Bigtable中的海量数据,HBase同样利用Hadoop MapReduce来处理HBase中的海量数据;Google Bigtable利用Chubby作为协同服务,HBase利用Zookeeper作为对应。 上图描述了Hadoop EcoSystem中的各层系统,其中HBase位于结构化存储层,Hadoop HDFS为HBase提供了高可靠性的底层存储支持,Hadoop MapReduce为HBase提供了高性能的计算能力,Zookeeper为HBase提供了稳定服务和failover机制。 此外,Pig和Hive还为HBase提供了高层语言支持,使得在HBase上进行数据统计处理变的非常简单。Sqoop则为HBase提供了方便的RDBMS数据导入功能,使得传统数据库数据向HBase中迁移变的非常方便。 2.1HBase访问接口 1.Native Java API,最常规和高效的访问方式,适合Hadoop MapReduce Job并行批处理HBase表数据 2.HBase Shell,HBase的命令行工具,最简单的接口,适合HBase管理使用 3.Thrift Gateway,利用Thrift序列化技术,支持C++,PHP,Python等多种语言,适合其他异构系统在线访问HBase表数据 4.REST Gateway,支持REST风格的Http API访问HBase,解除了语言限制 5.Pig,可以使用Pig Latin流式编程语言来操作HBase中的数据,和Hive类似,本质最终也是编译成MapReduce Job来处理HBase表数据,适合做数据统计 6.Hive,当前Hive的Release版本尚没有加入对HBase的支持,但在下一个版本Hive 0.7.0中将会支持HBase,可以使用类似SQL语言来访问HBase 2.2HBase数据模型 2.2.1Table & Column Family lRow Key:行键,Table的主键,Table中的记录按照Row Key排序 lTimestamp:时间戳,每次数据操作对应的时间戳,可以看作是数据的version number lColumn Family:列簇,Table在水平方向有一个或者多个Column Family组成,一个Column Family中可以由任意多个Column组成,即Column Family支持动态扩展,无需预先定义Column的数量以及类型,所有Column均以二进制格式存储,用户需要自行进行类型转换。 2.2.2Table & Region 当Table随着记录数不断增加而变大后,会逐渐分裂成多份splits,成为regions,一个region由[startkey,endkey)表示,不同的region会被Master分配给相应的RegionServer进行管理: -ROOT- && .META. Table HBase中有两张特殊的Table,-ROOT-和.META. l.META.:记录了用户表的Region信息,.META.可以有多个regoin l-ROOT-:记录了.META.表的Region信息,-ROOT-只有一个region lZookeeper中记录了-ROOT-表的location Client访问用户数据之前需要首先访问zookeeper,然后访问-ROOT-表,接着访问.META.表,最后才能找到用户数据的位置去访问,中间需要多次网络操作,不过client端会做cache缓存。 2.2.3MapReduce on HBase 在HBase系统上运行批处理运算,最方便和实用的模型依然是MapReduce,如下图: HBase Table和Region的关系,比较类似HDFS File和Block的关系,HBase提供了配套的TableInputFormat和TableOutputFormat API,可以方便的将HBase Table作为Hadoop MapReduce的Source和Sink,对于MapReduce Job应用开发人员来说,基本不需要关注HBase系统自身的细节。 2.3HBase系统架构 2.3.1Client HBase Client使用HBase的RPC机制与HMaster和HRegionServer进行通信,对于管理类操作,Client与HMaster进行RPC;对于数据读写类操作,Client与HRegionServer进行RPC 2.3.2Zookeeper Zookeeper Quorum中除了存储了-ROOT-表的地址和HMaster的地址,HRegionServer也会把自己以Ephemeral方式注册到Zookeeper中,使得HMaster可以随时感知到各个HRegionServer的健康状态。此外,Zookeeper也避免了HMaster的 单点问题,见下文描述 2.3.3HMaster HMaster没有单点问题,HBase中可以启动多个HMaster,通过Zookeeper的Master Election机制保证总有一个Master运行,HMaster在功能上主要负责Table和Region的管理工作: 1.管理用户对Table的增、删、改、查操作 2.管理HRegionServer的负载均衡,调整Region分布 3.在Region Split后,负责新Region的分配 4.在HRegionServer停机后,负责失效HRegionServer上的Regions迁移 2.3.4HRegionServer HRegionServer主要负责响应用户I/O请求,向HDFS文件系统中读写数据,是HBase中最核心的模块。 HRegionServer内部管理了一系列HRegion对象,每个HRegion对应了Table中的一个Region,HRegion中由多个HStore组成。每个HStore对应了Table中的一个Column Family的存储,可以看出每个Column Family其实就是一个集中的存储单元,因此最好将具备共同IO特性的column放在一个Column Family中,这样最高效。 HStore存储是HBase存储的核心了,其中由两部分组成,一部分是MemStore,一部分是StoreFiles。MemStore是Sorted Memory Buffer,用户写入的数据首先会放入MemStore,当MemStore满了以后会Flush成一个StoreFile(底层实现是HFile), 当StoreFile文件数量增长到一定阈值,会触发Compact合并操作,将多个StoreFiles合并成一个StoreFile,合并过程中会进 行版本合并和数据删除,因此可以看出HBase其实只有增加数据,所有的更新和删除操作都是在后续的compact过程中进行的,这使得用户的写操作只要 进入内存中就可以立即返回,保证了HBase I/O的高性能。当StoreFiles Compact后,会逐步形成越来越大的StoreFile,当单个StoreFile大小超过一定阈值后,会触发Split操作,同时把当前Region Split成2个Region,父Region会下线,新Split出的2个孩子Region会被HMaster分配到相应的HRegionServer上,使得原先1个Region的压力得以分流到2个Region上。下图描述了Compaction和Split的过程: 在理解了上述HStore的基本原理后,还必须了解一下HLog的功能,因为上述的HStore在系统正常工作的前提下是没有问 题的,但是在分布式系统环境中,无法避免系统出错或者宕机,因此一旦HRegionServer意外退出,MemStore中的内存数据将会丢失,这就需要引入HLog了。每个HRegionServer中都有一个HLog对象,HLog是一个实现Write Ahead Log的类,在每次用户操作写入MemStore的同时,也会写一份数据到HLog文件中(HLog文件格式见后续),HLog文件定期会滚动出新的,并 删除旧的文件(已持久化到StoreFile中的数据)。当HRegionServer意外终止后,HMaster会通过Zookeeper感知 到,HMaster首先会处理遗留的HLog文件,将其中不同Region的Log数据进行拆分,分别放到相应region的目录下,然后再将失效的region重新分配,领取 到这些region的HRegionServer在Load Region的过程中,会发现有历史HLog需要处理,因此会Replay HLog中的数据到MemStore中,然后flush到StoreFiles,完成数据恢复。 2.4HBase存储格式 HBase中的所有数据文件都存储在Hadoop HDFS文件系统上,主要包括上述提出的两种文件类型: 1.HFile,HBase中KeyValue数据的存储格式,HFile是Hadoop的二进制格式文件,实际上StoreFile就是对HFile做了轻量级包装,即StoreFile底层就是HFile 2.HLog File,HBase中WAL(Write Ahead Log) 的存储格式,物理上是Hadoop的Sequence File 2.4.1HFile 下图是HFile的存储格式: 首先HFile文件是不定长的,长度固定的只有其中的两块:Trailer和FileInfo。正如图中所示的,Trailer中有指针指向其他数据块的起始点。File Info中记录了文件的一些Meta信息,例如:AVG_KEY_LEN, AVG_VALUE_LEN, LAST_KEY, COMPARATOR, MAX_SEQ_ID_KEY等。Data Index和Meta Index块记录了每个Data块和Meta块的起始点。 Data Block是HBase I/O的基本单元,为了提高效率,HRegionServer中有基于LRU的Block Cache机制。每个Data块的大小可以在创建一个Table的时候通过参数指定,大号的Block有利于顺序Scan,小号Block利于随机查询。 每个Data块除了开头的Magic以外就是一个个KeyValue对拼接而成, Magic内容就是一些随机数字,目的是防止数据损坏。后面会详细介绍每个KeyValue对的内部构造。 HFile里面的每个KeyValue对就是一个简单的byte数组。但是这个byte数组里面包含了很多项,并且有固定的结构。我们来看看里面的具体结构: 开始是两个固定长度的数值,分别表示Key的长度和Value的长度。紧接着是Key,开始是固定长度的数值,表示RowKey的长度,紧接着是RowKey,然后是固定长度的数值,表示Family的长度,然后是Family,接着是Qualifier,然后是两个固定长度的数 值,表示Time Stamp和Key Type(Put/Delete)。Value部分没有这么复杂的结构,就是纯粹的二进制数据了。 2.4.2HLogFile 上图中示意了HLog文件的结构,其实HLog文件就是一个普通的Hadoop Sequence File,Sequence File的Key是HLogKey对象,HLogKey中记录了写入数据的归属信息,除了table和region名字外,同时还包括sequence number和timestamp,timestamp是“写入时间”,sequence number的起始值为0,或者是最近一次存入文件系统中sequence number。 HLog Sequece File的Value是HBase的KeyValue对象,即对应HFile中的KeyValue,可参见上文描述。 3、安装部署HBase 3.1安装过程 3.1.1下载HBase安装包 从Apache网站上(hbase.apache.org)下载HBase稳定发布包: http://mirrors.cnnic.cn/apache/hbase/hbase-0.96.2/ 也可以在/home/shiyanlou/install-pack目录中找到该安装包,解压该安装包并把该安装包复制到/app目录中 cd /home/shiyanlou/install-pack tar -zxf hbase-0.96.2-hadoop1-bin.tar.gz mv hbase-0.96.2-hadoop1 /app/hbase-0.96.2 3.1.2设置环境变量 1.使用sudo vi /etc/profile命令修改系统环境变量 export HBASE_HOME=/app/hbase-0.96.2 export PATH=$PATH:$HBASE_HOME/bin 2.使环境变量生效并验证环境变量生效 source /etc/profile hbase version 3.1.3编辑hbase-env.sh 1.打开hbase-env.sh文件 cd /app/hbase-0.96.2/conf sudo vi hbase-env.sh 2.修改该文件配置 #Java环境 export JAVA_HOME=/app/lib/jdk1.7.0_55 #通过hadoop的配置文件找到hadoop集群 export HBASE_CLASSPATH=/app/hadoop-1.1.2/conf #使用HBASE自带的zookeeper管理集群 export HBASE_MANAGES_ZK=true 3.1.4编辑hbase-site.xml 1.打开hbase-site.xml配置文件 cd /app/hbase-0.96.2/conf sudo vi hbase-site.xml 2.配置hbase-site.xml文件 <configuration> <property> <name>hbase.rootdir</name> <value>hdfs://hadoop:9000/hbase</value> </property> <property> <name>hbase.cluster.distributed</name> <value>true</value> </property> <property> <name>hbase.zookeeper.quorum</name> <value>b393a04554e1</value> </property> </configuration> 3.2启动并验证 3.2.1启动HBase 通过如下命令启动Hbase cd /app/hbase-0.96.2/bin ./start-hbase.sh 3.2.2验证启动 1.在hadoop节点使用jps查看节点状态 2.进入hbase的shell命令行,创建表member并进行查看 hbase shell hbase>create 'member', 'm_id', 'address', 'info' 4、测试例子 4.1测试说明 这里我们用一个学生成绩表作为例子,对HBase的基本操作和基本概念进行讲解: 下面是学生的成绩表: namegradcourse:mathcourse:art Tom18797 Jerry210080 这里grad对于表来说是一个列,course对于表来说是一个列族,这个列族由两个列组成:math和art,当然我们可以根据我们的需要在course中建立更多的列族,如computer,physics等相应的列添加入course列族. 4.2Shell操作 4.2.1建立一个表格scores具有两个列族grad和courese hbase(main):002:0> create 'scores', 'grade', 'course' 4.2.2查看当先HBase中具有哪些表 hbase(main):003:0> list 4.2.3查看表的构造 hbase(main):004:0> describe 'scores' 4.2.4插入数据 给表中Tom列族插入数据 hbase(main):005:0> put 'scores', 'Tom', 'grade:', '1' hbase(main):006:0> put 'scores', 'Tom', 'course:math', '87' hbase(main):007:0> put 'scores', 'Tom', 'course:art', '97' 给表中Jerry列族插入数据 hbase(main):008:0> put 'scores', 'Jerry', 'grade:', '2' hbase(main):009:0> put 'scores', 'Jerry', 'course:math', '100' hbase(main):010:0> put 'scores', 'Jerry', 'course:art', '80' 4.2.5查看scores表中Tom的相关数据 hbase(main):011:0> get 'scores', 'Tom' 4.2.6查看scores表中所有数据 hbase(main):012:0> scan 'scores' 本文转自shishanyuan博客园博客,原文链接:http://www.cnblogs.com/shishanyuan/p/4648263.html ,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android笔记二十七.Service组件入门(一).什么是Service?

转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一、Service 1.Service简单介绍 Service为Android四大组件之中的一个。Service与Activity组件相似,都代表可执行的程序且有自己的生命周期,唯一的差别是Activity组件提供界面方便人机交互而Service仅仅在后台执行且没有交互界面。Service是android 系统中的一种组件,它们都是从Context派生出来的,可是它不能自己执行,仅仅能在后台执行。而且能够和其它组件进行交互。 它须要通过某一个Activity或者其它Context对象来调用。 须要注意的是,Service不是一个单独的进程或为了防止应用出现无反应错误单独的线程,它像其它应用对象一样执行在其托管进程的主线程中。 当然,假设我们希望自己的Service能够在后台执行MP3或者网络下载,我们能够创建一个线程来实现。 2.Service的生命周期 因为Service可由两种方式启动:Context.startService()和Context.bindService(). (1)Context.startService()方法:通过该方法启动Service,訪问者(client)与Service之间没有关联,即使訪问者退出了,Service仍然执行。 调用Context.startService()触发的Service生命周期方法: onCreate()->onStartCommand(Intent, int, int) ->Service执行-> Context.stopService()或 stopSelf()->onDestory()->Service被关闭 (2)Context.bindService()方法:通过该方法启动Service。訪问者(client)与Service绑定在一起,訪问者一旦退出,Service也就终止了。 调用Context.startService()触发的Service生命周期方法: onCreate()->OnBind(Intent)->client绑定到Service->OnUnbind()->onDestory()->Service被关闭 升华笔记1: 1.当调用Context.bindService()方法启动一个Service时。不会运行onStartCommand(Intent, int, int)方法; 2.当Activity(client的Activiy)调用BindService()绑定一个已启动的Service(Activity起初通过startService()方法启动)时,系统仅仅是把Service内部IBinder对象(由onBind()方法返回)传递给Acitvity,并不会把该Service生命周期全然"绑定"到该Activity,因而当Activity调用unBindService()方法取消与该Service的绑定时,也仅仅是切断该Activity与Service之间的关联,并不能停止该Service组件。 3.API-Service public abstract classService (1)继承关系 java.lang.Object ↳ android.content.Context ↳ android.content.ContextWrapper ↳ android.app.Service (2)构造方法 Service() 可是。一般我们在开发Service时主要是通过Content.getService()方法来获取Service类对象。 (3)经常用法(Service组件方法) >void OnCreate():当该Service第一次被创建后将马上被调用。 >public int onStartCommand(Intent intent, int flags, int startId):每次client调用startService(Intent intent)方法启动该Service时都会回调该方法。 >public abstract boolean stopService (Intent service):client调用该方法关闭Service >public final void stopSelf ():Service自己主动关闭 >public abstract IBinder onBind (Intent intent):该方法是Service子类必须实现的方法,其返回一个IBinder对象,client应用程序可通过该对象与Service组件通信。參数Intent对象用于将client绑定到Service,传递给Context.bindService。 >boolean onUnbind(Intent intent):当该Service上绑定的全部client都断开链接时将会调用该方法 >void onDestory():当该Service被关闭之前将会调用该方法。Service将会清理其占有的全部资源(包含全部线程、注冊在Service上的接受者)。 4.Service的启动方式 (1)Context.startService()启动 当client(组件)通过Context的startService()启动Service后,訪问者与Service之间没有关联,该Service将一直在后台运行。即使调用startService的进程结束了,Service仍然还存在,直到有进程调用stopService(),或者Service自己自杀(stopSelf()).在这样的情况下,Service与訪问者之间无法进行通信、数据交换。 (2)Context.bindService()启动 通过Context的bindService()绑定Service后,Servcice就和调用bindService()的组件同生共死了。 也就是说当调用bindService()的组件销毁了,那么它绑定的Service也跟着被结束。 二、开发Service基本思路(本地) 1.创建、配置Service (1)定义一个继承于Service的子类,假设希望Service组件完毕某些事情,我们仅仅要在onCreate()或onStartCommand()方法中定义相关的业务代码就可以。 一个Service组件的框架例如以下: \src\service\FirstService.java public class FirstService extends Service { /*a.必须实现的方法,返回一个IBinder对象给client以便实现通信 * 因为我们调用startService方法启动一个Servie,无需与client(组件)绑定,因此,返回为null. */ @Override public IBinder onBind(Intent arg0) { return null; } /*b.Service被创建时回调该方法*/ @Override public void onCreate() { super.onCreate(); System.out.println("Service is Created"); } /*c.Service被启动时回调该方法*/ @Override public int onStartCommand(Intent intent,int flags,int startId) { Sytem.out.println("Service is Started"); return START_STICKY; } /*d.Service被关闭之前回调*/ @Override public void onDestroy() { super.onDestroy(); System.out.println("Service is Destroyed"); } } 2.在AndroidManifest.xml文件里配置该Service 定义了上面的Service之后,接下来须要在AndroidManifest.xml文件里配置该Service。配置Service使用<service../>元素。 与配置Activity相似的是,配置Service时也可为<service../>元素配置<intent-filter../>子元素。用于说明该Service可被哪些Intent启动。 <!--配置一个Service组件--> <service android:name=".FirstService"> <intent-filter> <!--为该service组件的intent-filter配置action--> <action android:name="com.example.service.FIRST_SERVICE"/> </intent-filter> </service> Action中的值一定要与程序中创建的Intent的Action的值一致,程序就是依据Action的值来查找对应的Service从而启动它。 Service是Android四大组件中与Activity最相似的组件,它们都代表可执行的程序。 所以,开发Service类似于开发Activity,我们仅仅需定义一个继承Service的子类而且在AndroidManifest.xml文件里配置该Service后,就能在程序中执行该Serviec。 怎样启动一个Service呢?我们能够在本应用的Activity子类中通过Context.startService()方法或Context.bindService()方法启动一个service,也能够在还有一个应用的Activity子类中通过Context.startService()方法或Context.bindService()方法启动这个service. 3.启动和停止Service 当Service开发完毕后,我们能够在自身应用的Activity子类中启动该Service,也能够在其它应用中启动该Service。这里,我们在本应用中启动(关闭)该Service,使用Content.startService(Intent intent)方法。 \src\service\StartService public class StartServiceTest extends Activity { Button start,stop; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //获取程序界面button中的start、stop两个button start = (Button) findViewById(R.id.start); stop = (Button) findViewById(R.id.stop); //创建启动Service的Intent final Intent intent = new Intent(); //为Intent设置Action属性 intent.setAction("com.example.service.FIRST_SERVICE"); start.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { //启动指定Service startService(intent); } }); stop.setOnClickListener(new OnClickListener(){ @Override public void onClick(View arg0) { //关闭指定Service stopService(intent); } }); } } 通过以上3步。我们就算完毕了一个Service及使用该Service的应用程序(Service为该应用程序的组成部分)。 升华笔记3: 1.为Intent设置Action属性。主要作用是指定启动哪个Service。当中。"com.example.service.FIRST_SERVICE"在Service的AndroidManifest.xml配置文件里的<service../>元素的<intent-filter../>子元素中配置该Service的action属性。 2.该Activity通过Content.startService(Intent intent)方法启动指定的Service,每当Service被创建时会回调onCreate方法,每次Service被启动时都会回调onStart方法--多次启动一个已有的Service组件将不会再回调onCreate方法。但每次启动时都会回调onStartCommand()方法。 參考:http://wear.techbrood.com/reference/android/app/Service.html 本文转自mfrbuaa博客园博客,原文链接:http://www.cnblogs.com/mfrbuaa/p/5104681.html,如需转载请自行联系原作者

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册