hive日常积累优化技巧

一、join优化
Join查找操作的基本原则:应该将条目少的表/子查询放在 Join 操作符的左边。原因是在 Join 操作的 Reduce 阶段,位于 Join 操作符左边的表的内容会被加载进内存,将条目少的表放在左边,可以有效减少发生内存溢出错误的几率。
Join查找操作中如果存在多个join,且所有参与join的表中其参与join的key都相同,则会将所有的join合并到一个mapred程序中。
案例:
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1) 在一个mapre程序中执行join
SELECT a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key2) 在两个mapred程序中执行join
Map join的关键在于join操作中的某个表的数据量很小,案例:
SELECT /*+ MAPJOIN(b) */ a.key, a.value
FROM a join b on a.key = b.key
Mapjoin 的限制是无法执行a FULL/RIGHT OUTER JOIN b,和map join相关的hive参数:hive.join.emit.interval hive.mapjoin.size.key hive.mapjoin.cache.numrows
由于join操作是在where操作之前执行,所以当你在执行join时,where条件并不能起到减少join数据的作用;案例:
SELECT a.val, b.val FROM a LEFT OUTER JOIN b ON (a.key=b.key)
WHERE a.ds=’2009-07-07′ AND b.ds=’2009-07-07′
最好修改为:
SELECT a.val, b.val FROM a LEFT OUTER JOIN b
ON (a.key=b.key AND b.ds=’2009-07-07′ AND a.ds=’2009-07-07′)
在join操作的每一个mapred程序中,hive都会把出现在join语句中相对靠后的表的数据stream化,相对靠前的变的数据缓存在内存中。当然,也可以手动指定stream化的表:SELECT /*+ STREAMTABLE(a) */ a.val, b.val, c.val FROM a JOIN b ON (a.key = b.key1) JOIN c ON (c.key = b.key1)
二、group by 优化
Map端聚合,首先在map端进行初步聚合,最后在reduce端得出最终结果,相关参数:
· hive.map.aggr = true是否在 Map 端进行聚合,默认为 True
· hive.groupby.mapaggr.checkinterval = 100000在 Map 端进行聚合操作的条目数目
数据倾斜聚合优化,设置参数hive.groupby.skewindata = true,当选项设定为 true,生成的查询计划会有两个 MR Job。第一个 MR Job 中,Map 的输出结果集合会随机分布到 Reduce 中,每个 Reduce 做部分聚合操作,并输出结果,这样处理的结果是相同的 Group By Key 有可能被分发到不同的 Reduce 中,从而达到负载均衡的目的;第二个 MR Job 再根据预处理的数据结果按照 Group By Key 分布到 Reduce 中(这个过程可以保证相同的 Group By Key 被分布到同一个 Reduce 中),最后完成最终的聚合操作。
三、合并小文件
文件数目过多,会给 HDFS 带来压力,并且会影响处理效率,可以通过合并 Map 和 Reduce 的结果文件来消除这样的影响:
· hive.merge.mapfiles = true是否和并 Map 输出文件,默认为 True
· hive.merge.mapredfiles = false是否合并 Reduce 输出文件,默认为 False
· hive.merge.size.per.task = 256*1000*1000合并文件的大小
四、Hive实现(not) in
通过left outer join进行查询,(假设B表中包含另外的一个字段 key1
select a.key from a left outer join b on a.key=b.key where b.key1 is null
通过left semi join 实现 in
SELECT a.key, a.val FROM a LEFT SEMI JOIN b on (a.key = b.key)
Left semi join 的限制:join条件中右边的表只能出现在join条件中。
五、排序优化
Order by 实现全局排序,一个reduce实现,效率低
Sort by 实现部分有序,单个reduce输出的结果是有序的,效率高,通常和DISTRIBUTE BY关键字一起使用(DISTRIBUTE BY关键字 可以指定map 到 reduce端的分发key)
CLUSTER BY col1 等价于DISTRIBUTE BY col1 SORT BY col1
六、使用分区
Hive中的每个分区都对应hdfs上的一个目录,分区列也不是表中的一个实际的字段,而是一个或者多个伪列,在表的数据文件中实际上并不保存分区列的信息与数据。Partition关键字中排在前面的为主分区(只有一个),后面的为副分区
静态分区:静态分区在加载数据和使用时都需要在sql语句中指定
案例:(stat_date=’20120625′,province=’hunan’)
动态分区:使用动态分区需要设置hive.exec.dynamic.partition参数值为true,默认值为false,在默认情况下,hive会假设主分区时静态分区,副分区使用动态分区;如果想都使用动态分区,需要设置set hive.exec.dynamic.partition.mode=nostrick,默认为strick
案例:(stat_date=’20120625′,province)
七、Distinct 使用
Hive支持在group by时对同一列进行多次distinct操作,却不支持在同一个语句中对多个列进行distinct操作。
八、Hql使用自定义的mapred脚本
注意事项:在使用自定义的mapred脚本时,关键字MAP REDUCE 是语句SELECT TRANSFORM ( … )的语法转换,并不意味着使用MAP关键字时会强制产生一个新的map过程,使用REDUCE关键字时会产生一个red过程。
自定义的mapred脚本可以是hql语句完成更为复杂的功能,但是性能比hql语句差了一些,应该尽量避免使用,如有可能,使用UDTF函数来替换自定义的mapred脚本
九、UDTF
UDTF将单一输入行转化为多个输出行,并且在使用UDTF时,select语句中不能包含其他的列,UDTF不支持嵌套,也不支持group by 、sort by等语句。如果想避免上述限制,需要使用lateral view语法,案例:
select a.timestamp, get_json_object(a.appevents, ‘$.eventid’), get_json_object(a.appenvets, ‘$.eventname’) from log a;
select a.timestamp, b.*
from log a lateral view json_tuple(a.appevent, ‘eventid’, ‘eventname’) b as f1, f2;
其中,get_json_object为UDF函数,json_tuple为UDTF函数。
UDTF函数在某些应用场景下可以大大提高hql语句的性能,如需要多次解析json或者xml数据的应用场景。
十、聚合函数count和sum
Count和sum函数可能是在hql语句中使用的最为频繁的两个聚合函数了,但是在hive中count函数在计算distinct value时支持加入条件过滤。
转自:http://in.sdo.com/?p=809

Servlet的多线程安全问题

public class MyServlet extends HttpServlet {
		final static int i = 0;
		public void doGet(HttpServletRequest req, HttpServletResponse res) {
			private HttpSession session = req.getSession();
			private ServletContext ctx = getServletContext();
			synchronized (ctx) {
				Object obj = ctx.getAttribute();
				// code to alter obj
			}
		}
	}

上面代码中的哪些变量是线程安全的?
选择:
* A. i
* B. session
* C. ctx
* D. req
* E. obj
* F. res
IBM 给出的答案是:
正确答案:
* A、C、D 和 F
说明:
静态变量 i 是线程安全的,因为它是 final(不能被修改),否则它将不是安全的。请求和响应对象的作用域只在请求的生命周期,因此它们也是线程安全的。会话和 ServletContext 对象可以从多个线程访问,同时处理多个请求,因此它们不是线程安全的。但在本例中,同步了 ServletContext 对象,因此它只能由一个线程一次访问。obj 不是线程安全的,因为即使同步了 ServletContext 对象,它的属性也没有同步。它们需要另外进行同步。因此,选项 B 和 E 是不正确的,而选项 A、C、D 和 F 是正确的。
Servlets的多线程安全
多线程占用资源少,处理速度快,提高了效率。
一些编码建议:
对变量和方法定义适当的访问方式, 例如单纯取值操作不会有多线程安全问题;
同步化所有访问重要数据的实例变量; 多线程下,如果操作的是一个变量,且兼有读写操作,
就要考虑加上同步,但同步不能乱加,否则会造成死锁问题。
并发需要注意的
并发的环境:资源处于一个并发的环境
共享资源:多个线程共享一个临界资源
全面同步:如有n个变量访问同一个资源,这n个变量都得同步。即多个锁一把钥匙,钥匙放在一个共享区域内
sychronized(this):粗粒度的锁。是将所有的路都加锁;
sychronized(object o1):细粒度的锁。只对对象中的变量加锁。效率较前面的高,但是较难控制。
读写需要互斥。
sychronized(this):this不能是基本数据类型,必须是Object.不锁对象的引用,而是对象的内存空间。
servlet中需要同步的:成员变量、文件、静态变量、数据库连接
一,servlet容器如何同时处理多个请求。
Servlet采用多线程来处理多个请求同时访问,Servlet容器维护了一个线程池来服务请求。
线程池实际上是等待执行处理的一组线程,也叫做工作者线程(Worker Thread),
Servlet容器使用一个调度线程来管理工作者线程(Dispatcher Thread)。
当容器收到一个访问Servlet的请求,调度者线程从线程池中选出一个工作者线程,将请求传递给该线程,
然后由该线程来执行Servlet的service方法。
当这个线程正在执行的时候,容器收到另外一个请求,调度者线程将从池中选出另外一个工作者线程来服务新的请求;
容器并不关心这个请求是否访问的是同一个Servlet还是另外一个Servlet;
当容器同时收到对同一Servlet的多个请求,那这个Servlet的service方法将以多线程方式并发执行。
二,Servlet容器默认采用单实例多线程的方式来处理请求,减少产生Servlet实例的开销,提升了对请求的响应。
对于Tomcat可以在server.xml中通过元素设置线程池中线程的数目。
就实现来说:
调度者线程类所担负的责任是调度线程,只需要利用自己的属性完成自己的责任。
而其他对象又依赖于该对象所承担的责任,需要得到该特定对象,那该类就是一个单例模式的实现了。
三,如何开发线程安全的Servlet
1,变量的线程安全:这里的变量指字段和共享数据(如表单参数值)。
a,将参数变量本地化:多线程并不共享局部变量.所以我们要尽可能的在servlet中使用局部变量。
例如:String user = request.getParameter(“user”);
b,使用同步块Synchronized,防止可能异步调用的代码块。这意味着线程需要队列处理。
在使用同板块的时候要尽可能的缩小同步代码的范围,不要直接在sevice方法和响应方法上使用同步,这样会严重影响性能。
2,属性的线程安全分析:ServletContext,HttpSession,ServletRequest对象的属性
ServletContext:(线程是不安全的)
ServletContext是可以多线程同时读/写属性的,线程是不安全的。要对属性的读写进行同步处理或者进行深度Clone()。
所以在Servlet上下文中尽可能少地保存频繁改写的数据,可以采取其他方式在多个Servlet中共享,比方我们可以使用单例模式来处理共享数据。
HttpSession:(线程是不安全的)
HttpSession对象在用户会话期存在,只能处理属于同一个Session的请求的线程,因此Session对象的属性访问理论上是线程安全的。
当用户打开多个同属于一个进程的浏览器窗口,在这些窗口的访问属于同一个Session,会出现多次请求,需要多个工作线程来处理请求,可能造成同时多线程读写属性,这时我们对属性的读写进行同步处理。
ServletRequest:(线程是安全的)
对于每一个请求,由一个工作线程来执行,都会创建有一个新的ServletRequest对象,所以ServletRequest对象只能在一个线程中被访问。ServletRequest是线程安全的。
注意:ServletRequest对象在service方法的范围内是有效的,不要试图在service方法结束后仍然保存请求对象的引用。
3,使用同步的集合类:
使用Vector代替ArrayList,使用Hashtable代替HashMap。
4,不要在Servlet中创建自己的线程来完成某个功能:
Servlet本身就是多线程的,在Servlet中再创建线程,将导致执行情况复杂化,出现安全问题。
5,在多个servlet中,对外部对象(例如文件)进行修改操作一定要加锁,做到互斥的访问
四,SingleThreadModel接口
javax.servlet.SingleThreadModel接口是一个标识接口,如果一个Servlet实现了这个接口,
则Servlet容器将保证在同时刻仅有一个线程可以在该servlet实例的service方法中执行,将其他所有请求进行排队。
服务器可以使用多个实例来处理请求,代替单个实例的请求排队带来的性能问题。
服务器可创建一个Servlet类的多个实例组成的实例池,对于每个请求分配Servlet实例进行响应,之后放回到实例池中等待下此请求。此时,局部变量(字段)也是安全的,但对于全局变量和共享数据是不安全的,需要进行同步处理。
而对于这种多实例的情况,使用SingleThreadModel接口并不能解决并发访问产生的问题,
且SingleThreadModel接口在servlet规范中已经被明确声明为deprecated了。

jedis多线程异常

多线程下使用jedis会报一些奇怪的错误

[2013.09.13 11:17:19.280]redis.clients.jedis.exceptions.JedisConnectionException: Unknown reply: 2
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.process(Protocol.java:71)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Protocol.read(Protocol.java:122)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBinaryBulkReply(Connection.java:172)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Connection.getBulkReply(Connection.java:161)
[2013.09.13 11:17:19.280]	at redis.clients.jedis.Jedis.get(Jedis.java:65)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getShowSearchCurve(ProManager.java:916)
[2013.09.13 11:17:19.280]	at com.youku.index.web.util.MergeFullkpi.mergeFull(MergeFullkpi.java:59)
[2013.09.13 11:17:19.280]	at com.youku.index.web.manager.ProManager.getAllShowVV(ProManager.java:836)
[2013.09.13 11:17:19.280]	at com.youku.index.web.action.ProAction.vrShow(ProAction.java:422)
[2013.09.13 11:17:19.280]	at sun.reflect.GeneratedMethodAccessor87.invoke(Unknown Source)
[2013.09.13 11:17:19.280]	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
[2013.09.13 11:17:19.280]	at java.lang.reflect.Method.invoke(Method.java:597)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeAction(DefaultActionInvocation.java:450)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invokeActionOnly(DefaultActionInvocation.java:289)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:252)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.debugging.DebuggingInterceptor.intercept(DebuggingInterceptor.java:256)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.DefaultWorkflowInterceptor.doIntercept(DefaultWorkflowInterceptor.java:167)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.validator.ValidationInterceptor.doIntercept(ValidationInterceptor.java:265)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.validation.AnnotationValidationInterceptor.doIntercept(AnnotationValidationInterceptor.java:68)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ConversionErrorInterceptor.intercept(ConversionErrorInterceptor.java:138)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ParametersInterceptor.doIntercept(ParametersInterceptor.java:239)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.StaticParametersInterceptor.intercept(StaticParametersInterceptor.java:191)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.MultiselectInterceptor.intercept(MultiselectInterceptor.java:73)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.CheckboxInterceptor.intercept(CheckboxInterceptor.java:91)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.FileUploadInterceptor.intercept(FileUploadInterceptor.java:252)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ModelDrivenInterceptor.intercept(ModelDrivenInterceptor.java:100)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ScopedModelDrivenInterceptor.intercept(ScopedModelDrivenInterceptor.java:141)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ChainingInterceptor.intercept(ChainingInterceptor.java:145)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.PrepareInterceptor.doIntercept(PrepareInterceptor.java:171)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.MethodFilterInterceptor.intercept(MethodFilterInterceptor.java:98)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.I18nInterceptor.intercept(I18nInterceptor.java:161)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.interceptor.ServletConfigInterceptor.intercept(ServletConfigInterceptor.java:164)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.AliasInterceptor.intercept(AliasInterceptor.java:193)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.interceptor.ExceptionMappingInterceptor.intercept(ExceptionMappingInterceptor.java:189)
[2013.09.13 11:17:19.280]	at com.opensymphony.xwork2.DefaultActionInvocation.invoke(DefaultActionInvocation.java:246)
[2013.09.13 11:17:19.280]	at org.apache.struts2.impl.StrutsActionProxy.execute(StrutsActionProxy.java:54)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.Dispatcher.serviceAction(Dispatcher.java:563)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.ExecuteOperations.executeAction(ExecuteOperations.java:77)
[2013.09.13 11:17:19.280]	at org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(StrutsPrepareAndExecuteFilter.java:99)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.DispatchFilterChain.doFilter(DispatchFilterChain.java:97)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:280)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.RequestDispatcherImpl.forward(RequestDispatcherImpl.java:108)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.NormalRewrittenUrl.doRewrite(NormalRewrittenUrl.java:213)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.handleRewrite(RuleChain.java:171)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.RuleChain.doRules(RuleChain.java:145)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriter.processRequest(UrlRewriter.java:92)
[2013.09.13 11:17:19.280]	at org.tuckey.web.filters.urlrewrite.UrlRewriteFilter.doFilter(UrlRewriteFilter.java:381)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.FilterFilterChain.doFilter(FilterFilterChain.java:76)
[2013.09.13 11:17:19.280]	at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:158)
[2013.09.13 11:17:19.280]	at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:178)
[2013.09.13 11:17:19.280]	at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:241)
[2013.09.13 11:17:19.280]	at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:268)
[2013.09.13 11:17:19.280]	at com.caucho.server.port.TcpConnection.run(TcpConnection.java:586)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.runTasks(ThreadPool.java:690)
[2013.09.13 11:17:19.280]	at com.caucho.util.ThreadPool$Item.run(ThreadPool.java:612)
[2013.09.13 11:17:19.280]	at java.lang.Thread.run(Thread.java:662)

