2年来,从码农到技术总监,我在一家金融科技公司经历了什么?

背景:我就职于一家金融科技公司,主要是做大数据风控业务。刚开始加入这个团队的时候我是第一个写代码的人,到今天需要管理一支近40人的技术团队,这个过程无论以后什么时候回想起来必定都是终身难忘的,所以希望今天借此机会复盘,和大家分享一下一路走来踩过的一些坑和从中学习到的教训或经验。

继续阅读2年来,从码农到技术总监,我在一家金融科技公司经历了什么?

centos 6.5 安装tesseract

给服务器安装tesseract

安装Tesseract-OCR
准备工作:
编译环境: gcc gcc-c++ make(这个环境一般机器都具备,可以忽略)
yum install gcc gcc-c++ make
依赖的包: autoconf automake libtool libjpeg-devel libpng-devel libtiff-devel zlib-devel leptonica(1.68)

autoconf automake libtool libjpeg-devel libpng-devel libtiff-devel zlib-devel 可以通过yum安装:

yum install autoconf automake libtool
yum install libjpeg-devel libpng-devel libtiff-devel zlib-devel

2. leptonica 需要源码编译安装
参考资料:
http://paramountideas.com/tesseract-ocr-30-and-leptonica-installation-centos-55-and-opensuse-113
http://www.leptonica.org/source/README.html
下载 leptonica 包: http://www.leptonica.org/source/leptonica-1.68.tar.gz
解压后切换到 leptonica-1.68 根目录

./configure
make
make install
tesseract安装:
依赖安装完毕后开始安装tesseract
下载 tesseract-3.01 安装包: http://tesseract-ocr.googlecode.com/files/tesseract-3.01.tar.gz
解压后切换到 tesseract-3.01 根目录
(如果在make时遇到类似 strngs.h:1: error: stray ‘\357’ in program 的错误,请将 tesseract-3.01/ccutil/strngs.h 文件转为 ANSI 编码保存,再重新编译)
./autogen.sh
./configure
make
make install
ldconfig
tesseract英文语言包安装:
下载 tesseract-3.01 英文语言包: http://tesseract-ocr.googlecode.com/files/tesseract-ocr-3.01.eng.tar.gz
解压后将 tesseract-ocr/tessdata 下的所有文件全部拷贝到 /usr/local/share/tessdata 下
安装完毕.
测试一下:
切换到解压后的 tesseract-3.01 根目录(这个目录下有一个自带的 phototest.tif 可以做测试用)
命令行:
tesseract phototest.tif result -l eng
输出:
Tesseract Open Source OCR Engine v3.01 with Leptonica
Page 0
这时应该在当前目录生成一个 result.txt 文本文件,内容就是 phototest.tif 显示的文字.

mac安装tesseract

做一个验证码识别的工作,
这个还是有一堆坑的,
具体的安装包需要的可以联系我zhu_qing@icekredit.com
我说下安装的步骤,我是os x yosemite。
安装的顺序,
jpeg->zlib->pil->leptonica->tesseract
安装jpeg/zlib/pil详见上一篇文章
其他都是./configure 再make && make install
最后把eng.traneddata.gz解压到/usr/local/share/tessdata,
测试, tessract imgae.jpeg result -l eng 结果会输出到当前目前的result.txt中

dnsmasq – 小团队科学上网利器

好些天没更博了,给大家分享一个最近发现的科学上网利器,特别适合小团队内部用。

相关配置:centos 6.6 final server一台、作为dns服务器

相关文件:可以关注我的项目,单机用户可以顺便在这里看一下科学上网ip的使用方法:https://github.com/ching1221/google-ips

0、修改、创建dnsmasq使用的resolv文件


$ echo 'nameserver 127.0.0.1' >> /etc/resolv.conf

$ cp /etc/resolv.conf /etc/resolv.dnsmasq.conf

$ echo 'nameserver 8.8.8.8' >> /etc/resolv.dnsmasq.conf

1、安装dnsmasq

在服务器安装即可:

$ yum install dnsmasq

2、配置文件在/etc/dnsmasq.conf

addn-hosts=你git的hosts文件的路径  // 通过git同步(ip我会定期更新)。
listen-address=0.0.0.0
resolv-file=/etc/resolv.dnsmasq.conf

