<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>Bupthua's Blog</title>
 <link href="http://bupthua.github.io/atom.xml" rel="self"/>
 <link href="http://bupthua.github.io/"/>
 <updated>2014-03-14T21:23:32-07:00</updated>
 <id></id>
 <author>
   <name>bupthua</name>
   <email>bupthua@gmail.com</email>
 </author>

 
 <entry>
   <title>表达不清与站位不明导致的过度演化</title>
   <link href="http://bupthua.github.io/posts/bdst-howto-makeitclear.html"/>
   <updated>2014-03-15T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/bdst-howto-makeitclear</id>
   <content type="html">&lt;p&gt;事情发展到这一步真是让人有点震惊，由此可见当一个人在做计划发指令的时候，一定要想清楚要达到什么样的效果，千万不能模糊的任其蔓延。&lt;/p&gt;

&lt;h5&gt;事件回放&lt;/h5&gt;

&lt;p&gt;前台处于论文状态，没太多时间，后台的人不能闲着，根据上次的经验，在我们没有多少文档的情况下，大家应该充分了解我们平台的功能，熟悉目前已有平台的样子，所以我的计划是由一个人负责，理顺系统脉络，然后“所有人员阅读报告，理解系统完成的所有功能，对所有页面有个整体认识。后台 了解协助梳理所有功能，&lt;strong&gt;吹毛求疵的了解&lt;/strong&gt;所有细节”，而关于讨论和意见，多半是针对前台的，因为前台是第一个最需要知道所有功能，提出意见的，所以定义为“前台 了解所有功能，并提出修改意见，思考可能的页面，确定所有功能点（例如社团的QA是否要，为什么要），确定网站的整体风格，定调前多与大象沟通”&lt;/p&gt;

&lt;p&gt;结果事情的发展是负责梳理脉络的人在画好思维导图后群发了邮件，定义自己为“负责社团管理平台底层功能改进建议的收集与整理工作”，并要求大家提出功能修改意见完善意见，此时所有人没有方向的发散的提出大量的意见，而太多的意见不是我们现在需要讨论的，整个团队一度处于混乱的状态。&lt;/p&gt;

&lt;h5&gt;总结&lt;/h5&gt;

&lt;p&gt;此次事件我应该负全责，既然定义了进度，就应该负责去把控。在收到收集意见的邮件时，自己退化到随波逐流的成员去思考（可能这个是第一反应吧），没有及时把握当前的形势，虽然我完全明白当前不需要讨论（我一直强调做好基础功能），而是需要熟悉了解当前的基础功能，但是没有及时发现形势的转变。由此，在以后的工作中，我应该有更强的领导意识、全局意识、责任意识，多与大象沟通，积极健康的推动团队的发展。&lt;/p&gt;

&lt;h5&gt;补救&lt;/h5&gt;

&lt;p&gt;周末开会时一起梳理这一次的基础功能，让前台了解当前的目标和所有功能，让后台知道以后页面上所有功能的作用和期望。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>做程序员100题</title>
   <link href="http://bupthua.github.io/posts/Study-100-Question-of-Interview.html"/>
   <updated>2014-03-15T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Study-100-Question-of-Interview</id>
   <content type="html">&lt;ol&gt;
&lt;li&gt;二元查找树转换为排序的双向链表&lt;/li&gt;
&lt;li&gt;带min函数的栈，要求函数都是O（1）&lt;/li&gt;
&lt;li&gt;子数组最大和&lt;/li&gt;
&lt;li&gt;在二元树中找出和为某一值的所有路径&lt;/li&gt;
&lt;li&gt;k小/大的k个数 multiset&lt;int, greater&lt;int&gt; &amp;gt; IntHeap&lt;/li&gt;
&lt;li&gt;判断序列是否是二元查找树的后续遍历结果&lt;/li&gt;
&lt;li&gt;翻转句子中单词的顺序&lt;/li&gt;
&lt;li&gt;&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>Real Bugs</title>
   <link href="http://bupthua.github.io/posts/Real-Bugs.html"/>
   <updated>2014-03-15T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Real-Bugs</id>
   <content type="html">&lt;hr&gt;

&lt;p&gt;size_t 是无符号整数， 当str为空字符串时，用 int size = str.size() - 1 得到的不是 -1&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>找工作中的思考</title>
   <link href="http://bupthua.github.io/posts/Thinking-in-Job.html"/>
   <updated>2014-03-12T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Thinking-in-Job</id>
   <content type="html">&lt;p&gt;今天是今年第一次参加找工作的交流会，没听什么，我知道他们要讲什么，可能更多的我把这看做是一个标志吧，标志着我已经从几年来的看客变成了今年的主人公。找工作是最让人焦虑的一段时间，因为要直面很多问题，很多关键性的选择。我看到了很多人的生活，自己也经历了很多跌宕的事情，但是轮到自己去思考决定时，依然不能说是清明的。&lt;/p&gt;