jedis并不是线程安全的,于是在程序中改为每个线程只使用一个jedis实例。
较好的解决办法是使用JedisPool,见官方文档:https://github.com/xetorthio/jedis/wiki/Getting-started
先初始化一个池,可以设置一些参数,如setMaxActive,setMaxIdle等:
查看源代码打印帮助
JedisPool pool = new JedisPool(new JedisPoolConfig(), “localhost”);
然后就可以从池中取出一个实例:

Jedis jedis = pool.getResource();
try {
  /// ... do stuff here ... for example
  jedis.set("foo", "bar");
  String foobar = jedis.get("foo");
  jedis.zadd("sose", 0, "car"); jedis.zadd("sose", 0, "bike");
  Set<String> sose = jedis.zrange("sose", 0, -1);
} finally {
  /// ... it's important to return the Jedis instance to the pool once you've finished using it
  pool.returnResource(jedis);
}
/// ... when closing your application:
pool.destroy();

用完要记得放回池,不用了需要销毁。
转自
http://www.rigongyizu.com/jedis-multithread-exception/
不过还没来得及实现,标记下……

数据库索引

索引是对数据库表中一列或多列的值进行排序的一种结构,使用索引可快速访问数据库表中的特定信息。
数据库索引好比是一本书前面的目录,能加快数据库的查询速度。
索引是对数据库表中一个或多个列(例如,employee 表的姓氏 (lname) 列)的值进行排序的结构。如果想按特定职员的姓来查找他或她,则与在表中搜索所有的行相比,索引有助于更快地获取信息。
例如这样一个查询:select * from table1 where id=10000。如果没有索引,必须遍历整个表,直到ID等于10000的这一行被找到为止;有了索引之后(必须是在ID这一列上建立的索引),在索引中查找,但索引是经过某种算法优化过的,查找次数要少的多的多。可见,索引是用来定位的。
索引分为聚簇索引和非聚簇索引两种,聚簇索引 是按照数据存放的物理位置为顺序的,而非聚簇索引就不一样了;聚簇索引能提高多行检索的速度,而非聚簇索引对于单行的检索很快。
建立索引的目的是加快对表中记录的查找或排序。
为表设置索引要付出代价的:一是增加了数据库的存储空间,二是在插入和修改数据时要花费较多的时间(因为索引也要随之变动)。
创建索引可以大大提高系统的性能。第一,通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。第二,可以大大加快数据的检索速度,这也是创建索引的最主要的原因。第三,可以加速表和表之间的连接,特别是在实现数据的参考完整性方面特别有意义。第四,在使用分组和排序子句进行数据检索时,同样可以显著减少查询中分组和排序的时间。第五,通过使用索引,可以在查询的过程中,使用优化隐藏器,提高系统的性能。
也许会有人要问:增加索引有如此多的优点,为什么不对表中的每一个列创建一个索引呢?因为,增加索引也有许多不利的方面。第一,创建索引和维护索引要耗费时间,这种时间随着数据量的增加而增加。第二,索引需要占物理空间,除了数据表占数据空间之外,每一个索引还要占一定的物理空间,如果要建立聚簇索引,那么需要的空间就会更大。第三,当对表中的数据进行增加、删除和修改的时候,索引也要动态的维护,这样就降低了数据的维护速度。
索引是建立在数据库表中的某些列的上面。在创建索引的时候,应该考虑在哪些列上可以创建索引,在哪些列上不能创建索引。一般来说,应该在这些列上创建索引:
在经常需要搜索的列上,可以加快搜索的速度;
在作为主键的列上,强制该列的唯一性和组织表中数据的排列结构;
在经常用在连接的列上,这些列主要是一些外键,可以加快连接的速度;在经常需要根据范围进行搜索的列上创建索引,因为索引已经排序,其指定的范围是连续的;
在经常需要排序的列上创建索引,因为索引已经排序,这样查询可以利用索引的排序,加快排序查询时间;
在经常使用在WHERE子句中的列上面创建索引,加快条件的判断速度。
同样,对于有些列不应该创建索引。一般来说,不应该创建索引的的这些列具有下列特点:
第一,对于那些在查询中很少使用或者参考的列不应该创建索引。这是因为,既然这些列很少使用到,因此有索引或者无索引,并不能提高查询速度。相反,由于增加了索引,反而降低了系统的维护速度和增大了空间需求。
第二,对于那些只有很少数据值的列也不应该增加索引。这是因为,由于这些列的取值很少,例如人事表的性别列,在查询的结果中,结果集的数据行占了表中数据行的很大比例,即需要在表中搜索的数据行的比例很大。增加索引,并不能明显加快检索速度。
第三,对于那些定义为text, image和bit数据类型的列不应该增加索引。这是因为,这些列的数据量要么相当大,要么取值很少,不利于使用索引。
第四,当修改性能远远大于检索性能时,不应该创建索引。这是因为,修改性能和检索性能是互相矛盾的。当增加索引时,会提高检索性能,但是会降低修改性能。当减少索引时,会提高修改性能,降低检索性能。因此,当修改操作远远多于检索操作时,不应该创建索引。

