有些时侯我们想知道一个文件的某一行在哪一个版本里被谁修改的,此时git blame就派上用场了。

官方文档里描述如下

1
git-blame - Show what revision and author last modified each line of a file

  • git blame foo 查看foo文件的修改记录
  • git blame -L 20, 30 foo 查看foo文件从20行到30行的修改记录
  • git blame -L 20, +30 foo 查看foo文件20行开始的30行修改记录

参考资料:

联系作者

在使用git的过程中经常遇到这个问题。明明使用git status看到Your branch is up-to-date with 'origin/dev'. , 但添加自己的修改,提交之后,发现远程分支已经有了修改。这是为何?现在终于明白这个原因。

这里设计到三个概念,本地的dev, 本地的origin/dev, 远程的dev。上面提示中的origin/dev指的是本地的origin/dev,而不是远程的dev. 虽然本地的dev is up-to-date with本地的origin/dev但,origin/dev并没有与远程的dev同步。所以当我们向远程dev push时,才会提示有冲突。

要想让本地的origin/dev与远程的dev同步,可以执行 git fetch origin dev, 发现有了更新

1
2
* branch            dev        -> FETCH_HEAD
078c7d1..d71d504 dev -> origin/dev

此时再次执行git status, 就会提示已经落后了, Your branch is behind 'origin/dev' by 8 commits, and can be fast-forwarded.

之后使用merge命令将本地的origin/dev合并到本地的dev中git merge --no-ff origin/dev

参考资料:

联系作者

当你在一个分支中进行修改时,想切换到另外一个分支,但你目前的修改还不能commit, 因为是不完整的,此时stash命令就可以派上用场。

使用git stash操作将目前的操作保持起来,然后切换到另外一个分支,干活完成后再切回来。此时使用git stash apply将之前的操作恢复。

此外还有一些stash操作如

  • git stash list 列出所有储藏
  • git stash drop 丢弃储藏
  • git stash pop 应用并丢弃储藏

有一个需要注意的是,在一个分支中stash起来的修改,也可以应用于其它分支。所以git stash apply时一定要注意分支是否匹配。

其实这也隐藏了stash的一个功能。当你在一个分支上进行修改时,发现你想修改的是另外一个分支,此时你不想reset掉修改。stash派上用场了,先git stash将修改保存起来,然后切换到另外一个分支,之后git stash apply, 这样修改就应用与另外一个分支了。

参考资料:

联系作者

在公司的代码里见到下面两个正则,我认为可以进行优化,所以拿出来说说。

  • url(r'^api/(?P<model>(sku|hiring|news|enterprisenews)+)/?$')

这个正则的目的主要是匹配sku,hiring,news等模块,然而它也可以匹配skusku,skuhiring等等,这并不是我想要的。虽然最终不影响代码执行,但能够精确的就应该精确,因为计算机如此精确。所以把+号去掉是最好的写法。

  • var reg = /^.+\/(activitydocument\/.+)$/;

这里正则的目的是将http://.../activitydocument/...等链接替换成activitydocument/..., 因为+号是贪婪的,所以它会一直匹配到末尾,然后开始往回退,这样会影响性能。正确的做法是使用非贪婪。即改成/^.+?\/(activitydocument\/.+)$/;

在《正则指引》中,P305页有一个匹配HTML tag的例子,
</?[a-z][-a-z0-9_:.]*(?=[\s>])('[^']*'|"[^"]*"|[^'">])*>,但它不能匹配
等标签,以及不能匹配HTML注释,需要另外处理。

联系作者

自从写了Elasticsearch从MySQL到数据,收到几位同学的来信,主要是问如何使用elasticsearch-jdbc进行增量数据导入,这里还是写写具体操作。这里以从Wordpress导数据为例。

Elasticsearch准备

  • 新建索引

curl -XPUT ‘localhost:9200/article?pretty’

  • 新建type

curl -XPUT ‘localhost:9200/article/_mappings/blog’ -d ‘@mapping.json’

mapping.json内容

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
{
"_all": {
"enabled" : true,
"analyzer": "ik_max_word_syno",
"search_analyzer": "ik_smart"
}
,

"properties": {
"id": {
"type": "string",
"index": "not_analyzed",
"include_in_all": false
}
,

"title": {
"type": "string",
"analyzer": "ik_max_word_syno",
"search_analyzer": "ik_smart",
"boost": 2
}
,

"content": {
"type": "string",
"analyzer": "ik_max_word_syno",
"search_analyzer": "ik_smart"
}

}

}

分词配置可参看
Elatcissearch中ik添加同义词

  • 查看mapping
    curl -XGET ‘localhost:9200/article/_mapping’

elasticsearch-jdbc配置

到elasticsearch-jdbc的bin目录下,查看mysql-blog.sh文件, 内容如下

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
#!/bin/sh

DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
bin=${DIR}/../bin
lib=${DIR}/../lib

echo '
{
"type" : "jdbc",
"jdbc" : {
"url" : "jdbc:mysql://localhost:3306/blog",
"statefile" : "statefile.json",
"schedule" : "0 0-59 0-23 ? * *",
"user" : "blog",
"password" : "12345678",
"sql" : [{
"statement": "select id as _id, id, post_title as title, post_content as content from wp_posts where post_status = ? and post_modified > ? ",
"parameter": ["publish", "$metrics.lastexecutionstart"]}
],
"index" : "article",
"type" : "blog",
"metrics": {
"enabled" : true
},
"elasticsearch" : {
"cluster" : "elasticsearch",
"host" : "localhost",
"port" : 9300
}
}
}
' | java \
-cp "${lib}/*" \
-Dlog4j.configurationFile=${bin}/log4j2.xml \
org.xbib.tools.Runner \
org.xbib.tools.JDBCImporter