&lt;p&gt;留京、离京，技术、非技术，奋斗、安逸……我在追求什么，什么最让我快乐，什么最让我害怕&lt;/p&gt;

&lt;p&gt;-- 3.12&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>TCPIP Illustrated--TCP</title>
   <link href="http://bupthua.github.io/posts/TCPIP-Illustrated-TCP.html"/>
   <updated>2014-02-19T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/TCPIP-Illustrated-TCP</id>
   <content type="html">&lt;p&gt;基本分层：链路层（SLIP，PPP，ARP，RARP），网络层（IP/ICMP/IGMP)，运输层（TCP/UDP)，应用层&lt;br&gt;
ARP和RARP用于转换IP地址和MAC地址，包装在IP包中。&lt;br&gt;
ICMP和IGMP也都是用IP包发送。PING是利用的ICMP，&lt;br&gt;
路由搜索顺序：匹配IP地址，匹配网络号，匹配default&lt;br&gt;
路由表：netstat -rn，其中 U表示可以使用，G表示下一个是网关，H表示是到主机，D表示重定向而创建，M表示被重定向报文修改&lt;br&gt;
应用程序应该关注IP报文段长度，因为UDP不主动分片，而TCP试图避免分片&lt;br&gt;
DNS域名系统：顶级域被分为三个部分，1）arpa是一个用作地址到名字的转换，用于指针查询，例如根 33.13.252.140.in-addr.  arpa，2)7个三长度的普通域；3）国家代码  &lt;/p&gt;

&lt;p&gt;TCP&lt;br&gt;
建立链接用3次握手，拆连接用4次握手。需要用到2MSL等待状态，等待期间端口能否被重用用设置 SO&lt;em&gt;REUSEADDR&lt;br&gt;
经受时延确认：即捎带确认&lt;br&gt;
小数据：Nagel算法：为了避免微小分组可能增加阻塞的问题，规定一个TCP连接上最多只能有一个未被确认的未完成的小分组，可以用 TCP&lt;/em&gt;NODELAY关闭&lt;br&gt;
慢启动：指数级增加&lt;br&gt;
拥塞避免：增加慢启动门限ssthresh，超过后加法增加。发生超时时反应剧烈，ssthresh=cwnd/2，cwnd=1，进入慢启动&lt;br&gt;
快速重传: 收到3个相同ack时，cwnd=ssthresh+3&lt;br&gt;
快速恢复：发送方收到一个重复的ACK，那么根据TCP的ACK机制就表明有一个数据包离开了网络，于是cwnd加1。因此在快速回复的基础上，每次收到重复ACK时, 拥塞窗口加1&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Structure and Algorithm</title>
   <link href="http://bupthua.github.io/posts/Basic-Structure-Algorithm.html"/>
   <updated>2014-02-19T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/Basic-Structure-Algorithm</id>
   <content type="html">&lt;h3&gt;3-11&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;找出所有元素出现了两次后加入的一个元素的问题(xor)，扩展为加入两个的问题(xor, split, xor)&lt;/li&gt;
&lt;li&gt;最大子数组和的问题 &lt;code&gt;end[i] = max(end[i - 1] + arr[i], arr[i]), all[i] = max(end[i - 1] + arr[i],  all[i - 1])&lt;/code&gt;。扩展为可循环数组？找最小子数组和。更有意思的是从推到&lt;code&gt;end[i] = max(end[i - 1] + arr[i], arr[i])&lt;/code&gt;看出end[i - 1] &amp;lt; 0是 end[i]需要重新累加，因此直接相加比最大就行了。&lt;/li&gt;
&lt;li&gt;最长公共子序列 &lt;code&gt;d[i][j]=d[i - 1][j - 1] + 1 or max(d[i - 1][j], d[i][j - 1])&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;最长公共子串 &lt;code&gt;d[i][j]=d[i - 1][j - 1] + 1 or 0&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;3-12 海量数据处理&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;从大量中找出返回频率最高的N个。【首先hash到M个文件，然后使用hash在单个文件统计出现次数，对每个文件使用堆排序得到前N个数据，对MN个得到top N&lt;/li&gt;
&lt;li&gt;多个分机只能与主机慢速通信，每个分机有大量数据，如何找出所有数据的Frequent TOP K。每个分机先排序，然后中位数提交（median&lt;em&gt;v, median&lt;/em&gt;p)，比较k vs sum(median_p1, p2, ...., pn)&lt;/li&gt;
&lt;li&gt;找不重复的数，用bitmap or 2-bitmap， 还可以通过最高位不断将区间化小&lt;/li&gt;
&lt;li&gt;为什么要使用B+树而不是红黑树？ MyISAM的非聚集索引和InnoDB的聚集索引&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;3-14&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;卡特兰数 f(n)=f(0)f(n - 1) + f(1)f(n - 2) + ...... + f(n - 1)f(n) = C(2n, n) / (n + 1) = C(2n, n) - C(2n, n + 1)，找钱问题，递归打印可能的序列，凸多边形划分问题&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>Shell 基本知识</title>
   <link href="http://bupthua.github.io/posts/shell-basic.html"/>
   <updated>2014-01-15T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/shell-basic</id>
   <content type="html">&lt;p&gt;计算机语言是相通的，但是却各有特点。很多时候我们了解了一门语言后大呼“哦，原来是这么回事儿”，事后又忘记了。当再次遇到问题，或者搁置一段时间后想要再次上手仍然显得困难。因此，我打算对每种语言（shell，python，javascript，php）总结一些基本的概念和知识。主要是从基本概念和特点、变量、基本类型及作用域、函数定义、判断及循环着手吧。&lt;/p&gt;