谷歌票房预测模型 准确度高达94%

谷歌公布了一项重要研究成果–电影票房预测模型。该模型能够提前一个月预测电影上映首周的票房收入,准确度高达94%。这在业内引起了强烈讨论,不少内人士认为该模型非常适合好莱坞电影公司通过预测票房来及时调整电影营销战略,但同时也有吐槽者暗示谷歌的票房预测模型别有用心,旨在鼓动电影公司购买其搜索引擎广告。那么,孰是孰非,谷歌票房预测模型以及大数据在电影行业的应用是嘘头,还是大有来头,让我们来一探究竟。
谷歌票房预测模型的基础:电影相关的搜索量与票房收入的关联
谷歌的票房预测模型是大数据分析技术在电影行业的一个重要应用。随着互联网的发展,人们越来越习惯于在网上搜索电影信息。据谷歌统计,从2011到2012年,电影相关的搜索量增长了56%。谷歌发现,电影相关的搜索量与票房收入之间存在很强的关联。
图1显示了2012年电影票房收入(红色)和电影的搜索量(灰色)的曲线(注:本文的所有图片均引用自谷歌的白皮书:QuantifyingMovieMagicwithGoogleSearch)。可以看到,两条曲线的起伏变化有着很强的相似性。

p1

p1


 

