| T O P 1 0 |
我要一所大房子,有很大的落地窗户
我真的不曾想到工作了那么久我还会有那么的不安稳感。我是一个心里存不住事的人,一件烦心事于我就相当于一个已知现象却不知缘由的 bug 一样,不解决掉它我感觉整个系统都不稳定。
前面曾说过办手续的各种烦,没想到才见看稳定下来,又得到一条消息:女友可以提前调回北京总部了。而我们工作地位一个在丰台总部基地,一个在海淀西二旗,这就意味着必须得换房子了——令人愉悦的烦恼!
先说说我现在住的房子吧:西二旗智学苑,三室一厅次卧,无隔断间,距公司一千米,日常设施齐全,北大家属楼,北大校园网,房东直租,便宜——950/月,再加上免取暖物业费,网费和取暖费一年下来省不少;缺点是:小——实测只有九平米 + 一平米飘窗(虽然号称12平米),脏——关注我 Twitter 或者 Buzz 的同学应该知道卫生间我是如何打扫干净的。
毕竟住了三个月了,已经熟悉,而且离公司不是一般的近,骑自行车就更方便了。在校园网里,还可以上 IPV6 下电影,真有些舍不得,但是没办法。
我是一个土人,很羡慕那些电视里精心装修的干干净净的家居环境,比如《家有儿女》那种。本来换房子也想租个那样的,无奈房子太难找,好点儿的房子迟一点儿就会被人抢走。即使是找中介,也没有很多信息。而且都比较贵,因此都不敢想租个一居二居啥的,觉得负担不起。
在水木租房版、豆瓣租房小组、赶集网之类的地方关注了很久,也找了我爱我家中介,都没找到合适的。本来目标是长椿街和宣武门地铁站附近的合租主卧,昨天鬼使神差地在豆瓣租房小组多翻了一会儿,居然翻出来个牛街的一居,还挺便宜。赶忙提前下班去看了一下,怕被别人抢走,当场就定下来了,今天晚上刚和房东签了合同回来。
房子不能完全如我所期望,没有什么高档家具,全部都是简易的,也不是木地板,距离地铁也不是特别近。但让我满意的是:比较新——06年的房子、落地窗带阳台、卫生间和厨房都很干净、小区也比较安全。总共使用面积有四十多平吧,进去和我九平米的房间果然感觉不一样!
其实,最开心的是,总算能住上自己独门独户的房子了!再也不用和别人合用厨房、冰箱、卫生间、洗衣机——这可是我从上学时就梦寐以求的事情!
这个周末,就要用来搬家了。
广告:我的朋友们,谁想换个离西二旗地铁近的合租单间,可以和我联系了。要求高的满足不了,但是有两点必须得赞:房子很实惠,房东很实在。
Fastbit中的bitmap索引算法
摘要:bitmap 索引是一种典型的数据库索引方案,本文基于 Fastbit 软件包,使用实际用例对一些常用的 bitmap 索引算法进行了一个较为系统的介绍。
一、Fastbit是什么?
引用 Fastbit 的官方网站上的介绍:Fastbit是一个追随 NoSQL(Not Only SQL) 运动精神的开源的数据处理程序库,它提供了一系列的用压缩的 bitmap 索引支持的查询函数。在这里,我们关注的关键词是“bitmap 索引”。Fastbit 使用的是按列存储方式,其 bitmap 索引也是在按列存储的数据上建立起来的。
二、Fastbit 中的 bitmap 索引算法
Fastbit 的源代码有着非常清晰的结构。在 Fastbit 的源代码中,每个索引算法都用一个 C++ 类来实现,所有的索引算法类都是基类 index 的派生,并且在 fastbit 源代码中保存为以 i 开头的源文件。
下面是 Fastbit 中的索引类的派生关系图,从美观考虑,直接使用 xmind 思维导图而不是 UML 来展现了:
下面我们将对其中部分算法进行简单的介绍。我们将这些索引算法分为几大类:基础算法、扩展算法、多层算法和多成分算法。
三、基础 bitmap 索引算法
基础的 bitmap 索引算法是最简单的 bitmap 索引算法,给出了 bitmap 索引的基本原理。
3.1 relic
relic (定义在 irelic.h 中,实现在 irelic.cpp ) 是最原始的 equality-encoded 算法,这个单词代表“遗迹”的意思。它可谓是最简单直观的 bitmap 索引算法。relic 为需要索引的每个值都建立一个 bitvector,在该 bitvector 中,只有等于该值的列才会被置 1,其它位都被置 0,如下表所示:
| 数据 | 索引(bitmap) | ||||
| a | b | d | e | g | |
| a | 1 | 0 | 0 | 0 | 0 |
| g | 0 | 0 | 0 | 0 | 1 |
| d | 0 | 0 | 1 | 0 | 0 |
| e | 0 | 0 | 0 | 1 | 0 |
| b | 0 | 1 | 0 | 0 | 0 |
| d | 0 | 0 | 1 | 0 | 0 |
| g | 0 | 0 | 0 | 0 | 1 |
| e | 0 | 0 | 0 | 1 | 0 |
3.2 bin
bin (定义于 ibin.h,实现在 ibin.cpp)是 binned equality-encoded 算法,这里它代表“桶”的意思。它可以视为是 relic 的一种变形,它将值域分为几个不相交的区间,将原本是相等才置一的规则转变为值落在该区间内就置一,如下表所示。当然,relic 也可以视为 bin 的一个特例(将区间定义为 [a, a+ε)。bin 每个区间的范围由程序遵从某些规则设定,这些规则由命令行通过参数传入。
| 数据 | 索引(bitmap) | ||
| (…,b) | [b,e) | [e,…) | |
| a | 1 | 0 | 0 |
| g | 0 | 0 | 1 |
| d | 0 | 1 | 0 |
| e | 0 | 0 | 1 |
| b | 0 | 1 | 0 |
| d | 0 | 1 | 0 |
| g | 0 | 0 | 1 |
| e | 0 | 0 | 1 |
3.3 bin->range
range (定义于 ibin.h,实现于 irange.cpp)是 range-encoded 算法,这里它代表“范围”的意思。正如它字面所表达的意思,range 的每个 bitvector 标记着小于某边界值的值,如下表所示。因此,它可以视为是 bin 的一个累积表示,这也是 fastbit 软件包中所做的:首先构造 bin,然后累加转换成 range。值得注意的是,一般最后一列代表着小于无穷大,因此该 bitvector 全为 1,会被略去不写。
| 数据 | 索引(bitmap) | ||
| (…,b) | (…,e) | (…,g) | |
| a | 1 | 1 | 1 |
| g | 0 | 0 | 0 |
| d | 0 | 1 | 1 |
| e | 0 | 0 | 1 |
| b | 0 | 1 | 1 |
| d | 0 | 1 | 1 |
| g | 0 | 0 | 0 |
| e | 0 | 0 | 1 |
3.4 bin->mesa
mesa (定义于 ibin.h,实现于 imesa.cpp)是 interval-encoded 算法[1],它与 bin 类似,只不过它的区间之间有重叠部分。与 range 相同,在 fastbit 软件包中,它也是通过 bin 构造起来的。
| 数据 | 索引(bitmap) | |||
| (…,d) | [a,e) | [b,g) | [d,…) | |
| a | 1 | 1 | 0 | 0 |
| g | 0 | 0 | 0 | 1 |
| d | 0 | 1 | 1 | 1 |
| e | 0 | 0 | 1 | 1 |
| b | 1 | 1 | 1 | 0 |
| d | 0 | 1 | 1 | 1 |
| g | 0 | 0 | 0 | 1 |
| e | 0 | 0 | 1 | 1 |
四、扩展 bitmap 索引算法
4.1 direkte
direkte (定义于 idirekte.h,实现于 idirekte.cpp)是丹麦语中的 direct,它与 relic 几乎是一样的,不同点只是它为小于最大值的所有值都建立了一个 bitvector(即使该值并不存在于列中)。
| 数据 | 索引(bitmap) | ||||||
| a | b | c | d | e | f | g | |
| a | 1 | 0 | 0 | 0 | 0 | 0 | 0 |
| g | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| d | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
| e | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
| b | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| d | 0 | 0 | 0 | 1 | 0 | 0 | 0 |
| g | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
| e | 0 | 0 | 0 | 0 | 1 | 0 | 0 |
4.2 relic->slice
slice(定义于 irelic.h,实现于 islice.cpp)实现了 O'Neil'97 [2] 提出的 bit-slice 算法。它的基本思想就是首先将原始数据用二进制进行编码,bitmap 就是所有值的二进制编码表示的集合,bitvector 的个数由最大值的二进制表示决定,如下表所示:
| 数据 | 编码 | 索引(bitmap) | ||
| a | 0 | 0 | 0 | 0 |
| g | 4 | 1 | 0 | 0 |
| d | 2 | 0 | 1 | 0 |
| e | 3 | 0 | 1 | 1 |
| b | 1 | 0 | 0 | 1 |
| d | 2 | 0 | 1 | 0 |
| g | 4 | 1 | 0 | 0 |
| e | 3 | 0 | 1 | 1 |
4.3 bin->bak
bak (定义于 ibin.h,实现于 idbak.cpp)是丹麦语中的 bin,因此它是 bin 的变形。它使用减精度来表示 bin 区间的中心,即它的每一个区间都是用一个更低精度的数来表示,具体来说就是四舍五入啦。下面是一个对 1-100 的数据列建立 bak 索引的输出,其中第一列表示区间的中心,第二三列代表区间最小最大值,第四列代表该区间内数据的个数:
index (equality encoding on reduced precision values) for data.a contains 19 bitvectors for 100 objects 1 1 1 1 2 2 2 1 3 3 3 1 4 4 4 1 5 5 5 1 6 6 6 1 7 7 7 1 8 8 8 1 9 9 9 1 10 10 14 5 20 15 24 10 30 25 34 10 40 35 44 10 50 45 54 10 60 55 65 11 70 66 74 9 80 75 84 10 90 85 94 10 100 95 100 6
4.4 bin->bak2
bak2 (定义于 ibin.h,实现于 idbak2.cpp)是 bak 的变形,也是以减精度来表示区间。但与 bak 不同的是,它将 bak 的每个区间区分为两个区间:小于减精度数的区间,和大于等于减精度数的区间。虽然注释中这样说,但实现时 bak2 是将 bak 的区间分为了三个:小于、等于和大于。下面是一个对 1-100 的数据列建立 bak2 索引的输出,每列的含义与 bak 中示例相同:
index (equality encoding on reduced precision values) for data.a contains 37 bitvectors for 100 objects 1 1 1 1 2 2 2 1 3 3 3 1 4 4 4 1 5 5 5 1 6 6 6 1 7 7 7 1 8 8 8 1 9 9 9 1 10 10 10 1 10 11 14 4 15 15 19 5 20 20 20 1 20 21 24 4 25 25 29 5 30 30 30 1 30 31 34 4 35 35 39 5 40 40 40 1 40 41 44 4 45 45 49 5 50 50 50 1 50 51 54 4 55 55 59 5 60 60 60 1 60 61 65 5 66 66 69 4 70 70 70 1 70 71 74 4 75 75 79 5 80 80 80 1 80 81 84 4 85 85 89 5 90 90 90 1 90 91 94 4 95 95 99 5 100 100 100 1
除了上面几个算法之外,扩展的算法还有 roster 和 keywords,这两种算法比较复杂,这里就不示例讲解了。
五、多层 bitmap 索引算法
有了几个基础的 bitmap 索引算法,我们就可以考虑将这些算法组合成一个层次的结构,构造出多层的 bitmap 索引算法。下面的几个算法,即是由前面的基础 bitmap 索引算法构造出来的二(多)层 bitmap 索引算法。
5.1 bin->ambit
ambit(定义于 ibin.h,实现于 ixambit.cpp)是 multilevel-range based算法,在这个算法中索引分为多层,每层索引都是基于 range 的索引。具体实现时,fastbit 首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 ambit。分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则由一简单算法确定,确定分组个数的算法为(第一个桶不参与分组):
ixambit.cpp: 33 // the default number of coarse bins is determined based on a set 34 // of simplified assumptions about expected sizes of range encoded 35 // bitmaps and word size being 32 bits. 36 const uint32_t defaultJ = static_cast37 (nbins < 100 ? sqrt((double)nbins) : 38 0.5*(31.0 + sqrt(31.0*(31 + 4.0*nbins))));
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 ambit:
5.2 bin->pale
pale(定义于 ibin.h,实现于 ixpale.cpp)是 two-level binned equality-range算法,它的索引分为两层,第一层为 binned equality(bin) 索引,第二层为 range 索引。在具体实现时,pale 首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 pale。与 ambit 相同,分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当 bin 桶数大于31时,默认第一层为16个组:
ixpale.cpp:
45 else { // default -- 16 coarse bins
46 if (nbins > 31) {
47 j = 16;
48 }
49 else {
50 j = nbins;
51 }
52 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 pale:
5.3 bin->pack
pack(定义于 ibin.h,实现于 ixpack.cpp)是 two-level binned range-equality 算法。它的索引分两层,与 pale 相反,第一层为 range 索引,第二层为 binned equality(bin) 索引。具体实现时,fastbit 首先构造 bin,然后对桶进行分组(调用bin::divideBitmaps),然后构造 pack。分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当bin桶数大于63时,默认第一层为31个组:
ixpack.cpp:
44 else { // default -- 31 coarse bins
45 if (nbins > 63) {
46 j = 31;
47 }
48 else {
49 j = nbins;
50 }
51 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 pack:
5.4 bin->zone
zone(定义于 ibin.h,实现于 ixzone.cpp)是 two-level binned equality-equality 算法,它的索引分两层,两层均为 binned equality(bin) 索引。它的实现方式也是首先构造 bin,然后对桶进行分组(调用 bin::divideBitmaps),然后构造 zone。其分组粒度可以由命令行传入参数 ncoarse=x 和/或 nrefine=n 指定,否则当bin桶数大于31时,默认第一层为14个组:
ixpack.cpp:
46 else { // default -- 14 coarse bins
47 if (nbins > 31) {
48 j = 14;
49 }
50 else {
51 j = nbins;
52 }
53 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 zone:
5.5 bin->fuge
fuge(定义于 ibin.h,实现于 ixfuge.cpp)是 two-level binned interval-equality 算法,fuge 为德语中 interstice 的表述。fuge 的索引分两层,第一层为 interval(mesa) 索引,第二层为 binned equality(bin) 索引,它也是采用首先构造 bin,然后基于 bin 构造 fuge 的方式。其分组粒度由 ncoarse=x 指定,否则默认的分组个数由下面算法确定:
ixfuge.cpp: 887 // default size based on the size of fine level index sf: sf(w-1)/N/sqrt(2) ... 899 if (ncoarse < 5U && offset32.back() > 900 offset32[0]+static_cast(nrows/31)) { 901 ncoarse = sizeof(ibis::bitvector::word_t); ... 913 else { 914 ncoarse = ncmax; 915 } 916 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 bin,右侧是基于该 bin 构造的 fuge:
5.6 relic->bylt
bylt(定义于 irelic.h,实现于 ixrelic.cpp)是 two-level unbinned range-equality 算法,bylt 是丹麦语的 pack(binned 版本算法)。bylt 索引分两层,第一层为 range 索引,第二层为 unbinned equality(relic) 索引。在实现时首先构造 relic,然后对桶进行分组(调用bin::divideBitmaps),然后构造 bylt。分组粒度可以由 ncoarse=x 指定,bylt 保证每组中桶数是大致均匀的,否则由下面算法决定分组的个数:
ixbylt.cpp:
182 // default size based on the size of fine level index sf:
183 // (w-1) * sqrt(sf*(sf-N/(w-1))) / (2N)
184 if (ncoarse < 5U && offset64.back() > offset64[0]+(int32_t)(nrows/31U)) {
185 ncoarse = sizeof(ibis::bitvector::word_t);
const int wm1 = ncoarse*8-1;
...
199 ncoarse = ncmax;
200 }
201 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 bylt:
5.7 relic->fuzz
fuzz(定义于 irelic.h,实现于 ixfuzz.cpp)是two-level unbinned interval-equality 算法,即 fuge 的 unbinned 版本,名字起源于 fuzzy 聚类/分类。fuzz 索引分两层,第一层为 interval(mesa) 索引,第二层为 unbinned equality(relic) 索引,具体实现时 fastbit 也是采用首先构造 relic,然后构造 fuzz 的方式。其分组粒度可以由 ncoarse=x 指定,否则默认分组个数由下面算法确定:
ixfuzz.cpp:
168 // default size based on the size of fine level index sf: sf(w-1)/N/ sqrt(2)
169 if (ncoarse < 5U && offset64.back() > offset64[0]+nrows/31U) {
170 ncoarse = sizeof(ibis::bitvector::word_t);
...
182 else {
183 ncoarse = ncmax;
184 }
185 }
下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 fuzz:
5.8 relic->zona
zona(定义于 irelic.h,实现于 ixzona.cpp)是 two-level unbinned equality-equality 算法,zona 是丹麦语的zone(binned 版本算法),其索引分两层,两层均为 unbinned equality(relic) 索引。首先构造 relic,然后对桶进行分组构造zona,分组个数默认为11个。下面看一个实际的例子,左侧是对 1-100 的数据列构造的 relic,右侧是基于该 relic 构造的 zona:
六、多成分 bitmap 索引
多成分(multi-component)bitmap 索引[3]是使用一组基数将数据值分解成多个部分,分别对每个部分进行 bitmap 索引的方案。原理描述如下:给定 n-1 个基数 { bn-1, bn-2, ..., b1},那么一个值 v 可以通过下式分解为 {vn, vn-1, ..., v1}:
这和数的表示法类似,如果令 bi 都是 10,那么 vi 就是十进制表示法中第 i 位的值(大于等于0,小于10)。更准确的表述可以参考[3]。下面我们来看 fastbit 中的几个实现。
6.1 relic->fade
fade(定义于 irelic.h,实现于 ifade.cpp)是 multicomponent range-encoded 算法,即在每个部分中,是使用的 range 索引。下面来看一个 range-encoded 的例子:
在(b)图中,选择的基数是 9,那么索引就变成了一个单成分的 range 索引算法;在(c)图中,选择的基数是 <3, 3> 这样一个双成分编码,对分解出来的每个成分(大于等于0,小于3)生成 range 索引,就得出了 (c) 图中的结果。
6.2 relic->fade->sapid
sapid(定义于 irelic.h,实现于 isapid.cpp)是 multicomponent equality-encoded 算法,即在每个部分中是使用的 equality(relic) 索引。下面来看一个 equality-encoded 的例子:
在(b)图中,选择的基数是 <3, 4> 这样一个双成分编码,对分解出来的每个成分生成 relic 索引,就得到了 (b) 图中的索引结果。
除了这两个索引算法之外,还有 sbiad(multicomponent interval-encoded),egale(multicomponent equality code on bins), entre(multicomponent interval code on bins), moins(multicomponent range code on bins)这几个索引算法。从括号中我们可以大致猜出这些索引的实现方式,但是由于我们现在没有一个很好的示例展现方式,用实际用例来展现这些索引算法的效果将会留给以后的文章进行。
七、总结
这篇文章基于 fastbit 软件包,加以实际的用例对常用的 bitmap 索引算法进行了一个较为系统的介绍。不过生成 bitmap 索引仅仅是第一步,bitmap 索引在存储时会有很大的开销,在不损害(较少损害)查询效率的情况下,对 bitmap 索引进行有效的压缩是一个非常有挑战性的课题。除了 bitmap 索引的生成和存储之外,在不同类型的 bitmap 索引上实现高效的各种类型的查询,也是一个值得进一步探讨的问题。我们很高兴地看到 fastbit 软件包实现了很多这些相关领域的算法,为我们提供了非常宝贵的资料。
参考文献
[1] C-Y. Chan and Y. E. Ioannidis, An efficient bitmap encoding scheme for selection queries, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1999.
[2] P. O’Neil and DalIan Quass, Improved Query Performance with Variant Indexes, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1997.
[3] C-Y. Chan and Y. E. Ioannidis, Bitmap Index Design and Evaluation, in Proceedings of the ACM international conference on Management of data (SIGMOD), 1998.
我为什么这么忙
这里已经很长时间没有更新了,原因很简单,我很忙!敲下这几个字时,我正坐在母校中国科学院研究生院中关村园区东小楼的台阶上,等待某人过来给我盖一个戳——如果能把这个行为称为被“戳”一下的话,我已经千疮百孔了。
1. 品行鉴定
今天这个戳,是要戳到“品行鉴定”上。我个人是相当不理解该文件存在的意义,但是为了这个戳,我已经是第二次跑过来了。最开始给院系总支的老师打电话,她说,嗯,我们已经放假了,你8月26号以后再来吧。幸运的是,我最后总算联系上一个非常好心的老师,他给我戳了一下。但没有料到的是,过了一个星期之后,该文件又回来了,意见是:落款不能用手写,必须机打。于是,我只能打电话找人,然后再跑来。
2. 离校手续单
拿到离校手续单的时候,我花了几天时间跑了一圈,我以为都办完了。然后才被告知,虽然我一次没踏入过机房,也一次没从学校财务借过钱,我仍然需要到两个相关部门去签字盖戳,否则离校手续就是没有办全,连校园卡都不给你退。
3. 某某部
第一次去某某部,那时还没有放假,但等到9点半还没有上班;第二次去某某部,已经放假了,虽然前一个周二、五和后一个周二、五都有人值班,但是去的那个周五就是没人值班;第三次去某某部,我变聪明了,让同学先去打听一下他们上不上班,结果同学只问了保安,没看到通知,通知上写的是,8月6日以后必须得等到8月26日开学才开始值班。然后...我只能继续等。
4. 毕业推荐表
由于当时工作确定较早,使用的是2009年的毕业推荐表,把2009改成2010,然后戳一下。入职后公司说,新的推荐表格式都不一样了,最好要一张新的。然后我只能先跑到院系要一张新表盖戳,然后再找就业指导中心盖戳,他们暑假里都是某天才上班,而且这天还不固定。照片还只能要白底的,只好再照一张。
5. 成绩单
上头说成绩单上非百分制都要给出说明并盖戳,而我们的教务处说,已经放假,8月26日以后上班,暑假不值班。
6. 关于校区
最要命的是,我们有两个校区,一个在玉泉路,一个在中关村。所有和院系相关的证明、戳,我都得在中关村办;所有和学校相关的证明、戳,我都得在玉泉路办。所以我有时候得来回辗转多次,而这两个校区,相距15公里,距离我住的地方,也有10公里。
7. 关于学校
在母校读研期间,我深深地羡慕该校行政人员的舒适。校图书室的上班时间为:周一到周五9点到5点,中午休息两个小时,周五下午不上班,周末不上班;校园卡中心每天中午休息两个小时,周六下午上班,周日不上班,充电卡必须在规定的时间,否则即使有工作人员也不予受理;上班时间去找科研处的工作人员,打电话背景音是商场里。更别提放寒暑假时候了,虽然很多科研人员、研究僧们连个高温假都没有,行政仍然可以理直气壮地休假,连定期值班的人都没有。
虽然前面列举了遭遇到的种种困难,但值得说明的是也有我自己的问题在里面。由于母亲重病,我办完入职手续就请假回家陪护了,因此没有来得及在放暑假前把各种手续办完。
大家都没有错,学校行政人员有权利享受假期,国家行政机关有权利要求各种靠谱和离谱材料,只剩下的是我们这些小人物,埋头捡拾着新鲜出炉的一个又一个杯具。
使用 screen 命令的一些小技巧
由于工作环境的问题,最近越来越感觉到 screen 命令的可贵,下面总结一点使用 screen 命令的小技巧。
最常用的参数组合:
screen -ls // 列出已有的 screen
screen -D -R // 进入指定的 screen 名,如果没有,则以该名称创建 screen
由于很常用,我把这两个命令取了个 alias:
alias sl='screen -ls'
alias sr='screen -D -R'
除了命令之外,还有快捷键 Ctrl+ac 创建 screen;Ctrl+aa 在两个 screen 之间相互切换;Ctrl+ad 从 screen 中 detach;Ctrl+a数字,跳转到数字指代的 screen。
在 screen 最下方显示状态栏,状态栏包括已经打开的 screen 标签列表,当前的 screen 和时间。其中在 screen 标签处显示该 screen 所处的目录名。显示 screen 所处的目录名这一点实现起来要困难一些,首先得修改 .bashrc,加入 screen term 对应的信息
case $TERM in
screen*)
# This is the escape sequence ESC k \w ESC
# Use current dir as the title
SCREENTITLE='\[\ek\W\e\\\]'
PS1="${SCREENTITLE}${PS1}"
;;
*)
;;
esac
然后 . 或者 source 一下,再修改 screen 的配置文件,添加状态栏,在 .screenrc 中添加:
caption always '%{=b cw}%-w%{=rb db}%>%n %t%{-}%+w%{-b}%< %{= kG}%-=%D %c%{-}'
shelltitle '$ |bash'
最终效果为:

宅并低俗着
其实我今天本来想出门的,但是睡到 11 点,吃了 xixi 昨晚买好的蛋糕之后,再也不想动了。算了,鞋子也是买亦可不买亦可的东西,带回北京反而比较累。
xixi 去改高考卷了,白天也没时间陪我。是我逼着她去的,因为我比较爱财,改卷子能赚不少钱呢,所以这是自作自受。不过等她离开了南大,这种机会也不会再有了。我忽然意识到今年江苏数学卷好像是传说中的“数学帝”出的,不过我不太相信,出高考卷子这种事,难道只赖一个人吗?
起来以后就在网上闲逛,看了看《非诚勿扰》被整改的评论,小百合 BBS 上居然有不少人(可能甚至是大多数人)持赞同态度,让我心里着实郁闷了一把。其实韩寒对“69 圣战”的评论完全可以应用在此:
“...不要以任何名义去驱逐任何一种文化,更不要想教训和消灭它的受众群体,无论是文化还是政治都不能排他,也不能代替别人做出选择,哪怕它很傻,哪怕它不合你的口味,只要它不反人类。”
有很多人担忧会污染青少年,天,我倒希望自己被早教会一点,而且,小孩子会喜欢看这类节目吗?还提到拜金主义、低俗、虚荣,我只能说,哈!大家都去看“做好事从不留名”的《雷锋的故事》吧。
然后,然后我就发现 Twitter 抽风了,扯淡都不能了,然后我就开始看一个叫做《泡沫之夏》的偶像剧,继续低俗。
因为我 fo 的人太少,忽然觉得可看的东西少了,于是就启用了 Buzz。在 Google Reader 看到订阅了很久的一个博主今天早上生了个姑娘,当爹的喜悦洋洋溢溢飘飘洒洒,连我都跟着高兴。不过想到这样一来他责任又重了几分,况且还要在北京把孩子抚养大,我又不知道该不该高兴了。
世界杯开始了。球赛我是爱看的,因为好歹我也踢过几年球,但因为关注得少,我总是记不住那些球星。我会为精彩的传球射门欢呼,也会为失去的机会遗憾,但我讲不出那漂亮的脚法是梅西还是贝利玩出来的,也记不住巴西还是法国上届世界杯进过多少球。所以我一般不讨论这个话题,也不掺和这类讨论。
南京这几天的天气还不错——至少在屋里感觉是这样。昨天下午我出了趟门,被淋得湿透,却还愤怒于找不到一个建设银行的提款机。易于愤怒是不成熟的表现,那么我认为至少在面对系统故障的时候,我是比较成熟了。当电脑诡异地当掉且手边没有任何工具盘时,我居然没有感觉气愤,而是想尽各种办法解决问题,事后还写了篇博客记录一番。
我的 D630 要给 xixi 了,然后把她的本要来给我妹,替换掉给她的那个台式机。这是为了资源的最优配置,最差的电脑给最不需要的人。我很惊奇于居然有博客的读者还记得我的笔记本型号,我想可能是与他用的型号相同吧。等入职后公司应该会配电脑,到时候如果能折腾的话,我还会继续写折腾的记录。
该吃饭了,先宅到这里吧。
删除 MBR 引发的诡异问题
我要跟女友交换一下笔记本电脑,她不常用 Linux,而我的 Ubuntu 分区占了好几十 G 空间,因此我想还是删了再给她吧。
我的电脑有两个系统:Windows Server 2008 和 Ubuntu 10.04。按照惯常的思维,删除 Ubuntu 只需要先格式化 MBR,然后删除 Ubuntu 分区即可。因为手头没有 DOS 启动盘,我想到一键恢复的硬盘版是带 DOS 工具的,就在 Windows 下装了个一键恢复硬盘版,然后进 DOS 命令行 “fdisk /mbr”。
可谁知道做完这些之后,MBR 是清掉了,但系统无法启动了,提示消息是这样的:
Windows 未能将启动原因可能是最近更改了硬件或软件
文件:\Windows\system32\winload.exe
状态:0xc000000e
信息:无法加载所选项,因为应用程序丢失或损坏。
...
然后我就傻眼了,从来没有遇到过这种情况呀!搜索了一番之后,才明白了这是什么意思。
Windows Vista 之后的系统,不再使用 boot.ini 保存启动菜单,而是使用一种叫做 BCD(Boot Configuration Data)机制来管理启动菜单,其默认的配置文件是活动分区(一般是 C:\)的 \Boot\BCD。简单的来说,可以将 \Boot\BCD 文件看成是 GRUB 的 menu.lst(grub.conf)文件,里面储存着系统装载程序的路径和参数等。
在我这里,出现上面问题的原因是 BCD 每项记录中的 device 选项被“一键恢复硬盘版”改成了 unknown,这样启动程序不知道到哪里去找系统的装载程序,自然也就无法启动了。使用 bcdedit /store C:\Boot\BCD 可以查看系统的 BCD 每项记录。(较为诡异的是,在没有删除 MBR 之前,我是如何进入到启动项里的?)
我用的解决方法是把所有默认启动项中的 unknown 改成了 boot。还得依靠工具,使用 WinPE U 盘(DOS 启动盘未尝试)启动,进入 C:\Windows\System32\,执行 bcdedit 命令:
bcdedit /store C:\Boot\BCD /set {default} osdevice boot
bcdedit /store C:\Boot\BCD /set {default} device boot
bcdedit /store C:\Boot\BCD /set {default} detecthal 1
然后就可以启动进入 Windows 了。
南京一樽牛排
在这一个月里,我正在进行着一个人生阶段的重要跨越——从学生转型为程序员。最近在忙毕业的事情,很久没有更新博客。虽然也不是忙得没有空闲,但空闲时也没有心情来写字。体验过中国官僚制度的同学们应该都知道,跑手续是一件多么繁琐累人的事情。
到目前为止,琐事基本上告了一个段落,已经通过答辩,各项材料等都提交了上去。下面只需要办离校手续和等待发放毕业证和学位证。据说中科院的学位证一般是在七月中旬发放,唉,这样一来只能暂时拿大半个月的实习工资了。
我在西二旗的智学苑小区租了间房子,大部分东西已经搬了过去,我也准备定居在那里了。如果有朋友也同样住智学苑的,以后不妨结识一下
趁着入职前的这段空闲,我请了一周的假。
今天早上到的南京,中午女朋友带我去吃垂涎已久的一樽牛排。牛排的味道很不错,还搭配饮料、汤、面包等,加上自助水果,尤其是南大学生可以打六折,这样就让它显得超值了。而且,女朋友说我运气真好,这次的牛排、果汁、水果都是她吃过量最足的。
晚上蹭了一顿南大数学系研究生的毕业聚餐。
世界杯开始了。
向费师兄家属捐款事宜
不了解此事件的,参见这个链接。
消息来源:南大数学 02 级原年级长博客
关于向费存林同学捐款的办法,国内,请发信至 dean1873@gmail.com 获鼎处了解账号的相关信息,为了安全起见,不公布账号。
北美的同学,请寄支票到我处
139 Running Farm LN
Apt 104
Stanford CA 94305支票寄出后,请给我电话确认。
捐款会在 6 月底结束。
本来我没想转发这个捐款的消息,但是我今天遇到一个和我联系的陌生朋友居然也认识费师兄。我想也许有一些有心想帮助费师兄家人的同学和朋友不能从 gookbaby 博客上了解这个信息,所以在这里我算尽一份自己的力量吧。
南京大学学位论文 LaTeX 模板
由于女朋友要写毕业论文,一些前人写的模板我不熟悉,并且摘要格式好像都不符合南京大学研究生院要求,所以我就在中科院学位论文模板的基础上给她改了一个南大研究生学位论文 LaTeX 模板。主要工作是将封面和摘要格式都改成符合南大研究生院给的样张格式,实话说,花了不少工夫。
既然模板都已经写好,后来我干脆又完善了一下,添加了博士毕业论文需要的国家图书馆论文封面。这样大概可以作为一个完整的,包含硕士和博士毕业论文格式的南大研究生学位论文 LaTeX 模板包,我将这个 LaTeX 模板释出在下面这个地址:
http://share.solrex.org/njuthesis/,或者Google Code页:http://njuthesis.googlecode.com/
下面是一个 flash 的预览:
http://share.solrex.org/njuthesis/template-preview.swf。
有需要的同学可以去下载,最起码可以作为一个修改的基础,希望这些工作能够对别人有所助益。我会尽量地维护这个模板,所以如果有哪位校友觉得有不完善的地方,可以和我联系,我会修正相应的缺点。
初次尝试网上冲印
由于数码照片很普及,好久没有冲印照片的需求了。最近临近毕业,各种乱七八糟的申请表都需要一些证件照片,于是一寸照片就给用完了。
为图省事,我手头上有之前一张一寸照片的数码底板,而且觉得那张相片照得还不错,就想着再多冲洗几张算了。谁知道到附近的照相馆一问,一版一寸照片需要五块钱一张,而且还要第二天取,我怎么算都觉得不值。想起来惠普喀嚓鱼曾经有过免费洗照片的优惠,算上运费应该也不比这贵,于是就干脆回来网上冲印算了。
回来先上网调研了一下,网上冲印看起来比较靠谱的有两家:惠普喀嚓鱼和网易印象派。比较了一下价格:单张照片网易印象派要便宜一些,6寸的照片,富士相纸 0.45 元一张,柯达相纸 0.6 元一张;考虑到运费和促销,惠普喀嚓鱼要便宜一些,喀嚓鱼开头免费送 10 张(首页上常年挂的免费 20 张是骗人的),超过 30 张运费就是 5 块而印象派的运费都是 8 块。
由于以前在卓越买东西喀嚓鱼老给我发优惠券,虽然一张都没来得及用,我想还是先试试它家的服务吧。为了凑齐 30 张省 5 块钱运费,我就拾掇拾掇把以前拍的一些照片觉得好的也拿出来洗了,总共凑了 33 张,算上运费是 18.8 元,平均每张合到 0.57 元。
我是 2010 年 4 月 21 日晚上 10 点左右下的单,22 日下午 5 点多通知我处理完成,23 日也就是今天中午 12 点多收到的照片。38 个小时,从这个速度来看,是相当快的了。
照片的包装是铜板纸袋外面套一层塑料封套,里面除了照片之外还有两张广告。照片用的是富士相纸,当时可选光面和磨砂的,我选的是光面的。总的来看觉得冲洗的效果很不错,我想这种成天大批量冲洗的网站,师傅手艺应该不会比一般照相馆差。
总之这次尝试让我觉得挺满意,以后有数码照片不用再专门跑照相馆去洗了。由于网上冲印又便宜又方便,看来以后实体冲洗店免不了遭受和实体书店相同的冲击。













近期评论