&lt;h2&gt;shell基本概念和特点&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;shell脚本中一切皆是命令，是一堆命令的集合。&lt;/strong&gt; shell脚本很有意思，和一般的编程语言很不一样，每句话都是可以在命令行中运行的，是一系列命令的组合。一些有意思的例子&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;括号（）， 在shell中表示在子shell中执行；&lt;/li&gt;
&lt;li&gt;shell函数中的return（return表示退出码，不是普通意义的返回值？为什么，因为shell是一堆命令的集合，函数也只是将一组命令打包命名，shell中使用管道的概念，即对输出进行重定向；&lt;/li&gt;
&lt;li&gt;令人混淆的空格问题。刚开始写shell的时候一定很不理解为什么shell中赋值、判断中空格显得很怪异。其实根本原因在于shell全部是命令的集合，而命令与选项之间需要空格。我们来剖析一下： &lt;code&gt;a=1&lt;/code&gt; 和 &lt;code&gt;a = 1&lt;/code&gt;怎么被解析，因为命令和选项由空格隔开，前面一句没有空格，命令是&amp;quot;a=1&amp;quot;，解析到了=号，所以认为是赋值命令，参数由等号前后决定。后面的&lt;code&gt;a = 1&lt;/code&gt;被解析为命令是&lt;code&gt;a&lt;/code&gt;，参数是等号和1，而a是没有被定义的，所以发生了错误。从这里我们可以充分理解一切都是命令了吧。 再来看if中的条件判断，其实&lt;code&gt;[&lt;/code&gt;也是一条命令，相当于test，只不过&lt;code&gt;[&lt;/code&gt;的最后一个参数必须是&lt;code&gt;]&lt;/code&gt;来表示结束，命令的写法就是&lt;code&gt;命令+空格+参数+空格&lt;/code&gt;，所以命令&lt;code&gt;[&lt;/code&gt;的写法就是&lt;code&gt;[+空格+若干参数+]&lt;/code&gt;，所以如果&lt;code&gt;[&lt;/code&gt;和参数之间没有空格，就会认为命令是&lt;code&gt;]+参数&lt;/code&gt;，显然没有这样的命令，所以又会出错&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;变量、基本类型及作用域&lt;/h2&gt;

&lt;p&gt;$varname表示变量，是${varname} 的一个缩写。赋值使用&lt;code&gt;varname=$val&lt;/code&gt;
shell中变量类型概念很弱，普通的都当做字符串来处理。用 $(())可以表示整数操作， let也可以进行计算， 例如 &lt;code&gt;a=$((b+1))&lt;/code&gt;, &lt;code&gt;echo $((b++))&lt;/code&gt;, &lt;code&gt;echo $((--b))&lt;/code&gt;。shell中也有数组，可以用小括号加空格来赋值，引用数组变量要用 &lt;code&gt;${var[index]}&lt;/code&gt;，index为&lt;em&gt;/@的时候表示所有元素， 个数用 &lt;code&gt;${#var[*]}&lt;/code&gt;，可以用 for var in ${arr[&lt;/em&gt;]}或者while进行遍历，清空单个用空赋值，unset清空所有。
变量的作用域为shell进程，函数的意义决定了没有函数作用域，用export可以扩大变量作用域&lt;/p&gt;

&lt;h2&gt;函数定义&lt;/h2&gt;

&lt;p&gt;再次强调，函数其实是命令的集合，也是一个命令，所以调用方式是  &lt;code&gt;functname param1 param2 ...&lt;/code&gt; 而不是 &lt;code&gt;functname(param1, param2, ...)&lt;/code&gt;
函数定义：&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;function functname { 
    shell commands 
} 
或者
functname() {

}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;我们可以在脚本中来获取参数的值。使用$N，其中$0是函数名称，$1为param1，$2为param2，如此类推，如果N大于实际参数的数目，为空。我们一般将位置变量是从$1开始。
$* 表示所有参数组成的一个字符串，这些参数之间的间隔是IFS的首个字母即空格，IFS包括TAB，空格，换行等字符。
$@ 等同于&amp;quot;$1&amp;quot; &amp;quot;$2&amp;quot;... &amp;quot;$N&amp;quot;。
$# 表示参数的个数
$? 退出码&lt;/p&gt;

&lt;h2&gt;流程控制&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;shell命令，可以按照分号分割，也可以按照换行符分割。如果想一行写入多个命令，可以通过“&amp;#39;;”分割。&lt;/li&gt;
&lt;li&gt;if语句结构[if/then/elif/else/fi]&lt;/li&gt;
&lt;li&gt;for循环使用方法(for/do/done)： for … in 语句， for((赋值；条件；运算语句))&lt;/li&gt;
&lt;li&gt;while循环使用（while/do/done)&lt;/li&gt;
&lt;li&gt;untile循环使用(untile/do/done)&lt;/li&gt;
&lt;li&gt;case选择语句使用（case/esac)，用两个分号表示break， 其中pattern是正则表达式，* 任意字串；? 任意字元；[abc]表示a, b, 或c三字元其中之一；[a-n]   从a到n的任一字元；|表示多重选择&lt;/li&gt;
&lt;li&gt;select语句使用方法（产生菜单选择）， 使用(select name in seq/do/case $ch in/esac/done)&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;p&gt;有了以上的基础，一些基本的脚本程序就可以搞定了。其他的遇到问题再查资料吧。&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Python如此优雅，你知道么?</title>
   <link href="http://bupthua.github.io/posts/Python-is-so-beautiful.html"/>
   <updated>2014-01-10T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/Python-is-so-beautiful</id>
   <content type="html">&lt;p&gt;不知道从什么时候开始，很多人桌上都有了一本Python基础教程或者学习手册类的书，这门语言迅速风靡了码农圈。而它的优雅，你全知道了吗？&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Python的截取可以用负值表示位置&lt;/li&gt;
&lt;li&gt;join只能对str，那么如果是int列表怎么办呢？ &lt;code&gt;&amp;#39;.&amp;#39;.join(&amp;#39;%s&amp;#39; % id for id in dataList)&lt;/code&gt; 瞧，多么优雅&lt;/li&gt;
&lt;li&gt;列表倒置 dataList[::-1]&lt;/li&gt;
&lt;/ol&gt;
</content>
 </entry>
 
 <entry>
   <title>2013年总结和展望</title>
   <link href="http://bupthua.github.io/posts/2013review.html"/>
   <updated>2014-01-04T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/2013review</id>
   <content type="html">&lt;p&gt;2013年已经结束，这也意味着研究生期间稳定在实验室的日子的结束。回望这一年，竟然是这么的短暂。&lt;/p&gt;

&lt;p&gt;上半年，本来应该进入移动研究院的我机缘巧合留在了实验室，因为以前做过网页转换的内容，而实验室需要做这方面的探索，所以很顺利的过渡到了实验室的工作。我着重是研究了整体结构（模仿了以前的体系，实践了寒假的时候看的《Unix高级编程》），并再次梳理了我自导自演的算法。同时，因为去年这个时候在IBM接触到了大数据团队，而正好实验室也想在大数据方面做一些东西，所以我顺带看了点大数据，最后做了个简化hadoop部署的玩意，其实基本上与大数据没什么关系。总体来说，上半年比较酱油。借原来原来实习公司的需要，我还去了一趟&lt;em&gt;苏州&lt;/em&gt;。&lt;/p&gt;

&lt;p&gt;后来，认识了一个人，莹~。跟她在一起的日子是美好阳光的，还记得第一次见他后第二天给她送的话。我们去了&lt;em&gt;泰山&lt;/em&gt;、&lt;em&gt;青岛&lt;/em&gt;、&lt;em&gt;北戴河&lt;/em&gt;，最后是她的毕业，离开。飞得越高，摔得越痛。西安，见证了一个男孩的泪水。&lt;/p&gt;

&lt;p&gt;暑假在&lt;em&gt;西安&lt;/em&gt;过的，放假前接手了两个项目，北大社团和康jia医疗，都是网页项目，基本上也是赚点生活费而已，只是没有想到这两个项目拖了这么久，就像一个长跑。北大社团网站用的是Python系列软件，这给了我学习实践Python的机会，不得不说Python是一门非常优雅的语言。医疗的项目还是PHP，没太多东西，但还是是给了我很多关于网站、数据库方面的经验。&lt;/p&gt;

&lt;p&gt;下半年主要是负责HTTP2.0优化的验证项目。在研究的过程中了解了Spdy协议、Netty框架，Android编程。以前在做网页转换的时候已经了解了很多HTTP方面的知识，这次更加深刻理解了TCP方面的东西。另外，研究了文档转换技术，利用OpenOffice和JodConvertor实现了一个文档转换工具，并部署给了广州电信。借机去了一趟&lt;em&gt;广州&lt;/em&gt;，飞去飞来的，印象不大。&lt;/p&gt;

&lt;p&gt;总的来说，今年走了很多地方，经历了很深刻的爱情，做了很多杂七杂八的项目。&lt;/p&gt;

&lt;p&gt;对于研究生来说，不能在某方面研究的特别深入，但是如果还不能再做过的东西中进行深化，那一定是失败的。遗留的待补充扩展的是&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;研究一个PHP框架， ThinkPHP&lt;/li&gt;
&lt;li&gt;补充网络方面的只是， 看TCP/IP详解&lt;/li&gt;
&lt;li&gt;刷题。马上就要找实习了，算法是王道。看算法导论，刷OJ&lt;/li&gt;
&lt;/ol&gt;

&lt;hr&gt;

&lt;p&gt;2014年计划
着重 完成补充扩展，加强算法方面的能力， 争取找实习， 然后找到好工作
加强身体锻炼（是个空话么？~~~）
继续寻找机会&lt;/p&gt;

&lt;p&gt;希望一切都好~~~~~&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Hadoop实战：SQL语句转换为hadoop程序</title>
   <link href="http://bupthua.github.io/posts/SQL2Hadoop.html"/>
   <updated>2013-11-17T00:00:00-08:00</updated>
   <id>http://bupthua.github.io/posts/SQL2Hadoop</id>
   <content type="html">&lt;h2&gt;引入&lt;/h2&gt;

&lt;p&gt;大数据很火，很多人都想插一杠子，很多人都买了《Hadoop权威指南》，都看了《Hadoop in Action》，但可能还是没有一个有血有肉的认识，因为实践才能出真知。正好最近参加了一个大数据的比赛，虽然最后可能方法有些问题，但是做完这个题目，对大数据确实有了一个更好的认识。就像提交完成后才老师说的：大数据不过如此。
比赛题目在这里: &lt;a href=&quot;http://note.youdao.com/share/?id=4716c99c69215bd79da3cb74bf5d1584&amp;amp;type=note&quot;&gt;http://note.youdao.com/share/?id=4716c99c69215bd79da3cb74bf5d1584&amp;amp;type=note&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;题目分析&lt;/h2&gt;

&lt;p&gt;题目给出的是一个SQL语句，语义上共分为3不&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;第一步 按照LAC和CI为分组标准，聚合统计部分字段&lt;/li&gt;
&lt;li&gt;第二步 按照intFirstLac和intFirstCi为分组标准，聚合统计两个字段&lt;/li&gt;
&lt;li&gt;第三步 以LAC=intFirstLac和CI=intFirstCi为条件，更新上两部得到的数据，并计算最终的比例&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;题目就是要求我们尽可能快的用大数据的方式进行查询得到结果。我们讨论认为Hbase、Hive或者是impala都是通用性工具，运行效果肯定比不上我们自定义的Hadoop程序，所以我们尝试不使用这些工具，直接用 hdfs和hadoop实现（结果表明这样可能效果并不是很好，这个最后再讨论）。&lt;/p&gt;

&lt;h3&gt;代码思想&lt;/h3&gt;

&lt;p&gt;因为分组标准聚合的标准不同，所以一般认为不能通过一遍扫描统计两个表的字段，但是考虑LAC的取值只能是intFirstLac和intEndLac，CI的取值只能是intFirstCi和intEndCi，所以前两次查询的分组标准有很大联系，在更新的时候也是直接通过两者是否相等来统计的，所以我们总结出一遍扫描来统计所有字段的方法。
对于一条记录，有两种情况：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;LAC=intFirstLac，CI=intFirstCi。这时前两个聚合统计的分组标准一致，所以可以直接统计所有相关字段&lt;/li&gt;
&lt;li&gt;LAC=intEndLac，CI=intEndCi。此时，两次聚合统计的标准不一致，所以应该输出两条结果记录，一条对应于第一个SQL语句，第二个SQL中的字段为0，一条对应于第二个SQL语句，第一个SQL中的字段为0&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;因此，对于每一行数据（包含95个字段），map输出两个&lt;key, value&gt;，第一个对应于第一个sql语句，第二个对应于第二个sql语句，当这两个值的key相同时可以进行合并。最后在combine和reduce的时候累加每个key对应的value字段并得到了最后的统计结果。&lt;/p&gt;

&lt;h3&gt;代码实现&lt;/h3&gt;

&lt;p&gt;因为人比较多，所以各自专注于不同的功能，包括 Java版本、Python版本、Awk程序用于结果分析。这里只分析 Java版本的实现。&lt;/p&gt;

&lt;h5&gt;key&lt;/h5&gt;

&lt;p&gt;Key由LAC和CI作为属性，这里定义了 &lt;code&gt;readFields&lt;/code&gt;和&lt;code&gt;write&lt;/code&gt;方法用于序列化，&lt;code&gt;compareTo&lt;/code&gt;用于比较，定义 &lt;code&gt;equals/hashCode&lt;/code&gt; 保证在比较相等的时候有正确的语义。最后，定义了rawComparator，当比较 key 的时候就可以直接从字符数组比较，而不需要首先解析出对象再比较&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;public class Key implements WritableComparable&amp;lt;Key&amp;gt;{
    int lac, ci;
    public Key(){}
    public Key(int lac, int ci) {
        //...
    }

    public void readFields(DataInput in) throws IOException {
        //...
    }

    public void write(DataOutput out) throws IOException {
        //...
    }

    public int compareTo(Key k) {
        //...
    }

    @Override
    public boolean equals(Object obj){
        //...
    }

    public int hashCode(){
        //..
    }

    public String toString(){
        //...
    }

    public static class Comparator extends WritableComparator{

        public Comparator(){
            super(Key.class);
        }

        @Override
        public int compare(byte[] b1, int s1, int l1, byte[] b2, int s2, int l2) {
            int lac1 = readInt(b1, s1);
            int lac2 = readInt(b2, s2);
            if(lac1 != lac2) return lac1 - lac2;
            int ci1 = readInt(b1, s1 + 4);
            int ci2 = readInt(b2, s2 + 4);
            return ci1 - ci2;
        }
    }

    static{
        WritableComparator.define(Key.class, new Comparator());
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Value&lt;/h4&gt;

&lt;p&gt;Value和Key类似，不过Value有重载了toString方法，用于最后reduce输出的时候调用。所以关于比例的计算可以写在这里。&lt;/p&gt;

&lt;h4&gt;Maper&lt;/h4&gt;

&lt;p&gt;在 hadoop2.x 中counter可以这么使用 &lt;code&gt;context.getCounter(&amp;quot;user_defined&amp;quot;, &amp;quot;ok1&amp;quot;).increment(1);&lt;/code&gt;&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;public class MyMapper extends Mapper&amp;lt;LongWritable, Text, Key, Value&amp;gt; {
    public MyMapper() {
    }

    @Override
    protected void map(LongWritable key, Text value, Context context) throws IOException, InterruptedException {
        // split the fields
        // parse the fields and set to attribute
        // caculate lac and ci
        // if satisfy condition 1, set value1&amp;#39;s field to 1
        // if satisfy condition 2, set value2&amp;#39;s filed to 1
        // if key1 == key2, merge value1 and value2
        // context.write value1/value2
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h4&gt;Conbiner/Reducer&lt;/h4&gt;

&lt;p&gt;需要注意的一点是 Writable是易变的。因为在Value字段中有一个set对象，在readFields时要特别注意，首先要清空这个set，因为Value会被重用。也就是说在reduce的&lt;code&gt;Iterable&amp;lt;Value&amp;gt; vlist&lt;/code&gt;中每一个vlist中的值的对象是同一个，只是值在readFields时被改变。&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;protected void reduce(Key k, Iterable&amp;lt;Value&amp;gt; vlist, Context context){
    // accumulate and write
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>PHP反射API</title>
   <link href="http://bupthua.github.io/posts/Php-Reflecting.html"/>
   <updated>2013-10-30T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Php-Reflecting</id>
   <content type="html">&lt;p&gt;以前没有看PHP手册，在编程的时候遇到了一个问题：如何用字符串变量动态访问对象的属性或者方法。因为对象的概念大多数来自于Java，所以我猜想PHP应该有类似于get的方法，这样才能使用变量来访问吧。但其实这个问题很简单，使用 $obj-&amp;gt;$attr 就行了，可见PHP真的是特别灵活。PHP中也提供了动态调用的系列方法&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_class&lt;/code&gt; 返回类名&lt;/li&gt;
&lt;li&gt;&lt;code&gt;instanceof&lt;/code&gt; &lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_class_methods&lt;/code&gt;。可以用 &lt;code&gt;in_array($method, get_class_methods($obj))&lt;/code&gt; 来监测对象是否有$method方法&lt;/li&gt;
&lt;li&gt;&lt;code&gt;is_callable/method_exists&lt;/code&gt;。区别在于方法存在，如果是private也不能调用&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_class_vars&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_parent_class/is_subclass_of&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;call_user_func/call_user_func_array&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;除了上述方法外，PHP也完全支持类似于Java的反射机制。反射API中的部分类： &lt;code&gt;Reflection, ReflectionClass, ReflectionMethod, ReflectionParameter, ReflectionFunction&lt;/code&gt; ……反射在模板的使用中肯定是挺多的。一个例子如下&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;/*
创建一个类类动态加载Module对象。所有Module的子类必须实现execute方法。可以允许用户在XML配置文件中列出所有的Module类，系统使用配置加载这些类然后执行execute
子类可以提供setter方法并在配置中配置属性
*/
class Person {
    public $name;
    function __construct($name){
        $this-&amp;gt;name = $name;
    }
}

interface Module{
    function execute();
}

class FtpModule implements Module{
    function setHost($host){
        print &amp;quot;FtpModule::setHost（）：$host\n&amp;quot;;
    }

    function setUser($user){
    }

    function execute(){
        //....
    }
}

class PersonModule implements Module{
    function setPerson(Person $person){
        //...
    }
    function execute(){
        //...
    }
}

class ModuleRunner{
    private $config = array(
        &amp;quot;PersonModule&amp;quot; =&amp;gt; array(&amp;quot;person&amp;quot; =&amp;gt; &amp;quot;bob&amp;quot;),
        &amp;quot;FtpModule&amp;quot; =&amp;gt; array(&amp;quot;host&amp;quot; =&amp;gt; &amp;quot;127.0.0.1&amp;quot;, &amp;quot;user&amp;quot; =&amp;gt; &amp;quot;admin&amp;quot;)
    );
    private $modules = array();

    function init(){
        $inteface = new ReflectionClass(&amp;#39;Module&amp;#39;);
        foreach($config as $moduleName =&amp;gt; $params){
            $moduleClass = new ReflectionClass($moduleName);
            if(!$moduleClass-&amp;gt;isSubclassOf($interface)){
                throw new Exception(&amp;quot;Unknown module type: $moduleName&amp;quot;);
            }
            $module = $moduleClass-&amp;gt;newInstance();
            foreach($moduleClass-&amp;gt;getMethods() as $method){
                $this-&amp;gt;handleMethod($module, $method, $params);
            }
            array_push($modules, $module);
        }
    }

    function handleMethod(Module $module, ReflactionMethod $method, $params){
        $name = $method-&amp;gt;getName();
        $args = $method-&amp;gt;getParameters();
        if(count($args) != 1 || substr($name, 0, 3) != &amp;#39;set&amp;#39;){
            return false;
        }

        $property = strtolower(substr($name, 3));
        if(!isset($params[$property])){
            return false;
        }

        $argClass = $args[0]-&amp;gt;getClass();
        if(empty($argClass)){
            $method-&amp;gt;invoke($module, $params[$property]);
        }
        else{
            $method-&amp;gt;invoke($module, $argClass-&amp;gt;newInstance($params[$property]));
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;</content>
 </entry>
 
 <entry>
   <title>PHP手册拾遗1</title>
   <link href="http://bupthua.github.io/posts/Php-Manual1.html"/>
   <updated>2013-10-24T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Php-Manual1</id>
   <content type="html">&lt;ul&gt;
&lt;li&gt;将对象转换为array时结果为数组，属性名为键。不过有几点例外：整数属性不可访问；私有变量前会加上类名作前缀；保护变量前会加上一个 &amp;#39;*&amp;#39; 做前缀。这些前缀的前后都各有一个 NULL 字符。这会导致一些不可预知的行为（实验证明private和protect的索引变了，所以最好还是不要引用吧）&lt;/li&gt;
&lt;li&gt;array_map也可以像python中的map一样把函数作用于数组&lt;/li&gt;
&lt;li&gt;如果常量名是动态的，也可以用函数 constant() 来获取常量的值&lt;/li&gt;
&lt;li&gt;运算符优先级：new &amp;gt; [ &amp;gt; 类型转换， 为什么不能写 new Obj()-&amp;gt;func(), 加括号都不行 (new Obj())-&amp;gt;func()&lt;/li&gt;
&lt;li&gt;isset 的含义是检测变量是否设置，并且不是 NULL。与empty区别&lt;/li&gt;
&lt;li&gt;&lt;p&gt;直接改变数组的值自 PHP 5 起可以通过引用传递来做到。之前的版本需要需要采取变通的方法：&lt;/p&gt;

&lt;p&gt;Example #10 在循环中改变单元&lt;/p&gt;

&lt;p&gt;&amp;lt;?php
// PHP 5
foreach ($colors as &amp;amp;$color) {
    $color = strtoupper($color);
}
unset($color); /* ensure that following writes to
$color will not modify the last array element */&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;
</content>
 </entry>
 
 <entry>
   <title>你好，PHP</title>
   <link href="http://bupthua.github.io/posts/Hello.html"/>
   <updated>2013-10-23T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/Hello</id>
   <content type="html">&lt;p&gt;最近做了一个决定，选择PHP作为深入研究的目标。总结一下自己这几年来的开发，不知道怎么搞的，都与网页扯上了关系。  &lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;2011年 Etao.Beijing 做了一个开发统计工具，使用了PHP和YII框架&lt;/li&gt;
&lt;li&gt;2012年 实验室毕设 视频会议&lt;/li&gt;
&lt;li&gt;2012年 德讯潮泰 使用PHP搭建了营销助手&lt;/li&gt;
&lt;li&gt;2012年 德迅潮泰 尝试开发网页转换工具，详细探索了网页的方方面面。&lt;/li&gt;
&lt;li&gt;2012年 IBM 开发代码依赖和patch工具&lt;/li&gt;
&lt;li&gt;2013年 开发HealthEpoch 使用PHP和ThinkPHP框架&lt;/li&gt;
&lt;li&gt;2013年 维护北大社团管理 使用Python和webpy/sqlalchemy&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;这些项目中，与网页相关的居多，使用过PHP、JSP、SSH和Python，但自我感觉开发网页最方便的还是PHP。PHP入手容易，调试方便，随时都可以输出，随时都可以终止，用起来得心应手。另外PHP的语法与C特别相似，这对于从C/C++出发的人来说格外友好。另外再辅以PHP的各种框架，开发过程就变得容易。但是因为上手比较容易，灵活性大也带来结构比较松散，代码维护成本较大，要写出高质量的代码依然是一个挑战。另外网页涉及的方面特别多，需要学习的地方也特别多，所以学习PHP的过程，绝不仅仅是PHP，是对系统、软件、算法、经验的综合考量。&lt;/p&gt;

&lt;p&gt;最近在实验室做Http优化的项目，顺带维护几个网站，整个人很忙乱，但是感觉自己对自己没有一个规划，每天没有进步，思前想后，便有了今天这个博客和这篇博文——踏上PHP的学习之路。接下来的日子我将从 PHP本身、PHP框架、数据库、几个开源软件、算法、编程模式、编程思想等几个方面进行学习。这个博客将记录我的学习和成长。博客只是个写东西的地方，我不希望花太多时间去折腾，基本看懂了github page这个系统的运作，抄袭了&lt;a href=&quot;http://kylexlau.github.io&quot;&gt;kylexlau&lt;/a&gt;的风格，希望不会介意，我觉得这个模板特别简洁，而且有分类等基本功能。Markdown语法参考 &lt;a href=&quot;http://wowubuntu.com/markdown/&quot;&gt;http://wowubuntu.com/markdown/&lt;/a&gt;&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>一个python的随机字符串发生器</title>
   <link href="http://bupthua.github.io/posts/A-Random-String-Gendertor-In-Python.html"/>
   <updated>2013-10-23T00:00:00-07:00</updated>
   <id>http://bupthua.github.io/posts/A-Random-String-Gendertor-In-Python</id>
   <content type="html">&lt;p&gt;不得不承认Python语言是一种很优雅的语言。那次我在网上搜了下如何获取随机字符串，有很多种方法，但是有这么一句话深深的吸引了我：&lt;/p&gt;
&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;text language-text&quot; data-lang=&quot;text&quot;&gt;&amp;#39;&amp;#39;.join(map(lambda xx:(hex(ord(xx))[2:]),os.urandom(3)))
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;这里面的每个单词我都认识，但几乎每个单词都需要help，一个一个来&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;os.urandom: Return a string of n random bytes suitable for cryptographic use&lt;/li&gt;
&lt;li&gt;ord:  Return the integer ordinal of a one-character string&lt;/li&gt;
&lt;li&gt;hex: Return the hexadecimal representation of an integer or long integer&lt;/li&gt;
&lt;li&gt;lambda:  a shorthand to create anonymous functions&lt;/li&gt;
&lt;li&gt;map: Return a list of the results of applying the function to the items of the argument sequence(s).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;所以这个函数的意思就是： 对于os.urandom产生的每一个字符， 把他们用十六进制表示的字符串（不含0x）连接起来。比如如果 os.urandom(3)产生了&amp;#39;abc&amp;#39;, 因为 ord(&amp;#39;a&amp;#39;) = 97 = 0x61， 所以最后得到的是 616263。 &lt;/p&gt;

&lt;p&gt;最后，这个函数产生的随机数位数是不固定的，虽然这个函数很酷，还是要少用，不易阅读，不过用来学习Python最好不过了.&lt;/p&gt;
</content>
 </entry>
 

</feed>