图1.2012年票房收入与搜索量的曲线
(红色是票房收入,灰色是搜索量,横轴是月份,纵轴是数量)

更进一步地,谷歌把电影的搜索分成了两类:
  I.涉及电影名的搜索(MovieTitleSearch);
  II.不涉及电影名的搜索(Non-TitleFilm-RelatedSearch)。这类搜索不包含具体的名字,而是一些更宽泛的关键词搜索,如“热门电影”、“爱情片”、“好莱坞电影”等。
  图2显示了票房收入与这两类搜索量之间的关系。从图上可以看到,大部分情况下,第I类搜索量超过第II类搜索量。但在电影淡季的时候(图中灰色椭圆区域,这时候票房收入较低),第I类搜索量会低于第II类搜索量。这符合常理,因为在淡季的时候知名度高的电影很少,人们往往用更宽泛的搜索来寻找想看的电影。

p2
p2

图2.2012年票房收入和两类搜索量的曲线

  (红色代表票房收入,蓝色代表第I搜索,灰色代表第II类搜索,横轴是月份,纵轴是数量)

  这一发现对电影的网络营销来说有一定的指导意义:在淡季的时候,电影公司可多购买相对宽泛的关键词的广告,而在旺季的时候,多购买涉及电影名的、更具体的关键词的广告。
  提前一周预测票房,可达到92%的准确度
  上面的讨论表明用电影的搜索量来预测票房是有可能的。那么,如果单纯使用搜索量来预测首周票房收入,效果怎么样?通过对2012年上映的99部电影的研究,谷歌发现仅依靠搜索量来预测是不够的。谷歌尝试构建了一个线性的模型,但只达到了70%的准确度(如图3)。