这里主要看两个配置, statefile和schedule,

其中statefile这个配置对于增量导数据一定不能少。因为只有配置了statefile,elasticsearch-jdbc才知道将上次抓取时间存在哪里,才可以做增量索引。

schedule的作用与crontab类似,用来固定时间执行增量导数据,具体用法参看文档活着crontab。

查看结果

http://localhost:9200/article/blog/_search?q=test

在配置elasticsearch-jdbc的过程中,查看日志很重要。日志文件在bin目录下的logs里,可以修改log4j2.xml文件,把日志等级改为debug以查看更多日志。

联系作者

最近在看《Python学习手册》,看到多继承部分,对于函数查找以为使用广度优先,查找MRO文档才发现使用C3算法

对于class C(p1, p2, …, pn), mro(c) = [c] + merge(mro(p1), mro(p2), …, mro(pn), [p1, p2, …, pn])

而其中merge的规则是,从左到右选取第一个在列表中是头,在其它列表中也是头的类,将这个类加入到mro中,并将它从merge中移除,然后继续merge直到结束。如果不能找到这样的头,则无法构造类,将会报错。

举个例子,对于

1
2
3
4
5
6
7
8
9
10
O = object
class F(O): pass
class E(O): pass
class D(O): pass
class C(D,F): pass
class B(E,D): pass
class A(B,C): pass

if __name__ == "__main__":
print A.mro()

查找顺序是

1
[<class '__main__.A'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.F'>, <type 'object'>]

计算过程如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
mro(F) = [F, O]
mro(E) = [E, O]
mro(D) = [D, O]
mro(C) = [C] + merge([D, O], [F, O], [D, F])
= [C, D] + merge([O], [F, O], [F])
= [C, D, F] + merge([O], [O])
= [C, D, F, O]
mro(B) = [B] + merge([E, O], [D, O], [E, D])
= [B, E] + merge([O], [D, O], [D])
= [B, E, D] + merge([O], [O])
= [B, E, D, O]
mro(A) = [A] + merge([B, E, D, O], [C, D, F, O], [B, C])
= [A, B] + merge([E, D, O], [C, D, F, O], [C])
= [A, B, E] + merge([D, O], [C, D, F, O], [C])
= [A, B, E, C] + merge([D, O], [D, F, O])
= [A, B, E, C, D] + merge([O], [F, O])
= [A, B, E, C, D, F] + merge([O], [O])
= [A, B, E, C, D, F, O]

联系作者

最近公司说要做智能推荐,于是想起了协同过滤,想到了Slope One算法,虽然以前看过这个算法,但没有记笔记,这次只好从头看起,好在Slope One比较容易。

Wiki上看了介绍,印象中有人用Python写了一个非常简洁的版本,于是在网上找。在这里找到详细说明,在这里找到代码。

u\v i i
u1 3 2
u2 4 2
u3 5 ?

对于上表中,使用 Slope One算法来预测用户u3对j 的评分具体过程是这样的:首先计算项目i和j的偏差,即((3 – 2) + (4 – 2)) / 2 = 1.5,之后预测用户u3对j的评分就可以这样计算5 – 1.5 = 3.5。

之后自己写了一个版本

联系作者

因为Oryx推荐引擎需要用到Spark, 所以开始了解Spark,

按照使用Spark MLlib给豆瓣用户推荐电影写了一个Python版本, 算是有了一个初步了解。只是不知道推荐效果怎样,关键是不好测试效果。

使用的过程中遇到一个问题

org.apache.hadoop.mapred.InvalidInputException: Input path does not exist: hdfs://localhost:9000/user/long/README.md

这是在执行官方文档例子quickstart例子时遇到,

1
2
>>> textFile = sc.textFile("README.md")
>>> textFile.count()

一直想不通,后来想到在测试Oryx的例子时,在conf/spark-env.sh里配置了HADOOP_CONF_DIR,把它注释掉即可。

而之所以之前配置了HADOOP_CONF_DIR, 是因为在执行Oryx的例子时,会使用bin/spark-submit –master yarn-client提交,此时如果没有配置HADOOP_CONF_DIR, 会报Exception in thread “main” java.lang.Exception: When running with master ‘yarn-client’ either HADOOP_CONF_DIR or YARN_CONF_DIR must be set in the environment.错误。

参考文章

联系作者

之前是用Django自带的Paginator进行分页。在每一个需要分页的view都要添加分页处理,而使用django-pagination, 则只需要在模版里添加即可。于是开始使用django-pagination。使用的过程中发现以下问题

‘WSGIRequest’ object has no attribute ‘REQUEST’

这是因为REQUEST对象已经在Django1.9中丢弃. 进入python的lib目录,进入lib/python2.7/site-packages/pagination, 将middleware.py里的return int(self.REQUEST[‘page’])改为return int(self.GET[‘page’])

sequence index must be integer, not ‘slice’

这是因为xrange对象不能进行slice操作,进入templatetags,将pagination_tags.py,paginate函数里的page_range = paginator.page_range改为 page_range = list(paginator.page_range)

很郁闷的是,django-pagination的github仓库里的程序没有更新,而且报TOKEN_BLOCK错误,估计是这个commit中引入的。

于是只好fork出一份,自己修改。参见product分支

联系作者

以前使用virtualenv来隔离Python环境。最近知道了virtualenvwrapper, 才知道之前使用virtualenv的方法不对,而virtualenv也有一些不便,而virtualenvwrapper就是用来解决这些不便。

  • 统一环境存储位置
  • 方便环境切换

具体查看virtualwapper官方文档。工欲善其事,必先利其器确实很有道理。

想想以前花费在Windowns系统安装和软件安装的时间,太不值了。

联系作者