-
Notifications
You must be signed in to change notification settings - Fork 2
/
atom.xml
3681 lines (2986 loc) · 205 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[Chouqin's Blog]]></title>
<link href="http://chouqin.github.io/atom.xml" rel="self"/>
<link href="http://chouqin.github.io/"/>
<updated>2015-01-06T11:23:11+08:00</updated>
<id>http://chouqin.github.io/</id>
<author>
<name><![CDATA[chouqin]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[2014年终总结]]></title>
<link href="http://chouqin.github.io/blog/2014/12/31/2014-summary/"/>
<updated>2014-12-31T18:13:00+08:00</updated>
<id>http://chouqin.github.io/blog/2014/12/31/2014-summary</id>
<content type="html"><![CDATA[<p>2014年算是过得比较充实的一年,看了比较多的书和论文,
也沉下心来写过一些代码,在专业方面还是有不少的积累。
另外,在性格方面,也慢慢改变了一些自己的缺点,
虽然还需要继续努力~。</p>
<h2 id="section">计划的完成程度</h2>
<blockquote>
<p>修身仍旧还是第一位,而且必须要花一定的时间。</p>
</blockquote>
<p>这个感觉完成得并不是很好,不过需要慢慢来,
多反省,多总结就好。</p>
<blockquote>
<p>多看书,多看非专业书。</p>
</blockquote>
<p>看的书还挺多的,待会再慢慢总结。</p>
<blockquote>
<p>看完Graphlab和Spark的源码, 期间需要巩固C++和学习Scala。</p>
</blockquote>
<p>Spark的源码看了大部分,了解代码的基本结构,
知道每一个功能的实现大概在什么位置。一直在跟进社区的Pull Request,
在研究Spark上面花了不少的时间,坚持下来有不少的收获。这一点明年继续保持。
Scala也在读Spark源码过程中不断熟悉,现在看Spark的源码不会有不理解的地方了。</p>
<p>至于Graphlab,完全没看。。</p>
<blockquote>
<p>上完Convex Optimization、Probabilistic Graphical Models
和Neural Networks for Machine Learning这三门在线课程。</p>
</blockquote>
<p>Convex Optimization比较圆满的完成了,看完了整本书,
同时顺便看了ADMM的那篇比较长的论文,Boyd老师真是大师,
讲课非常幽默,听完他的课之后对于优化这方面算是有了一个整体的框架,
了解了解决优化问题的思考方式。</p>
<p>另外两门课程没有参加,不过已经放在2015年的目标里了。</p>
<blockquote>
<p>在github上为开源项目提交代码。</p>
</blockquote>
<p>今年给Spark提交过几个patch,主要是和MLlib里面的决策树相关。</p>
<p>整体来说,2014年的计划完成了60%吧,由于完成了计划之外的一些事情。</p>
<h2 id="section-1">看完的书</h2>
<h3 id="section-2">计算机方面的</h3>
<ol>
<li>《Effective C++》: 想写好C++程序的必读书籍,
看完里面的建议能够避免一些初学者易犯的错误。
读起来并不难,关键需要在实际写代码的过程中去使用这些建议。</li>
<li>《Unix编程艺术》:整本书的中心思想就两个字:简单。
通过简单的方式去实现程序,将程序拆分成简单的低耦合的模块。
这是一本关于“知识”,更关注于“思想”; 关于“方法”,更关注于“理念”的书。 整本书都是在讲述在UNIX哲学中如何设计软件, 如何使用工具,如何看待各种技术, 这是一本教你如何从UNIX的视角去看待问题的书。
且不说这里面的观点正确与否, 它确实能够给你提供一个看待问题的新的思路。 而且UNIX文化和哲学中拥有许多值得去领悟的精华。 看这本书一点都不觉得沉闷,每一个观点都能够引发我思考, 结合自己的经历得出新的感悟和体会。 书中的代码虽然不多,却能够教你如何编程, 而大量的软件实例分析又像一个个路标, 指出设计中的陷阱和正确的方向。</li>
<li>《统计学习方法》:虽然只有一些简单的机器学习算法,
但是里面的公式推导还是比较好理解的。对于入门来说,这样一本中文的图书真的很有帮助。</li>
<li>《多处理器编程的艺术》:这本书开阔了我对于写并发程序的看法,通过一个个并发数据结构的例子,
可以学习到编写“无锁”程序的技巧。为了写好并发的程序,需要对于底层的体系结构有一定的了解。
书中第3章有一些理论部分没有认真地看过。</li>
<li>《计算机程序的构造和解释》:非常经典的一本书,
通过这本书可以体会到函数式编程的优雅。</li>
<li>《编程人生》:英文名叫《Coders at Worker》,对于国外10多个优秀程序员的采访,
从这些人身上可以学习到程序设计的技巧和思考问题的方式。</li>
<li>《Convex Optimization》:虽然整本书超过700页,但是理解起来并不困难,只要掌握微积分和线性代数即可。
看完整本书,结合对应的课程讲解,有一种豁然开朗的感觉。</li>
<li>《Masterminds of Programming》: 采访了一些语言的作者,看完了对于C#的作者和Haskell作者的采访,
感觉一门语言能够支持EDSL很重要。</li>
<li>《人月神话》:本书描述的是作者在上个实际60年代管理大型软件工程项目的一些经验和看法,
这些观点拿到现在来看也仍然没有过时。</li>
</ol>
<h3 id="section-3">非计算机的</h3>
<ol>
<li>《史玉柱》:一本史玉柱自述的关于营销的书,观点都很实在,很接地气。</li>
<li>《信息简史》:这本书和计算机也有一定的关系,讲述信息相关的各个方面,
介绍信息技术发展从古到今的一些科技成果,令人大开眼界。</li>
<li>《The Elements of Style》: 讲述如何用英语进行写作的书,非常薄的一本书(才100多页),
对于如何使用词语、标点符号和如何组织段落等都有一些很好的建议。</li>
<li>《自控力》:标题像鸡汤,其实是关于如何认识大脑中的三种不同的力量,
以及如何使用它们来达到自控的效果。书中的一些案例让我感同身受,
照着书中的建议去做确实能起到不错的效果。</li>
<li>《周鸿祎》:看过的最差的书之一,里面提到的有用的观点很少,
大部分是对于360的自我标榜,重复的废话太多,根本不值得用一本书来讲述。</li>
<li>《文明之光》:有点科技史的感觉,没有《浪潮之巅》和《数学之美》有趣,
不知道是不是个人兴趣的问题。</li>
<li>《失控》:看完了前面3章,讲述如何真正地实现机器的智能,
使用群体的智慧。</li>
</ol>
<h2 id="section-4">计划之外</h2>
<h3 id="llvm">LLVM</h3>
<p>今年选了一门外教上的高级编译技术的课程。
课程主要完成对LLVM进行扩展,让它能够支持使用并行机器指令完成长整数的运算。
在整个过程中,我看完了LLVM官网上的所有文档,整个代码也看了很多,
后端从LLVM IR到最终生成机器码的整个过程算是了解得比较清楚。
最终大致得完成了整个项目,还发现了LLVM里面的一些bug。
LLVM的代码写得还不错,是我看过的写得最好的C++代码之一。
唯一不足的是除了官方的文档,其他人写得关于LLVM的文章很少,
不管是关于实现还是使用的。学这门课最主要的还是锻炼了我的英语口语:D。</p>
<h3 id="haskell">Haskell的课程</h3>
<p>今年在Edx上学习了一门FP101的课程,比较基础地学习了Haskell,
Haskell确实和我见过的程序设计语言不一样,它主张使用各种抽象来达到代码的复用。
其中,最难以理解的就是Monad这个概念,当时花了很长时间才明白Monad是什么,
而后通过Monad实现CPS让我不住惊叹于它的强大。现在,仍然不敢说已经完全理解Monad,
以后还需要多多使用来加深对它的理解。它能够给你一个全新的写程序的角度。另外,
Haskell的类型系统真的很强大,当时在没有完全理解CPS的情况下可以依靠类型系统的提示写出正确的程序。</p>
<h3 id="section-5">一些论文</h3>
<p>今年看了不少的论文(相对于以前来说),主要是和机器学习相关的,
看完这些论文除了让我对论文中描述的技术有更深入的理解之外,
更重要的是让我学会了一些看论文的方法,以及不再害怕阅读论文的能力。</p>
<h3 id="section-6">学车</h3>
<p>虽然2014年最后一天的科目三没有通过,稍稍有点遗憾,
但是整个学车的过程还是让我成长了很多。
我克服了自己内心的恐惧,勇敢地走出自己的舒适区,
在一个自己非常不擅长的领域努力并取得了一定的成功。
学车整个的过程确实让我的内心变得更加强大,我也不断地弥补了一些自己性格上的弱势。
现在离最终拿到驾照还有很长的一段路要走,但是我相信我一定会成功的。</p>
<h2 id="section-7">2015年计划</h2>
<ol>
<li>拿到驾照,顺便锻炼自己强大的内心。</li>
<li>学习go,深入了解Docker及相关的技术。</li>
<li>机器学习方面,看完ESL和PRML(或者MLAPP),学习落下的课程。</li>
<li>多看书,多看和专业无关的书。</li>
<li>跟进Spark的进展,争取在这方面能够有所建树。</li>
<li>看完parameter_server或者petuum的源码。</li>
</ol>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[《人月神话》读书心得]]></title>
<link href="http://chouqin.github.io/blog/2014/12/15/the-mythical-man-month/"/>
<updated>2014-12-15T15:32:00+08:00</updated>
<id>http://chouqin.github.io/blog/2014/12/15/the-mythical-man-month</id>
<content type="html"><![CDATA[<p>花几天的时间读完了《人月神话》这本软件工程领域的经典书籍。
本书并不厚,作者的文笔很好,讲述一个观点时能够解释得非常清楚,
翻译得也很不错,没有给理解带来障碍。
书中描述的是作者在上个实际60年代管理大型软件工程项目的一些经验和看法,
可是这些观点拿到现在来看也仍然没有过时。
我在此总结一些我比较有体会的观点,并谈谈我的一些体会。</p>
<h2 id="section">人月神话</h2>
<p>首先是和书名对应的这个观点——“人月神话”,
意思是说尽管一个项目的工作量可以用人月来衡量,
但是“人”和“月”这两个量度并不是可以互换的,
也就是说不能通过增加更多的人手来减少项目完成所需要的时间。
这主要是由于两方面的原因:</p>
<ul>
<li>有些任务由于次序上的限制不能分解,
也就是说不能把一个任务分给两个人来做来减少一半的时间。</li>
<li>增加了一个人员就增加了培训和交流的成本。</li>
</ul>
<p>因此,作者提出了Brooks法则:</p>
<blockquote>
<p>向进度落后的项目中增加人手,只会使进度更加落后。</p>
</blockquote>
<p>这就是除去了神话色彩的人月。</p>
<h2 id="section-1">概念完整性</h2>
<p>概念完整性是指整个系统的设计具有一致性,系统只反应唯一的设计理念。
这要求系统的设计必须由一个人,或者非常少数互有默契的人员来实现。
在本书中,作者希望按照“外科手术队伍”的形式来组织团队,
团队的首席程序员类似于外科手术队伍的医生,他定义系统的功能,
设计程序,编制源代码,其他的人员负责给首席程序员提供必要的帮助。
或者,可以对设计方法和具体实现进行分工,
由架构师来完成设计,制定好技术说明,而实现人员负责实现。</p>
<p>概念完整性是如此重要,我所知的成功的软件项目都是反应了一两个天才程序员的理念,
由他们来决定整个项目的走向。</p>
<h2 id="section-2">没有银弹</h2>
<p>这是本书中一个颇具争议的观点:</p>
<blockquote>
<p>在未来十年内,无论是在技术还是管理方法上,
都看不出有任何突破性的进步,
能够独立保证在十年内大幅度地提高软件的生产率、可靠性和简洁性。</p>
</blockquote>
<p>首先,作者把软件项目的开发过程分为两部分:</p>
<ul>
<li>根本任务,打造构成抽象软件的复杂概念结构,我理解就是完成软件的设计。</li>
<li>次要任务,使用编程语言表达这些抽象实体,也就是完成实现。</li>
</ul>
<p>作者认为,现在的技术或管理方法的革新,只能改进次要任务的生产率,
而根本任务的难度并没有发生改变。这样,除非次要任务能够占到所有工作的9/10以上,
否则总体的生产率不会有数量级的提升。</p>
<p>那为什么根本任务的生产率无法提高呢?这是由于开发软件系统需要面对这些无法规避的问题:</p>
<ul>
<li>
<p>复杂度。一个软件系统有大量的状态,存在大量不同元素的相互叠加。
这使得软件系统的复杂性以指数的形式增长。而且,这些复杂度是软件系统的根本属性,
而不像数学和物理中那样可以建立简化的模型而忽略复杂的次要因素。</p>
</li>
<li>
<p>一致性。复杂度的问题不只是软件工程师才会面对,物理学家也会面临复杂度的问题。
但是他们相信能够建立一个通用的理论将这些复杂性统一起来,因为整个宇宙的规律是由上帝创造的,
而上帝不是反复无常的。而软件工程师需要控制的复杂度是随心所欲,毫无规律可言的,
需要遵循人为惯例和系统约束,需要和这些系统保持一致。
(可以这样理解,这些复杂度是由不同的PM带来的,我没有黑PM啊。。)</p>
</li>
<li>
<p>可变性。有两个因素导致软件需要经常发生变化,
一是软件系统改变的容易性使得有更多改变的需求(PM说,不就是改两行代码吗?
他绝不会轻易让人去改装一辆生产好的汽车);二是软件的寄主(操作系统,硬件)经常发生变化,
使得软件需要改变。</p>
</li>
<li>
<p>不可见性。这一点我不是很理解,可能随着图形界面的提出,
软件的可见性能够得到很大程度的改善吧。</p>
</li>
</ul>
<p>似乎,作者提出的这些问题40年后仍然没有得到解决,
对抗软件复杂性和可变性一个比较好的方式是快速原型,然后不断迭代。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[2013年终总结]]></title>
<link href="http://chouqin.github.io/blog/2013/12/31/2013-summary/"/>
<updated>2013-12-31T21:56:00+08:00</updated>
<id>http://chouqin.github.io/blog/2013/12/31/2013-summary</id>
<content type="html"><![CDATA[<p>还是踩着年末的尾巴发一篇年终总结吧。</p>
<p>2013对我来说不是平淡的一年。
这一年,我大学毕业,从一所大学来到另外一所大学,
分别原来的同学和朋友,
又在新的地方建立起了人际关系网;
这一年,我从大学生变成了研究生,
伴随着学历的增长,我的生活节奏也完全发生变化,
现在的我,开始沉下心来学习一些东西,
虽然现在仍然没有很大的成果。
这一年,我和她吵了不知道多少次架,
每次都是因我而起,我心里十分愧疚,
我现在仍然不够成熟,
心胸不够开阔。</p>
<h2 id="section">计划的完成程度</h2>
<blockquote>
<p>多看书,多感受生活,开阔自己的胸襟</p>
</blockquote>
<p>虽然这被放在了计划的第一条,但是完成的最不好。
这里的“看书”,当然是说非专业的书籍,
印象当中就看了《天龙八部》和《唐浩明评点曾国藩家书》(上下册),
家书下册还是这两天逼迫自己看完的,
看书之少,现在都替自己不好意思。</p>
<p>至于修身,也没有花多少功夫,
否则也不至于跟女朋友吵那么多架。
没有把这个放在比较重要的位置,
仍然还是我行我素,
只知道在专业方面努力,
其他方面都不在乎。
这一点,在来年必须要改。</p>
<blockquote>
<p>学习一门新的编程语言,可能是go或者erlang</p>
</blockquote>
<p>也完成的不是很好,大概的学习了一下go(完成了go tour),
没有用它写过实际的项目。</p>
<blockquote>
<p>学完完有关数据挖掘的基础知识</p>
</blockquote>
<p>这个完成得还不错,
掌握了很多的机器学习和数据挖掘方面的基础知识。
完成了毕业设计,使用scikit-learn开发过机器学习程序,
写了很多实现机器学习算法的matlab代码。
上了两门机器学习的课程,一门是浙大蔡登老师上的,
另一门是Coursera上的。</p>
<blockquote>
<p>为github上的一个库提交代码</p>
</blockquote>
<p>为<a href="https://github.com/easychen/TeamToy-Plugins">TeamToy-Plugin</a>这个项目写了两个插件,
一个是OpenId的,一个是创意墙(团队用户可以在上面分享创意,使用类似于Hacknews的排序,
这个插件没有提交)。</p>
<p>这个计划完成程度也不是很满意,投入的时间太少了。</p>
<h2 id="section-1">计划之外</h2>
<h3 id="section-2">专业书</h3>
<p>2013年在专业方面的投入还是蛮多的,
看过的书不能算少,也不能算多:</p>
<ol>
<li>
<p>《The C Programming Language》,这仅仅只有200多页的书,
除了让我知道如何写出好的C程序之外,
也让我明白了如何如何精简地表达自己的观点。</p>
</li>
<li>
<p>《The CPP Programming Language》,以前一直对这本书持保留看法,
觉得这么厚的一本书一定晦涩难懂,
直到我认认真真地把整本书都看了一遍,
才发现这是一本不可多得的好书。
整本书讲解清晰,
把C++这么复杂的一门语言的语言特性阐释得十分清楚,
而且,里面还有很多如何写出更好的程序的技巧,
很多时候作者的很多思想会引起我强烈的共鸣,
或者启发我深度的思考。</p>
</li>
<li>
<p>《Introduction to Data Mining》,
这本书总体感觉是介绍性质的,里面设计的理论不是很深,
数学讲解不是很多,不过能从中知道数据挖掘的各个方面。
可能Jiawei Han老师的那本数据挖掘更好一些。</p>
</li>
<li>
<p>《Pattern Classification》,
这本书是上机器学习课程的主要教材,
里面的理论讲得很深,
是一本比较好的参考书。</p>
</li>
<li>
<p>《The Practice of Programming》,
看这本书,完全是冲着Robert Pike的大名去的,
看完之后果然不失所望,
学到了很多的编程方法,
只是这本书的评注实在让人哭笑不得。</p>
</li>
<li>
<p>《Effective Java》,
这本书看的是中文版,
翻译得不是很好,
有少数几个地方有点难以理解。
由于以前写的Java程序太少,
看完这本书之后收益还是蛮大的,
至少现在知道怎么去写Java程序了,
同时对于面向对象的特性也有了更加深入的理解。</p>
</li>
</ol>
<p>应该说,今年看书确实比以往有所长进,
因为看完书之后能够对它进行总结,
其中一些重要的观点和思想都记录下来,
而不是看完就忘记了。
我觉得这是一种很好的看书方法,
看书不应该一味的追求速度,
看完之后的总结很有必要。</p>
<h3 id="coding">Coding</h3>
<p>2013年写过的代码不能算多,写的代码是PHP和Python,
但是有时候也看一些其它语言的书和文章,
然后拿着这些特性来进行一个比较,
想得比较多。同时,
有时需要写一些代码来测试一些有趣的语言特性,
这些代码可以作为以后的参考。</p>
<p>同时,今年看了几个开源项目的代码,
包括scrapy和redis,
看这些代码一方面能够开阔自己的视野,
另一方面对于如何写程序也能够有所体会。</p>
<h3 id="paper">Paper</h3>
<p>2013年也看过一些论文,
包括google的三大论文,
还有graphlab的4篇论文,
Spark的两篇论文。
对于后面的两种论文,
现在理解还不是很深入,
幸亏存在开源的代码能够加深理解。</p>
<p>在机器学习方面也看过一些论文,
其中推荐系统和聚类方面的论文看得比较多。</p>
<h2 id="section-3">2014年计划</h2>
<ol>
<li>修身仍旧还是第一位,而且必须要花一定的时间。</li>
<li>多看书,多看非专业书。</li>
<li>看完Graphlab和Spark的源码, 期间需要巩固C++和学习Scala。</li>
<li>上完Convex Optimization、Probabilistic Graphical Models
和Neural Networks for Machine Learning这三门在线课程。</li>
<li>在github上为开源项目提交代码。</li>
</ol>
<p>祝愿所有人新年快乐,新的一年实现自己的梦想。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Bigtable 学习心得]]></title>
<link href="http://chouqin.github.io/blog/2013/10/24/bigtable/"/>
<updated>2013-10-24T20:49:00+08:00</updated>
<id>http://chouqin.github.io/blog/2013/10/24/bigtable</id>
<content type="html"><![CDATA[<h2 id="section">基本介绍</h2>
<p>Bigtable是一个分布式的数据库,
它的出现主要是因为传统的关系型数据库在面对大量数据(PB级别)时不具有扩展性。
Bigtable在谷歌内部得到了广泛使用,
<a href="http://hbase.apache.org/">Apache HBase</a>是它的开源实现。</p>
<h3 id="section-1">数据格式</h3>
<p>可以把一个Bigtable当成一个持久化的,分布式的,多维的map。
它的值通过<code>(rowkey, columnkey, timestamp)</code>来索引。
其中<code>rowkey</code>,<code>columnkey</code>和值都可以是任意的字符串。
如下图所示。</p>
<p><img src="http://chouqin.github.io/images/row_column.jpg" alt="Bigtable数据示意图" /></p>
<p>在上图中,<code>rowkey</code>是<code>com.cnn.www</code>。
在Bigtable中,对row的操作是原子(atomic)的。
在Bigtable中,数据的保存顺序是通过<code>rowkey</code>的字典序来维持的,
基于这个特点,可以通过挑选合适的<code>rowkey</code>把相关的数据放在一起。
比如上图,通过使用倒序的主机名作为<code>rowkey</code>,
可以把同一域名下的网页放在一起。
几个row组合起来形成一个tablet,
一个table由一个或多个tablet组成。</p>
<p><code>columnkey</code>通过<code>column family</code>来进行划分,
如上图,anchor就是一个<code>column family</code>,它有两个<code>column key</code>:
<code>anchor:cnnsi.com</code>和<code>anchor:my.look.cn</code>。
contents也是一个<code>column family</code>, 它只有一个<code>column key</code>,
就是<code>contents:</code>。<code>column family</code>是访问控制的基本单位。
每一个<code>column key</code>必须以<code>column family:qualifier</code>的格式命名。</p>
<p>对于同一个<code>rowkey</code>和<code>columnkey</code>的组合,
Bigtable根据不同的<code>timestamp</code>保存了不同的值。
通常,会保存最近的几个版本(具体的版本数用户可以指定),
过期的数据会被垃圾回收掉。</p>
<h3 id="api">API</h3>
<p>Bigtable的API非常简单,下面是两个使用API的例子: </p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span>写Bigtable</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
</pre></td><td class="code"><pre><code class="cpp"><span class="line"><span class="c1">// Open the table</span>
</span><span class="line"><span class="n">Table</span> <span class="o">*</span><span class="n">T</span> <span class="o">=</span> <span class="n">OpenOrDie</span><span class="p">(</span><span class="s">"/bigtable/web/webtable"</span><span class="p">);</span>
</span><span class="line"><span class="c1">// Write a new anchor and delete an old anchor</span>
</span><span class="line"><span class="n">RowMutation</span> <span class="n">r1</span><span class="p">(</span><span class="n">T</span><span class="p">,</span> <span class="s">"com.cnn.www"</span><span class="p">);</span>
</span><span class="line"><span class="n">r1</span><span class="p">.</span><span class="n">Set</span><span class="p">(</span><span class="s">"anchor:www.c-span.org"</span><span class="p">,</span> <span class="s">"CNN"</span><span class="p">);</span>
</span><span class="line"><span class="n">r1</span><span class="p">.</span><span class="n">Delete</span><span class="p">(</span><span class="s">"anchor:www.abc.com"</span><span class="p">);</span>
</span><span class="line"><span class="n">Operation</span> <span class="n">op</span><span class="p">;</span>
</span><span class="line"><span class="n">Apply</span><span class="p">(</span><span class="o">&</span><span class="n">op</span><span class="p">,</span> <span class="o">&</span><span class="n">r1</span><span class="p">);</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>上面的代码段对<code>rowkey="com.cnn.www"</code>的行,
将<code>columnkey="anchor:www.c-span.org"</code>的列的值设置为<code>CNN</code>,
同时删除<code>columnkey = "anchor:www.abc.com"</code>的列。其中<code>Apply()</code>是原子操作。</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span>读Bigtable</span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
</pre></td><td class="code"><pre><code class="cpp"><span class="line"><span class="n">Scanner</span> <span class="n">scanner</span><span class="p">(</span><span class="n">T</span><span class="p">);</span>
</span><span class="line"><span class="n">ScanStream</span> <span class="o">*</span><span class="n">stream</span><span class="p">;</span>
</span><span class="line"><span class="n">stream</span> <span class="o">=</span> <span class="n">scanner</span><span class="p">.</span><span class="n">FetchColumnFamily</span><span class="p">(</span><span class="s">"anchor"</span><span class="p">);</span>
</span><span class="line"><span class="n">stream</span><span class="o">-></span><span class="n">SetReturnAllVersions</span><span class="p">();</span>
</span><span class="line"><span class="n">scanner</span><span class="p">.</span><span class="n">Lookup</span><span class="p">(</span><span class="s">"com.cnn.www"</span><span class="p">);</span>
</span><span class="line"><span class="k">for</span> <span class="p">(;</span> <span class="o">!</span><span class="n">stream</span><span class="o">-></span><span class="n">Done</span><span class="p">();</span> <span class="n">stream</span><span class="o">-></span><span class="n">Next</span><span class="p">())</span> <span class="p">{</span>
</span><span class="line"> <span class="n">printf</span><span class="p">(</span><span class="s">"%s %s %lld %s</span><span class="se">\n</span><span class="s">"</span><span class="p">,</span>
</span><span class="line"> <span class="n">scanner</span><span class="p">.</span><span class="n">RowName</span><span class="p">(),</span>
</span><span class="line"> <span class="n">stream</span><span class="o">-></span><span class="n">ColumnName</span><span class="p">(),</span>
</span><span class="line"> <span class="n">stream</span><span class="o">-></span><span class="n">MicroTimestamp</span><span class="p">(),</span>
</span><span class="line"> <span class="n">stream</span><span class="o">-></span><span class="n">Value</span><span class="p">());</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>上面的代码段遍历<code>rowkey="com.cnn.www"</code>的行中<code>column family="anchor"</code>的所有列的所有版本。</p>
<h2 id="section-2">实现</h2>
<p>Bigtable使用了几个部件构建而成:</p>
<ul>
<li>GFS,Bigtable的底层依赖GFS,它使用GFS来保存数据和commit log,马上就会讲述细节。</li>
<li>
<p>Chubby,是Google发布的另外一个分布式系统,它具体的原理我还没有去看那篇论文,
现在只需要知道Bigtable使用Chubby来完成下面的事情:</p>
<ul>
<li>保证任何时候只有一个bigtable master server</li>
<li>存放Bigtable最开始的数据,用于定位METADATA,接下来会看到。</li>
<li>用于监控tablet server的状态</li>
<li>存放schema</li>
<li>存放ACL(access control list)</li>
</ul>
<p>Chubby对于Bigtable非常重要,如果它停止工作了,
那么整个Bigtable也停止工作。
Chubby的开源实现是<a href="http://zookeeper.apache.org/">ZooKeeper</a>,
下次再来研究Chubby。</p>
</li>
</ul>
<h3 id="section-3">组成部分</h3>
<p>和GFS类似,Bigtable也由三个部分组成,分别是:</p>
<ul>
<li>client:用于和应用程序交互</li>
<li>一个master: 管理整个系统,要做的工作包括分配tablet,
负载均衡,垃圾回收,处理schema的变化。</li>
<li>很多的tablet server:一个tablet server负责多个tablet,
client对于tablet的读写请求直接与tablet server进行交互。</li>
</ul>
<p>需要注意的是,与GFS不一样,
关于tablet的位置信息client不需要通过master就可以知道(接下来就会提到),
所以大部分情况下client都不需要和master交互,
这样master上的压力更小了。</p>
<h3 id="tablet">Tablet的位置</h3>
<p>Bigtable使用一个三层的结构来存放tablet的位置,
如下图所示。(论文上说这个和B+树比较像,
我倒觉得用inode来类比更加好理解)</p>
<p><img src="http://chouqin.github.io/images/tablet_location_hierarchy.png" alt="" /></p>
<p>首先,一个Chubby File保存了root tablet的位置。
root tablet是一个特殊的METADATA table,
它保存了所有其他METADATA tablet的位置。
每一个METADATA又保存了user tablet的位置。
所以,顺着这个结构走下来,就能找到任意的tablet的位置。</p>
<p>关于这个“位置”,我是这样理解的,
它应该是一个具体的tablet server的名字,
client知道了哪个tablet server之后就向那个tablet server发出请求。
如果是这样的话,把tablet重新分配之后master需要去更新这些保存位置的tablet。</p>
<p>这里还有几个计算:</p>
<ul>
<li>如果一行占的空间是1KB,一个tablet的空间是128MB,
那么这样一个三层的结构能够保存的tablet的数目为$2^{34}$,
这个很容易理解,128MB / 1KB = $2^{17}$,两级下来就是$2^{34}$。</li>
<li>客户端会缓存住tablet的location,这样就不用每次都去读这个层级的结构。
如果客户端没有缓存,那么它读取一个tablet需要3次和tablet server的交互
(读root,METADATA,user tablet各一次)。如果缓存过期了,
最多需要6次和tablet server的交互(对于这个,我的理解是,如果客户端缓存了root tablet的location,
但是它过期了,那么它首先顺着这个结构下去,需要3次,然后发现不对,
又重新向Chubby得到root的位置,又再次顺着这个结构下去3次,
一共6次)。</li>
</ul>
<h3 id="tablet-1">Tablet的分配</h3>
<p>一个tablet一次只会被分配给一个tablet server,
master保存下面的信息:</p>
<ul>
<li>哪些tablet server是正常工作的(alive)</li>
<li>哪些tablet被分配给哪些tablet server</li>
<li>哪些tablet没有被分配(这个只是暂时的,master会把这些tablet分配好,外面看不到这个状态?)</li>
</ul>
<p>当一个tablet server启动时,
它会去获取Chubby的某个特定目录下的一个文件(一个tablet server唯一的对应这个目录下的一个文件)的互斥锁。
master通过检查这个目录查看哪些tablet server是alive的。
tablet server如果丢失了这个互斥锁,那么它会尝试重新获取,
如果这个文件不存在了,tablet server永远都拿不到这个锁了,
那么它会自动停止。
如果tablet server不工作了,它会释放这个锁,
这样master就知道它没有工作了,把它上面的tablet分配给其他的tablet server。</p>
<p>master会频繁地和那些正常工作的tablet server进行通信来获取它们的状态,
如果tablet server告诉master它失去了锁或者无法和这个tablet server进行通信,
那么master会尝试获取这个tablet server对应的文件锁,
如果能够拿到这个锁,说明Chubby能正常工作,
而这个tablet server要么死掉了要么不能和Chubby交互,
那么master就删除这个tablet server对应的文件,
这样这个tablet server就没用了,
然后master把这个tablet server上的tablet分配给其他的tablet server。</p>
<p>在master启动时,它会执行下面的步骤:</p>
<ol>
<li>首先,它会去Chubby上获取master锁,确保同一时间只有一个master工作</li>
<li>然后,扫描Chubby上的目录(就是上面提到的目录,所有tablet server对应的文件都在这个目录下),
知道哪些tablet server是alive的</li>
<li>然后,和每个alive的tablet server交互,知道哪些tablet已经被分配了</li>
<li>最后,便利tablet位置的三层结构(Figure 4),知道一共有哪些tablet,
然后把这些tablet分配给tablet server。</li>
</ol>
<p>这里有一个问题是,如果METADATA的tablet没有被分配,
那么它就不能被读取,那么第4步就没法进行了。
这个问题可以这样解决,如果需要读取某个tablet时它还没有被分配,
那么先把它分配给某个tablet server,然后就可以继续接下来的步骤。</p>
<p>当下面的情况发生时,tablet的分配情况要进行调整:</p>
<ul>
<li>tablet被创建或删除</li>
<li>tablet被合并</li>
<li>tablet被切分成两个tablet</li>
</ul>
<p>前面两种情况都是在master进行的,所以master直接进行调整就行,
而第三种过程是在某个tablet server上进行的,
master怎么知道的呢?
当tablet server对tablet进行切分时,
它首先在METADATA的tablet上记录下这个新的tablet,
然后通知master发生了改变。
如果这个通知丢失了,
那么当master去请求这个被切分的tablet时,
tablet server会发现这个tablet的METADATA table只是请求的METADATA的一部分,
就知道发生了切分,然后告诉master。</p>
<h3 id="tablet-2">Tablet的保存</h3>
<p>下面来看下一个tablet具体是如何保存的。</p>
<p><img src="http://chouqin.github.io/images/tablet_representation.png" alt="Tablet的表示" /></p>
<p>根据<a href="http://www.nosqlnotes.net/archives/122">这篇博客</a>,
要保存一个tablet,有这么几个部分:</p>
<ul>
<li>主SSTable,就是持久化的不可变的哈系表,保存在GFS上</li>
<li>memtable,在内存中记录最近的修改操作</li>
<li>commit log,修改记录,分为compacted和uncompacted(待会会说明)</li>
<li>次SSTable(为了区分两种SSTable,我用了“主”, “次”,不是重要性的区分),
这种SSTable是memtable的持久化版本,次SSTable的存在是为了加快recovery的速度,
因为recovery需要从commit log恢复memtable,同时可以释放memtable的内存</li>
</ul>
<p>有了这几个部分,对tablet的操作也就变得容易了,
对于写操作,只需要记录把操作记录在commit log中,
同时写入memtable。对于读操作,
由于数据不仅仅保存在主SSTable上,
还需要结合memtable和次SSTable来进行。</p>
<h3 id="compactions">Compactions</h3>
<p>Compaction主要是为了解决上面过程中出现的问题,它分为3种:</p>
<ul>
<li>minor compaction: 这个操作就是把memtable中的内容保存到SSTable,
释放memtable的内存,同时减小recovery时需要读取的commit log的数目,
已经被保存到次SSTable上的操作对应的commit称为compacted,
recovery时只需要从uncompacted的commit log中恢复就行了。 </li>
<li>merge compaction:
因为每次读取操作时都需要读取主SSTable和相关的次SSTable,
所以次SSTable的数量不能太多,因此,
master会把一些次SSTable组合成一个新的次SSTable。</li>
<li>major compaction:
master把次SSTable和memtable中的内容整合到SSTable里,
这样,就能回收掉修改的和删除的记录所占的空间。</li>
</ul>
<h2 id="section-4">优化</h2>
<h3 id="locality-groups">Locality groups</h3>
<p>client可以把一些列组放在一起形成一个locality group,
在每一个tablet里面,会为每一个locality group生成一个单独的SSTable,
使用locality group的好处是:</p>
<ul>
<li>可以提高读的性能,比如把网页的contents放在一个locality group,
而metadata放在另外一个locality group,
这样读取metadata时就不需要读取网页的内容。</li>
<li>可以对于不同的locality采取不同的调优参数。比如,
可以把有些locality group的SSTable放入内存。</li>
</ul>
<h3 id="cache">Cache</h3>
<p>为了提高读性能,tablet server采用了两种级别的cache:</p>
<ol>
<li>Scan Cache,缓存从SSTable返回的key-value对</li>
<li>Block Cache,缓存从GFS读回来的SSTable的block</li>
</ol>
<h3 id="bloom-filters">Bloom filters</h3>
<p>读操作需要结合SSTable和memtable,因此,
可以通过bloom filter来制定某些locality group的数据不可能存在于某些SSTable,
这样就可以减少需要读取的SSTable的数量。
Bloom filter一般保存在tablet server的内存中。</p>
<h3 id="commit-log">Commit log实现</h3>
<p>在Bigtable中,每一个tablet server只保存一个commit log,
这个commit log保存了所有的tablet相关的log。这样做的好处是:</p>
<ul>
<li>如果每个tablet一个commit log,就会导致同时有很多写请求发到GFS,
这样就会很多的磁盘seek。</li>
<li>这样限制了group commit的作用,
因为只有同一个tablet的写操作才能被合并成一个到一个group commit。</li>
</ul>
<p>所有tablet的commit log组合成一个文件增加了恢复的复杂性,
因为这样不同的tablet可能被迁移到不同的tablet server,
这样所有相关的tablet server都需要读取这个commit log来获取tablet的信息,
这个commit log会被重复读多次。</p>
<p>解决这个问题的一个办法是在recovery时,
先把commit log使用<code><table, row name, log sequence number></code>作为key进行排序,
这样一个tablet的commit log就是连续的,可以通过一次seek,
然后连续读就可以得到。
这个排序的过程也可以通过把这个commit log分成几块,然后并发地进行排序来加快速度。</p>
<p>为了避免GFS集群中由于网络原因或者load情况带来性能上的波动,
通常使用两个线程来完成写commit log的操作,
每一个线程有自己的commit log文件,
同一时课只有一个线程在写,
如果一个线程写出现了性能上的问题,
就切换到另外一个线程(因为两个线程使用了不同的文件,
可能分布到不同的chunkserver)。同时,
使用序列号来消除重复的commit log。</p>
<h3 id="recovery">加快recovery</h3>
<p>如果master把tablet从一个tablet server移到另一个,
源tablet server可以进行一次minor compaction,
这样uncompacted的commit log就减少了很多,
因为这个过程中可能会有其他的写操作,
所以在upload这个tablet时,
可以再进行一次非常快的minor compaction,
这样就不要进行recovery了。</p>
<h3 id="section-5">不变性</h3>
<p>利用SSTable的不可变性带来了以下的方便:</p>
<ul>
<li>缓存。</li>
<li>memtable是唯一可变的数据结果,对它使用<a href="http://en.wikipedia.org/wiki/Copy-on-write">copy-on-write</a>来消除读写冲突。</li>
<li>回收垃圾只需要回收SSTable就好了。</li>
<li>在split时,child tablet可以使用parent tablet的SSTable。</li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[把博客迁到Octopress]]></title>
<link href="http://chouqin.github.io/blog/2013/10/21/migrate-to-octopress/"/>
<updated>2013-10-21T20:02:00+08:00</updated>
<id>http://chouqin.github.io/blog/2013/10/21/migrate-to-octopress</id>
<content type="html"><![CDATA[<p>折腾了一个下午,终于把博客迁到到了Octopress。
迁移的原因主要有两点:</p>
<ul>
<li>
<p>喜欢Octopress整体的风格,包括它的响应式设计,
还有特别好看的<code>solarized</code>的语法高亮。</p>
</li>
<li>
<p>以前在<code>jekyll</code>上写博客,在<code>github</code>上面开了两个库,
原因在于Github Pages上不允许运行ruby脚本,
这样很多功能包括分页就都不能做了。为了完成分页的目的,
我在一个库里保存博客的源代码,使用<code>jekyll</code>来生成静态页面,
然后另一个库也就是<code>chouqin.github.io</code>就完全是静态页面,
把它发布到Github Pages上去。Octopress也是这样,
只不过它省去了我的麻烦,要发布到Github Pages,
只要一条<code>rake deploy</code>就够了,非常方便。</p>
</li>
</ul>
<p>来说一下具体的迁移过程吧。</p>
<h2 id="section">基础博客搭建</h2>
<p>其实完全是照着Octopress的<a href="http://octopress.org/docs/setup/">官方文档</a>一步步安装过来的,
官方博客已经写得很清楚了。Ruby管理使用的是<a href="http://rvm.io">rvm</a>。</p>
<p>出现了一个问题是<code>rake</code>安装的是10.1.0的版本,跟Gemfile对应的不一致,
直接把Gemfile里的那行改为<code>gem 'rake', '~> 10.1.0'</code>。</p>
<h2 id="section-1">修改配置</h2>
<p>首先是按照文档修改了一些<code>_conf.yml</code>配置:</p>
<ul>
<li>把使用的markdown改为<code>kramdown</code></li>
<li>启用<code>pygments</code>来进行语法高亮</li>
<li>Aside Bar只显示最近的Post和Github。</li>
<li>配置了<code>disqus_short_name</code>。</li>
</ul>
<p>具体的配置可以查看我的<a href="https://github.com/chouqin/chouqin.github.io/tree/source">github</a></p>
<h3 id="mathjax">使用MathJax</h3>
<p>由于使用的是<code>kramdown</code>,它的语法包含数学,为了在页面上展示数学公式,
在<code>source/_includes/head.html</code>上加入以下的内容:</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
<span class="line-number">9</span>
<span class="line-number">10</span>
<span class="line-number">11</span>
<span class="line-number">12</span>
<span class="line-number">13</span>
<span class="line-number">14</span>
<span class="line-number">15</span>
<span class="line-number">16</span>
<span class="line-number">17</span>
<span class="line-number">18</span>
<span class="line-number">19</span>
<span class="line-number">20</span>
<span class="line-number">21</span>
<span class="line-number">22</span>
<span class="line-number">23</span>
<span class="line-number">24</span>
<span class="line-number">25</span>
<span class="line-number">26</span>
<span class="line-number">27</span>
<span class="line-number">28</span>
<span class="line-number">29</span>
<span class="line-number">30</span>
<span class="line-number">31</span>
</pre></td><td class="code"><pre><code class="html"><span class="line"><span class="c"><!-- mathjax config similar to math.stackexchange --></span>
</span><span class="line">
</span><span class="line"><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/x-mathjax-config"</span><span class="nt">></span>
</span><span class="line"> <span class="nx">MathJax</span><span class="p">.</span><span class="nx">Hub</span><span class="p">.</span><span class="nx">Config</span><span class="p">({</span>
</span><span class="line"> <span class="nx">tex2jax</span><span class="o">:</span> <span class="p">{</span>
</span><span class="line"> <span class="nx">inlineMath</span><span class="o">:</span> <span class="p">[</span> <span class="p">[</span><span class="s1">'$'</span><span class="p">,</span><span class="s1">'$'</span><span class="p">],</span> <span class="p">[</span><span class="s2">"\\("</span><span class="p">,</span><span class="s2">"\\)"</span><span class="p">]</span> <span class="p">],</span>
</span><span class="line"> <span class="nx">processEscapes</span><span class="o">:</span> <span class="kc">true</span>
</span><span class="line"> <span class="p">}</span>
</span><span class="line"> <span class="p">});</span>
</span><span class="line"><span class="nt"></script></span>
</span><span class="line">
</span><span class="line"><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/x-mathjax-config"</span><span class="nt">></span>
</span><span class="line"> <span class="nx">MathJax</span><span class="p">.</span><span class="nx">Hub</span><span class="p">.</span><span class="nx">Config</span><span class="p">({</span>
</span><span class="line"> <span class="nx">tex2jax</span><span class="o">:</span> <span class="p">{</span>
</span><span class="line"> <span class="nx">skipTags</span><span class="o">:</span> <span class="p">[</span><span class="s1">'script'</span><span class="p">,</span> <span class="s1">'noscript'</span><span class="p">,</span> <span class="s1">'style'</span><span class="p">,</span> <span class="s1">'textarea'</span><span class="p">,</span> <span class="s1">'pre'</span><span class="p">,</span> <span class="s1">'code'</span><span class="p">]</span>
</span><span class="line"> <span class="p">}</span>
</span><span class="line"> <span class="p">});</span>
</span><span class="line"><span class="nt"></script></span>
</span><span class="line">
</span><span class="line"><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/x-mathjax-config"</span><span class="nt">></span>
</span><span class="line"> <span class="nx">MathJax</span><span class="p">.</span><span class="nx">Hub</span><span class="p">.</span><span class="nx">Queue</span><span class="p">(</span><span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
</span><span class="line"> <span class="kd">var</span> <span class="nx">all</span> <span class="o">=</span> <span class="nx">MathJax</span><span class="p">.</span><span class="nx">Hub</span><span class="p">.</span><span class="nx">getAllJax</span><span class="p">(),</span> <span class="nx">i</span><span class="p">;</span>
</span><span class="line"> <span class="k">for</span><span class="p">(</span><span class="nx">i</span><span class="o">=</span><span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o"><</span> <span class="nx">all</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">)</span> <span class="p">{</span>
</span><span class="line"> <span class="nx">all</span><span class="p">[</span><span class="nx">i</span><span class="p">].</span><span class="nx">SourceElement</span><span class="p">().</span><span class="nx">parentNode</span><span class="p">.</span><span class="nx">className</span> <span class="o">+=</span> <span class="s1">' has-jax'</span><span class="p">;</span>
</span><span class="line"> <span class="p">}</span>
</span><span class="line"> <span class="p">});</span>
</span><span class="line"><span class="nt"></script></span>
</span><span class="line">
</span><span class="line"><span class="nt"><script </span><span class="na">type=</span><span class="s">"text/javascript"</span>
</span><span class="line"> <span class="na">src=</span><span class="s">"http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"</span><span class="nt">></span>
</span><span class="line"><span class="nt"></script></span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<h2 id="section-2">迁移原来的博文</h2>
<p>原来的博客是基于<code>jekyll</code>的,对于每一篇博客,修改这几个地方即可:</p>
<ul>
<li>删除掉前面的<code>Included file 'JB/setup' not found in _includes directory</code>。</li>
<li>在配置上加入<code>comments: true</code>。</li>
</ul>
<h2 id="section-3">发布到七牛</h2>
<p>因为生成的是静态页面,所以也可以发布到七牛来加速访问。
在部署之前,你需要先<a href="https://portal.qiniu.com/signup?code=3l94gjc9mqzwx">注册</a>成为七牛用户,
然后获取<a href="https://portal.qiniu.com/setting/key">AccessKey 和 SecretKey</a>。</p>
<p>然后安装七牛的<a href="http://docs.qiniu.com/tools/v6/qrsync.html">qrsync</a>。</p>
<p>在<code>octopress</code>目录下创建<code>qiniu.conf</code>,写入以下内容:</p>
<div class="bogus-wrapper"><notextile><figure class="code"><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class="line-number">1</span>
<span class="line-number">2</span>
<span class="line-number">3</span>
<span class="line-number">4</span>
<span class="line-number">5</span>
<span class="line-number">6</span>
<span class="line-number">7</span>
<span class="line-number">8</span>
</pre></td><td class="code"><pre><code class="json"><span class="line"><span class="p">{</span>
</span><span class="line"> <span class="nt">"access_key"</span><span class="p">:</span> <span class="s2">"Please apply your access key here"</span><span class="p">,</span>
</span><span class="line"> <span class="nt">"secret_key"</span><span class="p">:</span> <span class="s2">"Dont send your secret key to anyone"</span><span class="p">,</span>
</span><span class="line"> <span class="nt">"bucket"</span><span class="p">:</span> <span class="s2">"Bucket name on qiniu resource storage"</span><span class="p">,</span>
</span><span class="line"> <span class="nt">"sync_dir"</span><span class="p">:</span> <span class="s2">"_deploy"</span><span class="p">,</span>
</span><span class="line"> <span class="nt">"async_ops"</span><span class="p">:</span> <span class="s2">""</span><span class="p">,</span>
</span><span class="line"> <span class="nt">"debug_level"</span><span class="p">:</span> <span class="mi">1</span>
</span><span class="line"><span class="p">}</span>
</span></code></pre></td></tr></table></div></figure></notextile></div>
<p>最后执行<code>qrsync qiniu.conf</code>,就能部署到七牛了。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[MapReduce学习心得]]></title>
<link href="http://chouqin.github.io/blog/2013/10/16/mapreduce/"/>
<updated>2013-10-16T00:00:00+08:00</updated>
<id>http://chouqin.github.io/blog/2013/10/16/mapreduce</id>
<content type="html"><![CDATA[<h2 id="section">简介</h2>
<p>对于计算机系的同学来说,MapReduce这个词应该并不陌生,
现在是所谓的“大数据时代”,“大数据”这个词被炒得非常热。
何为“大数据”?随着互联网的发展,现在的数据越来越多,
给原先的技术带来了两方面的挑战,一是<strong>存储</strong>,
如何存储这些PB级别的数据,
二是<strong>分析</strong>, 如何对这么大的数据进行分析,
从中提取出有用的信息。</p>
<p>MapReduce就是一个对大数据进行分析的框架。
使用MapReduce,用户只需要定义自己的<code>map</code>函数和<code>reduce</code>函数,
然后MapReduce就能把这些函数分配到不同的机器上去并行的执行,
MapReduce帮你解决好调度,容错,节点交互的问题。
这样,一个没有分布式系统编程经验的人也可以利用MapReduce把自己的程序放到几千台机器上去执行。</p>
<p><code>map</code>和<code>reduce</code>都是来自于函数式编程的概念,<code>map</code>函数接受一条条的纪录作为输入,
然后输出一个个<code><key, value></code>对,<code>reduce</code>函数接受<code><key, values></code>对,
(其中<code>values</code>是每一个<code>key</code>对应的所有的<code>value</code>),通过对这些<code>values</code>进行一个“总结”,
得到一个<code><key, reduce_value></code>。</p>
<p>比如拿经典的<strong>WordCount</strong>例子来说,对于文本中的每一个单词<code>word</code>,
<code>map</code>都会生成一个<code><word, 1></code>对(注意如果一个文本中一个单词出现多次就生成多个这样的对),
<code>reduce</code>函数就会收到<code><word, 1,...></code>这样的输入,它的工作就是把所有的<code>1</code>都加起来,
生成一个<code><word, sum></code>。</p>
<p>MapReduce函数基于键值对进行处理,看起来很简单,
那很多的分析任务不仅仅只是简单的Wordcount而已,能够使用这两个函数来实现吗?
幸运的是,很多的大规模数据分析任务都能通过MapReduce来表达,
这也是为什么MapReduce能够作为一个框架被提出的原因,