p3
p3

图3.搜索量与首周票房收入之间的关系

  (横轴是搜索量,纵轴是首周票房收入,灰色点对应某部电影的搜索量与首周票房收入)

  为了构建更加精确的预测模型,谷歌最终采用了四类指标:
  (1)(电影放映前一周的)电影的搜索量
  (2)(电影放映前一周的)电影广告的点击量
  (3)上映影院数量
  (4)同系列电影前几部的票房表现
  其中每类指标又包含了多项类内指标。
  在获取到每部电影的这些指标后,谷歌构建了一个线性回归模型(linearregressionmodel)模型,来建立这些指标和票房收入的关系。线性回归模型,在大数据分析领域里算是最基本的模型之一,它认为票房收入与这些指标之间是简单的线性关系。
  图4展示了模型的效果,其中灰色点代表了实际的票房收入,红色点代表了预测的票房收入。可以看到,预测的结果与实际的结果差异很小。

p4
p4

图4.提前一周预测票房的效果

  (横轴是搜索量,纵轴是首周票房收入,灰色点对应某部电影的首周票房收入,红色点对应预测的首周票房收入)

   提前一个月预测票房,可达到94%的准确度
   尽管提前一周预测可以达到92%的准确度,对于电影的营销来说,价值并不大,因为一周的时间往往很难调整营销策略,改善营销效果。因此,谷歌又进一步研究,使得模型可以提前一个月预测首周票房。
  实现提前一个月预测的关键在于:谷歌采用了一项新的指标–电影预告片的搜索量。谷歌发现,预告片的搜索量比起电影的直接搜索量而言,可以更好的预测首周票房表现。这一点不难理解,因为在电影放映前一个月的时候,人们往往更多地搜索预告片。
  仅使用预告片的搜索量仍然不够,因此谷歌的模型最终采用了三类指标:
  (1)电影预告片的搜索量
  (2)同系列电影前几部的票房表现
  (3)档期的季节性特征
  其中每类指标又包含了多项类内指标。
  在获取到每部电影的这些指标后,谷歌再次构建了一个线性回归模型(linearregressionmodel)模型,来建立这些指标和票房收入的关系。
  图5展示了模型的效果,其中灰色点代表了实际的票房收入,红色点代表了预测的票房收入。可以看到,预测结果与实际结果非常接近。