3、修改iptables,打开53端口的数据进出。(注意是udp)

$ vim /etc/sysconfig/iptables 复制一下22那条,把tcp->udp, 22->53即可。

4、开启服务、设置开机服务

$ service dnsmasq start
$ chkconfig dnsmasq --level 2345

5、让其他主机的dns首选项设置为你的服务器内网ip地址
6、更多,如果你想随时随地用…
把服务器的53端口通过路由器等设备设置虚拟服务器转发,外部53端口-服务器53端口..ok,你在外的时候,可以把dns指向你的外部ip地址,随时随地畅享科学上网..
这里唯一需要我们做的就是维护这个表,我的建议就是,写个脚本,cd到你为这个项目设置的git路径,然后自动每天某个时刻git pull origin(你设置的项目名称) master 一下,这样子再service dnsmasq restart即可:


updateIps.sh:

#!/bin/bash

cd $(dirname $0) || {
 exit
}
git pull origin master
service dnsmasq restart
$ crontab -e
02 4 * * * yourpathto/updateIps.sh

OK,介于这个项目我在维护,所以按照以上操作你完全不用操任何心了。

nginx 禁止访问某个目录

直接给一个部署了dokuwiki的实例,因为要保护data/ conf/ bin/  inc/ 下的文件,所以通过nginx来禁止从web访问指定目录下的文件:

假设我的dokuwiki是位于我网站根目录下的,则要保护这几个目录不被访问的方法是:

根目录:   root  /home/wwwroot/default;

1. 禁止访问某个具体的目录路径以及某个文件
location = /config/ {  #注意只是不能访问http://website.xx/config/而已,其下面的文件都可以访问,比如/config/data.txt
return 404;
}
location =/config.ini{  #不能访问http://website.xx/config.ini
return 404;
}

2. 禁止访问某个目录下所有的文件

比如不想别人访问我dokuwiki目录下的data/

则可以

location ^~/dokuwiki/conf/{

return 404;

}

如果是想显示禁止访问(403),可以把return 404; -> deny all;

板瓦工vps之vpn搭建

最近实在需要科学上网,搞了个vps. 简单说下怎么配置,以及让更多人分享。。

如果是在板瓦工买的,那么可以在ctrlpanel直接开openvpn server,可以下载一个初始的,当然,前提是你只是一个人用..

如果要给更多的小伙伴配置认证信息,看我说的。

ssh你的vps,

cd /

find ./ -name openvpn

一般情况下,你会在/etc/openvpn下找到

cd /etc/openvpn/2.0 你就可以看到一系列配置openvpn的操作。

其中,我们用的到的:

生成客户端 key
# ./build-key client1
Generating a 1024 bit RSA private key
…………++++++
………………………………………………..++++++
writing new private key to ‘client1.key
—–
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter ‘.’, the field will be left blank.
—–
Country Name (2 letter code) [CN]:
State or Province Name (full name) [SH]:
Locality Name (eg, city) [PD]:
Organization Name (eg, company) [ching]:
Organizational Unit Name (eg, section) []:ching
Common Name (eg, your name or your server’s hostname) [client1]:client1 #重要: 每个不同的client 生成的证书, 名字必须不同.
Name []:
Email Address [905407204@qq.com]:
Please enter the following ‘extra‘ attributes
to be sent with your certificate request
A challenge password []:xxxxxx
An optional company name []:
Using configuration from /etc/openvpn/2.0/openssl-1.0.0.cnf
Check that the request matches the signature
Signature ok
The Subject’s Distinguished Name is as follows
countryName           :PRINTABLE:‘CN’
stateOrProvinceName   :PRINTABLE:‘SH’
localityName          :PRINTABLE:‘PD’
organizationName      :PRINTABLE:‘ching
organizationalUnitName:PRINTABLE:‘ching’
commonName            :PRINTABLE:‘client1’
emailAddress          :IA5STRING:‘2990945@qq.com’
Certificate is to be certified until Aug  13 20:15:50 2025 GMT (3650 days)
Sign the certificate? [y/n]:y
1 out of 1 certificate requests certified, commit? [y/n]y
Write out database with 1 new entries
Data Base Updated
以此类推建立其他客户端 key
# ./build-key client2
# ./build-key client3
然后通过tar zcvf allkeys.tar.gz keys/* 先打包keys,再通过:

  scp -P yourserverSSHport root@ip:/etc/openvpn/easy-rsa/2.0/allkeys.tar.gz ./

其中

E3B26AB3-048E-4A43-A9B9-D78A6BFFA5B8

提供给tunnelblick类的软件使用(我自己给自己生成了一个叫ching的客户端),localhost.localdomain.opvn不一定叫这个名字,记得看keys文件夹下.ovpn结尾的即可,还要记得修改里面的内容:

client

remote 45.78.9.232 1194

dev tun

comp-lzo

ca ca.crt

cert ching.crt

key ching.key

route-delay 2

route-method exe

redirect-gateway def1

dhcp-option DNS 8.8.8.8

dhcp-option DNS 8.8.4.4

dhcp-option DNS 4.2.2.1

dhcp-option DNS 4.2.2.2

verb 3

更加完整的配置(从0到1)请参考:

http://blog.chinaunix.net/uid-26835604-id-3484906.html

 

 

文档型数据库设计模式-如何存储树形数据 [转]

突发奇想,怎么去实现一个树形关系的数据库结构,看到一篇文章,非常好。分享一下。

原文:http://seancribbs.com/tech/2009/09/28/modeling-a-tree-in-a-document-database/

在数据库中存储树形结构的数据,这是一个非常普遍的需求,典型的比如论坛系统的版块关系。在传统的关系型数据库中,就已经产生了各种解决方案。

此文以存储树形结构数据为需求,分别描述了利用关系型数据库和文档型数据库作为存储的几种设计模式。

A.关系型数据库设计模式1

id name parent_id
1 A NULL
2 B 1
3 C 1
4 D 2

上图表示了传统的设计方法之一,就是将树形结构的每一个结点作为关系型数据库中的一行进行存储,每一个结点保存一个其父结点的指针。

  • 优点:结构简单易懂,插入修改操作都很简单
  • 缺点:如果要获取某个结点的所有子结点,将是一件很恶心的事

B.关系型数据库设计模式2

id name parent_id left right
1 A NULL 1 8
2 B 1 2 5
3 C 1 6 7
4 D 2 3 4

上图在模式1的基础上多了两列,left和right,相当于btree中的左右分支,分别存储了左右分支结点的最大值和最小值。

(对这个更进一步的理解,可以看下http://blog.csdn.net/monkey_d_meng/article/details/6647488这篇文章中的第三条:基于左右值编码的Schema设计

  • 优点:要查找一个结点的子结点很容易,只需要做一个范围查询就行了(比如B节点的子结点,只需要查询 id >=2 && id<=5)
  • 缺点:由于树结构存在在这里面了,所以添加或修改已存在结点将可能产生连锁反应,操作过于复杂

C.文档型数据库设计模式1

{
  "name": "A",
  "children": [
    {"name": "B", "children": [{"name": "D"}]},
    {"name": "C"}
  ]
}

将整个树结构存成一个文档,文档结构既树型结构,简明易懂。

  • 优点:简明易懂
  • 缺点:文档会越来越大,对所有结点的修改都集中到这一个文档中,并发操作受限

D.文档型数据库设计模式2

{"_id": "A", "children": ["B", "C"]}
{"_id": "B", "children": ["D"]}
{"_id": "C"}
{"_id": "D"}

将每个结点的所有子结点存起来

  • 优点:结构简单,查找子结点方便
  • 缺点:查找父结点会比较麻烦

E.文档型数据库设计模式3

{
  "leaf": "A",
  "children": [
    {"leaf": "B", "children": [{"leaf": "D"}] },
    {"leaf": "C"}
  ]
}
{"_id": "A", ...}
{"_id": "B", ...}
{"_id": "C", ...}
{"_id": "D", ...}

充分利用文档型存储schema-less的优点,先利用上面C方案存存储一个大的树形文档,再将每一个结点的其他信息单独存储。

  • 优点:操作方便,结构上的操作可以直接操作大的树形文档,数据上的操作也只需要操作单条数据
  • 缺点:对所有结点的修改都集中到这一个文档中,并发操作受限

20150806@Tencent 数学建模分享

来这个team之后被安排到做数据挖掘,最近也在折腾推荐系统,不是简单的做个算法,更多的其实对我的挑战是学习hadoop,编写mapreduce。

因为之前参加过两次数学建模竞赛,空隙中做了一次关于数学建模的分享,自己其实也有很多不足的地方,不过接触更多工程后,理解更深刻,更能体会掌握一些数学模型后对解决实际问题时找到突破口是非常有帮助的。

下面是我本次分享的ppt:

http://chingzhu.com/share/20150806@tencent.pptx

主要有对数学模型的一个概览;

了解一次建模过程;

对目前常见的推荐系统方法的一个介绍;

对item cf的一个实现;

对latent factor算法的一个介绍;

以及比较好用的降维方法(pca)的介绍。

记录一下LimeSurvey的安装

帮同学安装一下limesurvey, 因为其要请我吃饭 …  哈哈..

顺手记录一下咯..

这是一个基于web的调查系统, 同学是win8,最开始看其官网提供了一个基于windows集成了xampp的安装包,but it doesn’t work,同学说他装的时候遇到的问题是php版本太低,我在他电脑上装的时候发现是数据库配置不正确,不管哪种可能,都觉得这种自带集成的没有我自己配置操作的来的好,来的清晰。

于是选择了第二种方法,就是自己先搭一个本地web服务器,然后再安装lime。并且此种方法适用于linux, osx, windows.

1 . 下载最新版xampp(我这是1.8.3-0-VC11),可以保证php mysql等版本都比较新,(要求mysql 4.1 ⬆️ ,php over 5.3 ⬆️)也带有官网说的需要支持的mbstring库。可以通过localhost/xampp查看phpinfo()哈,确保开启了。(安装完成后用xammp-control打开apache web server及mysql database,浏览器输入localhost看是否进入xampp管理页面确保是否安装成功哈。)

2. 下载limesurvey包,我在官网上下的最新的limesurvey206plus-build150629,而后解压到xampp/htdocs下,文件名随便你取,最好不要带特殊字符啥的以免被转义。(这里我命名为lime)

3. 上述都搞定后,在lime文件夹下打开admin/index.php,可以看到默认的配置是application下的config.php,但是我们去到这个文件夹下,是没有的,而在index.php中可以看见,当这个文件不存在的时候,调用的是-config-sample-mysql.php这个里面的配置(这个跟wordpress的安装很像哈),再打开config-sample-mysql.php,可以看见里面有一个array,定义了mysql的连接,其中dbname=limesurvey, 而实际上我们打开phpmyadmin,查看数据库列表,并没有这个数据库,这个是为什么我们直接在浏览器中打开localhost/lime,进入初始化配置时,点击不了下一步的原因,因为数据库中没有这个库,所以在数据库连接时,这一步就被卡死了。有兴趣的可以看一下,根目录下有一个installer/sql下的create-mysql.sql的文件,里面只有创建表的,但是没有对应的创建对应的数据库,所以需要我们先把数据库建好。mysql:host=localhost;port=3306;dbname=limesurvey; 这句就已经帮我们选择了db, 即相当于执行了 USE limesurvey; 然后初始化的时候再调用这个sql来创建里面的表。 ok, 现在就很清楚了,我们只用在这一步直接利用phpmyadmin创建一个名为limesurvey的数据库就ok。

4. 然后我们再打开localhost/lime,会跳转到初始化配置界面,一步一步按你的喜好填完即可。

5. 打开localhost/lime/admin,进入管理界面(利用你上一步填写的管理账号及密码)

done

(转)程序员应该知道的浮点数知识

昨儿在群里看见师兄分享的,说的很对。做前端,特别容易忘本。我想以后有时间,应该多抽出来看看底层的东西。

一个有趣的实验

本文从一个有趣而诡异的实验开始。最早这个例子博主是从 Stackoverflow上的一个问题中看到的。为了提高可读性,博主这里做了改写,简化成了以下两段代码:

#include <iostream>

#include <string>

using namespace std;

int main() {

const float x=1.1;

const float z=1.123;

float y=x;

for(int j=0;j<90000000;j++)

{

y*=x;

y/=z;

y+=0.1f;

y-=0.1f;

}

return 0;

}

#include <iostream>

#include <string>

using namespace std;

int main() {

const float x=1.1;

const float z=1.123;

float y=x;

for(int j=0;j<90000000;j++)

{

y*=x;

y/=z;

y+=0;

y-=0;

}

return 0;

}

上面两段代码的唯一差别就是第一段代码中y+=0.1f,而第二段代码中是y+=0。由于y会先加后减同样一个数值,照理说这两段代码的作用和效率应该是完全一样的,当然也是没有任何逻辑意义的。假设现在我告诉你:其中一段代码的效率要比另一段慢7倍。想必读者会认为一定是y+=0.1f的那段慢,毕竟它和y+=0相比看上去要多一些运算。但是,实验结果,却出乎意料, y+=0的那段代码比y+=0.1f足足慢了7倍。 。世界观被颠覆了有木有?博主是在自己的Macbook Pro上进行的测试,有兴趣的读者也可以在自己的笔记本上试试。(只要是支持SSE2指令集的CPU都会有相似的结果)。

shell> g++ code1.c -o test1

shell> g++ code2.c -o test2

shell> time ./test1

real 0m1.490s

user 0m1.483s

sys 0m0.003s

shell> time ./test2

real 0m9.895s

user 0m9.871s

sys 0m0.009s

当然 原文中的投票最高的回答解释的非常好,但博主第一次看的时候是一头雾水,因为大部分基础知识已经还给大学老师了。所以,本着知其然还要知其所以然的态度,博主做了一个详尽的分析和思路整理过程。也希望读者能够从0开始解释这个诡异现象的原因。

复习浮点数的二进制转换

现在让我们复习大学计算机基础课程。如果你熟练掌握了浮点数向二进制表达式转换的方法,那么你可以跳过这节。

我们先来看下浮点数二进制表达的三个组成部分。

6406401FFB692C-F8BD-42D8-A80A-440863ECBB40

三个主要成分是:

  • Sign(1bit):表示浮点数是正数还是负数。0表示正数,1表示负数
  • Exponent(8bits):指数部分。类似于科学技术法中的M*10^N中的N,只不过这里是以2为底数而不是10。需要注意的是,这部分中是以2^7-1即127,也即01111111代表2^0,转换时需要根据127作偏移调整。(这里我补充下原理:2^0, 0+127 = 01111111)
  • Mantissa(23bits):基数部分。浮点数具体数值的实际表示。
  • 下面我们来看个实际例子来解释下转换过程。

Step 1 改写整数部分

以数值5.2为例。先不考虑指数部分,我们先单纯的将十进制数改写成二进制。

整数部分很简单,5.即101.。

Step 2 改写小数部分

小数部分我们相当于拆成是2^-1一直到2^-N的和。例如:

0.2 = 0.125+0.0625+0.007825+0.00390625即2^-3+2^-4+2^-7+2^-8….,也即.00110011001100110011

Step 3 规格化

现在我们已经有了这么一串二进制101.00110011001100110011。然后我们要将它规格化,也叫Normalize。其实原理很简单就是保证小数点前只有一个bit。于是我们就得到了以下表示:1.0100110011001100110011 * 2^2。到此为止我们已经把改写工作完成,接下来就是要把bit填充到三个组成部分中去了。

Step 4 填充

指数部分(Exponent):之前说过需要以127作为偏移量调整。因此2的2次方,指数部分偏移成2+127即129,表示成10000001填入。

整数部分(Mantissa):除了简单的填入外,需要特别解释的地方是1.010011中的整数部分1在填充时被舍去了。因为规格化后的数值整部部分总是为1。那大家可能有疑问了,省略整数部分后岂不是1.010011和0.010011就混淆了么?其实并不会,如果你仔细看下后者:会发现他并不是一个规格化的二进制,可以改写成1.0011 * 2^-2。所以省略小数点前的一个bit不会造成任何两个浮点数的混淆。

具体填充后的结果见下图

 

FC6A5127-8141-470F-AA9B-49D6A33EA5CE

练习:如果想考验自己是否充分理解这节内容的话,可以随便写一个浮点数尝试转换。通过 浮点二进制转换工具可以验证答案。

什么是Denormalized Number

了解完浮点数的表达以后,不难看出浮点数的精度和指数范围有很大关系。最低不能低过2^-7-1最高不能高过2^8-1(其中剔除了指数部分全0和全1的特殊情况)。如果超出表达范围那么不得不舍弃末尾的那些小数,我们成为overflow和underflow。甚至有时舍弃都无法表示,例如当我们要表示一个:1.00001111*2^-7这样的超小数值的时候就无法用规格化数值表示,如果不想点其他办法的话,CPU内部就只能把它当做0来处理。那么,这样做有什么问题呢?最显然易见的一种副作用就是:当多次做低精度浮点数舍弃的后,就会出现除数为0的exception,导致异常。当然精度失准严重起来也可以要人命,以下这个事件摘自wikipedia

On 25 February 1991, a loss of significance in a MIM-104 Patriot missile battery prevented it intercepting an incoming Scud missile in Dhahran, Saudi Arabia, contributing to the death of 28 soldiers from the U.S. Army’s 14th Quartermaster Detachment.[25] See also: Failure at Dhahran

于是乎就出现了Denormalized Number(后称非规格化浮点)。他和规格浮点的区别在于,规格浮点约定小数点前一位默认是1。而非规格浮点约定小数点前一位可以为0,这样小数精度就相当于多了最多2^22范围。

但是,精度的提升是有代价的。由于CPU硬件只支持,或者默认对一个32bit的二进制使用规格化解码。因此需要支持32bit非规格数值的转码和计算的话,需要额外的编码标识,也就是需要额外的硬件或者软件层面的支持。以下是wiki上的两端摘抄,说明了非规格化计算的效率非常低。> 一般来说,由软件对非规格化浮点数进行处理将带来极大的性能损失,而由硬件处理的情况会稍好一些,但在多数现代处理器上这样的操作仍是缓慢的。极端情况下,规格化浮点数操作可能比硬件支持的非规格化浮点数操作快100倍。

For example when using NVIDIA’s CUDA platform, on gaming cards, calculations with double precision take 3 to 24 times longer to complete than calculations using single precision.

如果要解释为什么有如此大的性能损耗,那就要需要涉及电路设计了,超出了博主的知识范围。当然万能的wiki也是有答案的,有兴趣的读者可以自行查阅。

回到实验

总上面的分析中我们得出了以下结论:

  • 浮点数表示范围有限,精度受限于指数和底数部分的长度,超过精度的小数部分将会被舍弃(underflow)
  • 为了表示更高精度的浮点数,出现了非规格化浮点数,但是他的计算成本非常高。

于是我们就可以发现通过几十上百次的循环后,y中存放的数值无限接近于零。CPU将他表示为精度更高的非规格化浮点。而当y+0.1f时为了保留跟重要的底数部分,之后无限接近0(也即y之前存的数值)被舍弃,当y-0.1f后,y又退化为了规格化浮点数。并且之后的每次y*x和y/z时,CPU都执行的是规划化浮点运算。

而当y+0,由于加上0值后的y仍然可以被表示为非规格化浮点,因此整个循环的四次运算中CPU都会使用非规格浮点计算,效率就大大降低了。

其他

当然,也有在程序内部也是有办法控制非规范化浮点的使用的。在相关程序的上下文中加上fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);就可以迫使CPU放弃使用非规范化浮点计算,提高性能。我们用这种办法修改上面实验中的代码后,y+=0的效率就和y+=0.1f就一样了。甚至还比y+=0.1f更快了些,世界观又端正了不是么:) 修改后的代码如下

#include <iostream>

#include <string>

#include <fenv.h>

using namespace std;

int main() {

fesetenv(FE_DFL_DISABLE_SSE_DENORMS_ENV);

const float x=1.1;

const float z=1.123;

float y=x;

for(int j=0;j<90000000;j++)

{

y*=x;

y/=z;

y+=0;

y-=0;

}

return 0;

}

Reference

  • 什么是非规格化浮点数
  • Why does changing 0.1f to 0 slow down performance by 10x?
  • IEEE floating point
  • Floating point
  • Denormal number