p5
p5

图5提前一个月预测票房的效果

  (横轴是预告片搜索量,纵轴是首周票房收入,灰色点对应实际某部电影的首周票房收入,红色点对应预测的首周票房收入)

   为什么谷歌采用了这么简单的模型
  前面的分析中已经提到,谷歌采用的是数据分析中最简单的模型之一-线性回归模型。这对很多读者来说多少有点意外。为什么谷歌用的模型如此简单?
  首先,线性模型虽然简单,但已经达到了很高的准确度(94%)。简单且效果好,是我们在实际应用中一直追求的。
  其次,简单的模型易于被人们理解和分析。大数据分析技术的优势正是能够从大量数据中挖掘出人们可以理解的规律,从而加深对行业的理解。正是因为谷歌使用了线性预测模型,所以它很容易对各项指标的影响做出分析。例如谷歌的报告中给出了这样的分析结论:“距离电影上映一周的时候,如果一部影片比同类影片多获得25万搜索量,那么该片的首周票房就很可能比同类影片高出430万美元。若一部电影有搜索引擎广告,我们也可以通过其广告的点击量来推测票房表现——如果点击量超出同类电影2万,那该片首周票房将领先750万美元”。
  对于电影的营销来说,掌握各项指标对票房收入的影响,可以优化营销策略,降低营销成本。谷歌的报告中指出,用户一般会通过多达13个渠道来了解电影的信息。票房预测模型的出现无疑使得营销策略的制定更加有效。
   大数据分析在电影行业的应用前景:把模糊的行业经验变得更科学,更精准
  票房预测模型的公布,让业内人士再次见证了大数据的成功应用。近年来,大数据在电影行业的应用越来越引起关注,比如此前谷歌利用搜索数据预测了奥斯卡获奖者,Neflix通过大数据分析深度挖掘了用户的喜好,捧红了《纸牌屋》等。但大数据对电影行业的价值到底如何,仍然众说纷纭。梦工厂CEO卡森伯格最近接受腾讯财经专访时发表了一个似乎悲观的态度:电影创作靠创造力,不靠数据分析。
  要理解大数据对电影行业的影响,首先需要对大数据分析有正确的认识。大数据分析的本质,在于通过数据,更精准地挖掘用户的需求。而谁能掌握用户的需求,谁就可以引领行业的发展。谷歌的票房预测模型,本质上也是通过搜索量,挖掘出用户对电影的需求有多大,进而预测出票房收入。值得注意的是,谷歌的模型基于的只是宏观的搜索量的统计,对用户需求的挖掘相对表面。如何从搜索数据中更深地挖掘用户的需求将是未来的趋势之一。
  既然大数据分析的核心是挖掘用户需求,所以一大核心问题是:哪些用户的需求是可以从数据中挖掘到的?要知道,并不是任何需求都可以被挖掘到,或者说可以被精准地挖掘到。能够通过大数据分析挖掘到的需求,一般是符合行业经验的,应当是业内人士觉得可以被挖掘的(有时候,挖掘出的需求可能会超出行业经验,甚至产生颠覆性的影响)。谷歌的预测模型的基本假设,是符合行业直觉的,即电影的搜索量越大,往往票房收入越大。模型能够提前一个月预测票房,也符合行业经验,正如谷歌的一项行业调研揭示的:大多数观众会在电影首映4周前去了解电影。数据分析技术,是把这种模糊的行业经验,变得更科学,变得更精准。而这一过程,很可能会深层次地改变电影行业。
  要将大数据分析更广泛地应用于电影行业,可以从以下几个方面去探索:
   一.我们可以获得哪些数据。大数据时代的特点是数据来源广泛,可以是业内发布的数据,也可以是来自搜索引擎、社交媒体等的数据。有些数据看似关联不强(比如社交媒体数据),但往往能从中挖掘到用户的潜在需求。
   二.从数据中,我们想挖掘什么信息。谷歌的模型,挖掘了搜索量等数据与票房收入的关联;Netflix的模型,则挖掘了观众对不同电影的偏好,以及其他的行为特点。挖掘什么信息,一方面取决于我们有哪些数据,另一方面也取决于什么样的信息可能有助于商业决策。
  三.有什么行业经验是可以结合的。单纯地数据分析,可能会找到很多规律,但这些规律未必是有实际价值的。只有当数据结合行业经验,才更容易形成精准的行业模型,从而产生巨大的价值。
  而卡森伯格说的“不靠数据”,更多的是强调电影创作本身。电影的创作充满了艺术,是很难形成科学的规律的。即便如此,大数据对电影创作也可以起到一定的辅助作用。毕竟,了解观众的需求,也是电影创作的重要参考。

Hadoop的分块与分片

HDFS存储系统中,引入了文件系统的分块概念(block),块是存储的最小单位,HDFS定义其大小为64MB。与单磁盘文件系统相似,存储在HDFS上的文件均存储为多个块,不同的是,如果某文件大小没有到达64MB,该文件也不会占据整个块空间。在分布式的HDFS集群上,Hadoop系统保证一个块存储在一个datanode上。
当我们执行hadoop fs -put aa.txt /bb.txt,则aa.txt会被复制为集群的/bb.txt。查看系统的log日志hadoop-$username-namenode-*.log,可以看到类似于
2011-09-07 08:39:12,506 INFO org.apache.hadoop.hdfs.StateChange: BLOCK* NameSystem.addStoredBlock: blockMap updated: 127.     0.0.1:50010 is added to blk_5715489406767973176_1455 size 32
这样的信息,里面记录有分配block的元数据信息和block号(blk_5715489406767973176)。
在另一个日志中hadoop-$username-datanode-*.log可以看到对应的datanode打印出相应的log:
2011-09-07 08:39:12,495 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: Receiving block blk_5715489406767973176_145     5 src: /127.0.0.1:48492 dest: /127.0.0.1:50010
HDFS的namenode只存储整个文件系统的元数据镜像,这个镜像由配置dfs.name.dir指定,datanode则存有文件的metainfo和具体的分块,存储路径由dfs.data.dir指定。
分析完毕分块,下面讨论一下分片:
hadoop的作业在提交过程中,需要把具体的输入进行分片。具体的分片细节由InputSplitFormat指定。分片的规则为  FileInputFormat.class中的getSplits()方法指定:
long splitSize = computeSplitSize(goalSize, minSize, blockSize);
computeSplitSize:
Math.max(minSize, Math.min(goalSize, blockSize));
其中goalSize为“InputFile大小”/“我们在配置文件中定义的mapred.map.tasks”值,minsize为mapred.min.split.size,blockSize为64,所以,这个算式为取分片大小不大于block,并且不小于在mapred.min.split.size配置中定义的最小Size。
当某个分块分成均等的若干分片时,会有最后一个分片大小小于定义的分片大小,则该分片独立成为一个分片。
http://hi.baidu.com/chemical_liang/item/bd2d0163eb54d3177ddecceb

linux swap命令

一般来说可以按照如下规则设置swap大小:
4G以内的物理内存,SWAP 设置为内存的2倍。
4-8G的物理内存,SWAP 等于内存大小。
8-64G 的物理内存,SWAP 设置为8G。
64-256G物理内存,SWAP 设置为16G。
系统中交换分区的大小并不取决于物理内存的量,而是取决于系统中内存的负荷,所以在安装系统时要根据具体的业务来设置SWAP的值。
查看swap使用的情况:

swapon -s
free -m
cat /proc/sys/vm/swappiness

该值默认值是60.
swappiness=0的时候表示最大限度使用物理内存,然后才是 swap空间,
swappiness=100的时候表示积极的使用swap分区,并且把内存上的数据及时的搬运到swap空间里面。

eclipse插件FileSync自动同步文件到tomcat

eclipse插件FileSync自动同步文件到tomcat
tomcat server.xml 配置

<Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true" xmlNamespaceAware="false" xmlValidation="false">
        <Context path="" docBase="E:web3.4targetweb-0.0.1-SNAPSHOT" reloadable="true">
<!-- 					<Resource name="jdbc/biee-web" -->
<!-- 						factory="org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory" auth="Container" -->
<!-- 						type="javax.sql.DataSource"  -->
<!-- 						maxActive="20"  -->
<!-- 						maxIdel="10"  -->
<!-- 						maxWait="1000" -->
<!-- 						username="bieeweb"  -->
<!-- 						password="bieeweb001"  -->
<!-- 						driverClassName="oracle.jdbc.driver.OracleDriver" -->
<!-- 						URIEncoding="UTF-8" -->
<!-- 						url="jdbc:oracle:thin:@10.106.23.154:1523:yktdweb"> -->
<!-- 					</Resource> -->
				</Context>
      </Host>

安装FileSync插件:
注意:不同版本的eclipse需要安装不同版本的插件
Eclipse 3.3 – 3.4:
Go to “Help -> Software Updates -> Find and Install… -> Search for new features to install -> Next -> New Remote Site…”
Eclipse 3.5:
Go to “Help -> Install new Software… -> Work with:”
and use the http://andrei.gmxhome.de/eclipse/ as url.
please do not unzip the FileSync jar file – just copy it to the dropins folder for Eclipse 3.4-3.7, or plugins folder for Eclipse 3.3.
下载地址:http://andrei.gmxhome.de/filesync/links.html
FileSync使用:
工程-》右键-》属性 选择工程目录对应的taget目录即可,如下图:

FileSync 插件的使用

FileSync 插件的使用

java竖线分割字符串的问题

例1:
String[] paraStr = “6010;320100;A”.split(“;”);
System.out.println(Arrays.toString(paraStr));
输出:[6010, 320100, A]
Ok
例2:
String[] paraStr = “6010|320100|A”.split(“|”);
System.out.println(Arrays.toString(paraStr));
输出:[, 6, 0, 1, 0, |, 3, 2, 0, 1, 0, 0, |, A]
NO,和期望值相差甚远
例3:
String[] paraStr = “6010+320100+A”.split(“+”);
System.out.println(Arrays.toString(paraStr));
输出:
Exception in thread “main” java.util.regex.PatternSyntaxException: Dangling meta character ‘+’ near index 0
+
异常!
有现象,才能总结出结论:
使用String.split方法时要注意的问题
在使用String.split方法分隔字符串时,分隔符如果用到一些特殊字符,可能会得不到我们预期的结果。
我们看jdk doc中说明
public String[] split(String regex)
Splits this string around matches of the given regular expression.
参数regex是一个 regular-expression的匹配模式而不是一个简单的String,他对一些特殊的字符可能会出现你预想不到的结果:
1.用竖线 | 分隔字符串,你将得不到预期的结果。
2.用 * 分隔字符串运行将抛出java.util.regex.PatternSyntaxException异常,用加号 + 也是如此。
显然,| + * 不是有效的模式匹配规则表达式,用”\*” “\+”转义后即可得到正确的字符串结果。
“|” 分隔串时虽然能够执行,但是却不是预期的目的,得到的是每个字符的分割,而不是字符串,”\|”转义后即可得到正确的字符串结果。
还有如果想在串中使用””字符,则也需要转义.首先要表达”ab”这个串就应该用”a\b”,如果要分隔就应该这样才能得到正确结果:
String[] aa = “aaa\bbb\bccc”.split(“\\“);
注意:除了使用“\|”外,也可以用”[.]” 进行分隔!
如:
String[] paraStr = “6010|320100|A”.split(“[|]”);
String[] paraStr = “6010.320100.A”.split(“[.]”);
http://www.cnblogs.com/haitao-fan/archive/2013/01/27/2878537.html

字符编码-ASCII

计算机中的信息包括数据信息和控制信息,数据信息又可分为数值和非数值信息。非数值信息和控制信息包括了字母、各种控制符号、图形符号等,它们都以二进制编码方式存入计算机并得以处理,这种对字母和符号进行编码的二进制代码称为字符代码(Character Code)。计算机中常用的字符编码有ASCII码(美国标准信息交换码)和EBCDIC码(扩展的BCD交换码)。
编码
在显示器上看见的文字、图片等信息在电脑里面其实并不是我们看见的样子,即使你知道所有信息都存储在硬盘里,把它拆开也看不见里面有任何东西,只有些盘片。假设,你用显微镜把盘片放大,会看见盘片表面凹凸不平,凸起的地方被磁化,凹的地方是没有被磁化;凸起的地方代表数字1,凹的地方代表数字0。硬盘只能用0和1来表示所有文字、图片等信息。那么字母”A”在硬盘上是如何存储的呢?可能小张计算机存储字母”A”是1100001,而小王存储字母”A”是11000010,这样双方交换信息时就会误解。比如小张把1100001发送给小王,小王并不认为1100001是字母”A”,可能认为这是字母”X”,于是小王在用记事本访问存储在硬盘上的1100001时,在屏幕上显示的就是字母”X”。也就是说,小张和小王使用了不同的编码表。小张用的编码表是ASCII,ASCII编码表把26个字母都一一的对应到2进制1和0上;小王用的编码表可能是EBCDIC,只不过EBCDIC编码与ASCII编码中的字母和01的对应关系不同。一般地说,开放的操作系统(LINUX 、WINDOWS等)采用ASCII 编码,而大型主机系统(MVS 、OS/390等)采用EBCDIC 编码。在发送数据给对方前,需要事先告知对方自己所使用的编码,或者通过转码,使不同编码方案的两个系统可沟通自如。
ASCII
美国(国家)信息交换标准(代)码,一种使用7个或8个二进制位进行编码的方案,最多可以给256个字符(包括字母、数字、标点符号、控制字符及其他符号)分配(或指定)数值。
ASCII码于1961年提出,用于在不同计算机硬件和软件系统中实现数据传输标准化,在大多数的小型机和全部的个人计算机都使用此码。ASCII码划分为两个集合:128个字符的标准ASCII码和附加的128个字符的扩充和ASCII码。比较EBCDIC。其中95个字符可以显示。另外33个不可以显示。 标准ASCII码为7位,扩充为8位。
目前使用最广泛的西文字符集及其编码是 ASCII 字符集和 ASCII 码( ASCII 是 American Standard Code for Information Interchange 的缩写),它同时也被国际标准化组织( International Organization for Standardization, ISO )批准为国际标准。
基本的 ASCII 字符集共有 128 个字符,其中有 96 个可打印字符,包括常用的字母、数字、标点符号等,另外还有 32 个控制字符。标准 ASCII 码使用 7 个二进位对字符进行编码,对应的 ISO 标准为 ISO646 标准。
字母和数字的 ASCII 码的记忆是非常简单的。我们只要记住了一个字母或数字的 ASCII 码(例如记住 A 为 65 , 0 的 ASCII 码为 48 ),知道相应的大小写字母之间差 32 ,就可以推算出其余字母、数字的 ASCII 码。
虽然标准 ASCII 码是 7 位编码,但由于计算机基本处理单位为字节( 1byte = 8bit ),所以一般仍以一个字节来存放一个 ASCII 字符。每一个字节中多余出来的一位(最高位)在计算机内部通常保持为 0 (在数据传输时可用作奇偶校验位)。
由于标准 ASCII 字符集字符数目有限,在实际应用中往往无法满足要求。为此,国际标准化组织又制定了 ISO2022 标准,它规定了在保持与 ISO646 兼容的前提下将 ASCII 字符集扩充为 8 位代码的统一方法。 ISO 陆续制定了一批适用于不同地区的扩充 ASCII 字符集,每种扩充 ASCII 字符集分别可以扩充 128 个字符,这些扩充字符的编码均为高位为 1 的 8 位代码(即十进制数 128~255 ),称为扩展 ASCII 码。
通过了解字符的存储编码,可以解决很多由编码不匹配引起的问题,比如网页乱码、邮件乱码,本文简单扼要地阐明了ASCII编码、EBCDIC编码、GB2312编码、Unicode编码、UTF-8编码、以及Base64编码。
MBCS
GB2312
GBK
Big5
Unicode
http://baike.baidu.com/view/1204863.htm