我们几乎每天都做这样的操作,输入账号和密码登陆跳转机,从跳转机输入帐号和密码登陆目标机器。当然输入账号和密码登陆跳转机可以在SecureCRT这些客户端中建立登录会话解决,可是后面这一步呢?事实上,后面这一步可以写一个脚本解决。

例如现在需要登录192.168.1.1这台机器,登录用户名和密码都为test,而要登录192.168.1.1,需要先登录到跳板机172.168.1.1,则我们可以新建会话链接192.168.1.1,在其中的会话选项中,ssh2中填上登录172.168.1.1需要的用户名和密码,在登录动作中,我们可以引用一个登录脚本。这里的登录动作指的是登录机器后需要进行的后续操作,在我们这里指的是登录跳板机后需要进行的操作,这当然是登录我们的目标主机了,于是可以写脚本,脚本的内容如下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#$language = "VBScript"

#$interface = "1.0"
Sub main
' turn on synchronous mode so we don't miss any data
crt.Screen.Synchronous = True
crt.Screen.Send "ssh test@192.168.1.1" & VbCr
' Wait for a tring that looks like "password: " or "Password: "
crt.Screen.WaitForString "assword:"
' Send your password followed by a carriage return
crt.Screen.Send "test" & VbCr
' turn off synchronous mode to restore normal input processing
crt.Screen.Synchronous = False
End Sub

如此,我们只需要在SecureCRT中点击一下这个会话,就可以登录到192.168.1.1这台服务器了,是不是很方便?

联系作者

相信现在很多人还在用Solr1.4,因为Solr1.4许多时候还是满足需求了。可是总有一天会想升级,因为新版本中的一些功能和特性让使用Solr更加方便。而如果要从Solr1.4升级到Solr4.8,可以经过Solr1.4->Solr3.6->Solr4.0->Solr4.8这个步骤.

从Solr1.4->Solr3.6,去官网下载Solr3.6,使用需要升级的索引搭建起Solr引擎,执行curl ‘http://localhost:8983/solr/update?optimize=true&maxSegments=1&waitFlush=false‘ 即可

从Solr3.6->Solr4.0,去官网下载Solr4.0, 将lucene-core-4.0.jar拷贝到某一目录下,如:lib4.0/lucene-core-4.0.jar(注意,可能需要其它的包如:slf-api和log-back相关包,同样拷贝到lib4.0目录下), 之后执行java -cp “lib4.0/*” org.apache.lucene.index.IndexUpgrader -verbose index/, 这里 index目录存放着Solr3.6索引文件。

从Solr4.0->Solr4.8, 去官网下载Solr4.8,将lucene-core-4.8拷贝到某一目录下, 如:lib4.0/lucene-core-4.8.jar,之后执行../jdk1.7/bin/java -cp “lib4.8/*” org.apache.lucene.index.IndexUpgrader -delete-prior-commits -verbose index/,这里因为Solr4.8需要用到jdk1.7,所以执行java命令时,必须是jdk1.7。

联系作者

软连接和硬链接是Linux中经常用到的,详细介绍可以参考https://www.ibm.com/developerworks/cn/linux/l-cn-hardandsymb-links/

要知道软连接和硬链接的区别,必须知道了解Linux的文件系统设计,这其中就有inode这个概念。一个文件被分为用户数据和元数据,其中用户数据是数据存储的地方,而元数据中的inode则是指向这个地方,而文件名只是便于人们记忆而已。对于inode号,可以使用stat或者ls -i查看.

一个inode号可以对应多个文件名,这种情况下就是硬链接。因此创建硬链接并不需要拷贝用户数据,也就是不像cp命令那样,新创建一个inode号,所以创建硬链接速度非常快。只是硬链接有一个局限的地方就是只能对文件创建硬链接,并且不能跨越文件系统。需要注意的一个问题是,修改硬连接,原文件的内容也会修改。而修改原文件,也会修改硬连接。

而创建软连接则会创建新的inode号,只是这个inode号指向的用户数据很特殊,它指向创建软连接的文件。对于软连接,则没有硬链接的那些限制,它可以跨越文件系统,可以对目录创建软链接。只是当把原文件删除后,软连接就变成了死链接了。

联系作者

Solr关键概念

1.反向索引
2.检索词和布尔查询:
并查询:
+new +house 或者
new AND house
或查询:
new house 或者
new OR house
排除查询:
new house –rental 或者
new house NOT rental
短语查询:
“new home” OR “new house”
3 bedrooms” AND “walk in closet” AND “granite countertops”
分组查询:
New AND (house OR (home NOT improvement NOT depot NOT grown))
(+(buying purchasing -renting) +(home house residence –(+property -bedroom)))

对于短语查询,之所以可以实现,是因为在反向索引中保存了词在文档中的位置信息。

3.模糊查询
通配符查询:
如果需要查询以offic开头的词,只需要查询 offic
如果要使用通配符在开头的查询,如
ing,则需要将ReversedWildcardFilterFactory添加到字段分析链中

范围查询:
yearsOld:[18 TO 21] 18 <= x <= 21
yearsOld:{18 TO 21} 18 < x < 21
yearsOld:[18 TO 21} 18 <= x < 21
created:[2012-02-01T00:00.0Z TO 2012-08-02T00:00.0Z]

编辑距离查询:
administrator~ 默认编辑距离为1
administrator~1 编辑距离为1
administrator~2 编辑距离为2

临近查询:
“chief officer”~1 距离为1
例如: “chief executive officer”, “officer chief”

4.相关性:
Solr默认相关性,距离看文档

5.准确率和召回率
准确率说的是一次查询中,查询结果有多少是相关的比率
召回率说的是一次查询中,有多少相关结果被返回的比率

一般来说,搜索引擎都是尽量在二者中寻求一个平衡

6.Solr的一些局限
Solr无法执行想数据库查询那样复杂的查询
当更新一个跨越很多个文档的字段时,Solr将很麻烦
对于返回许多文档的查询,Solr的性能将会下降

联系作者

最近迷上了单元测试,在写单元测试时,提示一下错误:
java.lang.NoSuchMethodError: junit.framework.ComparisonFailure.getExpected()Ljava/lang/String;

莫名其妙的,assertFalse怎么可能没有。后来才知道,原来是版本冲突了,因为添加了好多个junit的jar本,而Eclipse只找到最低版本的,将一些低版本的jar去掉就好了。

添加jar这个问题真是蛋疼,在Eclipse里对引用的jar一个目录一个目录的添加,还要肉眼去把低版本的删除,真是麻烦。

联系作者

虽然在索引组,但有时还需要干解析的活,而这时,正则表达式就派上用场了。一段时间没写正则后,写起来就没有办法那么畅快,例如这次就是提取不到结果,想了之后,最后锁定在点号不能匹配换行符,试了之后,果然是这样。在Java中,加上Pattern.DOTALL就好了,以下就是用来提取雪球搜索页面里主要内容的函数,这个主要内容提取出来后是一个JSON格式的.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static String getXueQiuContent(String httpBody) {
Pattern pattern = Pattern.compile("SNB.data.search\\s*?=\\s*?(\\{.+?\\});.*?seajs.use", Pattern.DOTALL);
Matcher m = pattern.matcher(httpBody);
if (m.find()) {
httpBody = m.group(1);
JSONObject obj;
try {
obj = new JSONObject(httpBody);
JSONArray jsonArr = (JSONArray) obj.get("list");
httpBody = jsonArr.toString();
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
return httpBody;
}

如果不知道这个Pattern.DOTALL,其实用[\s\S]也是可以得,因为\s匹配空白字符,\S匹配非空白字符,两者合在一起就可以匹配任何字符了。
对于爬虫组来说,要发现新的站点,都雪球这些网站去搜索一番还是可以尝试的。

联系作者

最近因为负责一个小功能,所以想尽力做好它。于是对会经常看看用户的查询,看看这些查询的结果是否满足需要,于是需要对这些查询词进行提取。本来还想用Python来写的,后来想想shell才是做这事的最佳方法,于是先从grep开始。

solr的日志中,query都是跟在‘q=’后面,且参数间用&隔开,于是执行如下命令,
grep -o ‘q=.*\&’ solr.log
得到如下结果
q=磐安&macro.skip=0&qt=macro&wt=json&
q=磐安+财政&macro.skip=0&qt=macro&wt=json&
q=保定+财政&macro.skip=0&qt=macro&wt=json&
q=磐安+财政&macro.skip=0&qt=macro&wt=json&
q=财政+长春&macro.skip=0&qt=macro&wt=json&
q=财政+长沙&macro.skip=0&qt=macro&wt=json&
q=存款收入&macro.skip=0&qt=macro&wt=json&
q=存款收入&qt=macro&wt=json&macro.groupOffset=0&macro.groupNames=利率走势&
q=存款收入&qt=macro&wt=json&macro.groupOffset=0&macro.groupNames=行业经济&
q=存款收入&qt=macro&wt=json&macro.groupOffset=0&macro.groupNames=区域宏观&
q=存款收入&qt=macro&wt=json&macro.groupOffset=0&macro.groupNames=中国宏观&

之后就是截取query部分,这时awk就派上用场了。先用&分割,得到第一段,之后用=分割,得到第二段
grep -o ‘q=.*\&’ solr.log | grep -v ‘module2:’ | grep -v ‘solrconfig.xml’ | awk -F ‘&’ ‘{print $1}’ | awk -F ‘=’ ‘{print $2}’
结果如下:
磐安
磐安+财政
保定+财政
磐安+财政
财政+长春
财政+长沙
存款收入
存款收入
存款收入
存款收入
存款收入

之后想统计每个查询词的次数,此时先用sort排序,之后用uniq -c来统计,
grep -o ‘q=.*\&’ solr.log | grep -v ‘module2:’ | grep -v ‘solrconfig.xml’ | awk -F ‘&’ ‘{print $1}’ | awk -F ‘=’ ‘{print $2}’ |sort | uniq -c
结果如下:
1 保定+财政
5 存款收入
1 磐安
2 磐安+财政
1 财政+长春
1 财政+长沙

而我希望按查询次数从高到低排列,于是再用sort -rn
grep -o ‘q=.*\&’ solr.log | grep -v ‘module2:’ | grep -v ‘solrconfig.xml’ | awk -F ‘&’ ‘{print $1}’ | awk -F ‘=’ ‘{print $2}’ |sort | uniq -c | sort -rn
结果如下:
5 存款收入
2 磐安+财政
1 财政+长沙
1 财政+长春
1 磐安
1 保定+财政

一行代码搞定。一句话,管道实在是太方便了,linux也是如此。

联系作者

最近一个项目需要用脚本生成汉字拼音时来排序,组里同事说以前有同事写过一个,于是拿过来用,看了一下代码,发现有些地方还是可以优化的,

如以下代码:

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
self.polyphone = {}
for line in open(polyphone_path):
k, context, pron, other = line.split(' ', 3)
item = collections.defaultdict(dict)
key = "%X" % ord(unicode(k, 'utf8'))
item[key]['context'] = unicode(context, 'utf8')

item[key]['pron'] = pron
if self.polyphone.has_key(key):
self.polyphone[key].append(item)
else:
self.polyphone[key] = []
self.polyphone[key].append(item)
```
这一段代码里需要判断字典里有没有包含key,如果没有,则要先声明value为空的list,之后再添加值,这种情况下collections中的defaultdict就派上用场了。
``` python
self.polyphone = defaultdict(list)
for line in open(polyphone_path):
k, context, pron, other = line.split(' ', 3)
item = defaultdict(dict)
key = "%X" % ord(unicode(k, 'utf8'))
item[key]['context'] = unicode(context, 'utf8')
item[key]['pron'] = pron
self.polyphone[key].append(item)
```
defaultdict可以给定一个默认值,这样省去了判断key是否已经在字典里存在。

还见到如下代码:
``` python
polyphone = False
for item in self.polyphone[key]:
if chars.find(item[key]['context']) != -1:
result.append(item[key]['pron'].strip()[:-1].lower())
polyphone = True
break

if not polyphone:
result.append(self.dict[key].split(",")[0].strip()[:-1].lower())

这段代码里,if not polyphonse判断里的句子只有在上面的for没有被break时才执行,也就是for循环执行时才执行,这种情况在编程中经常遇到,而python提供了for else循环语句,于是可以修改成:

1
2
3
4
5
6
for item in self.polyphone[key]:
if chars.find(item[key]['context']) != -1:
result.append(item[key]['pron'].strip()[:-1].lower())
break
else :
result.append(self.dict[key].split(",")[0].strip()[:-1].lower())

是不是瞬间简洁很多?所以说,语言特性还是有必要学习的,虽然算法和数据结构依然是核心,可是代码易维护,易懂也是非常重要的

联系作者

如要查看8080端口被进程占用,以前都是用 lsof命令的,
lsof -i:8080

现在lsof命令不能用了,于是改成netstat
netstat -nltp | grep 8080

以前执行这个命令时没有加上p参数,后来仔细看netstat的帮助,知道p参数是显示进程id和名字用的

联系作者

以前专门考虑过这个问题,只是没有记录笔记,和组里的同事说起这个问题,于是又考虑了一次,这次还是记下来为妙。

13球问题说的是有12个标准球和1个不合格的球,这个球可能偏重或者偏轻了,给你一个天平,问至少称多少次可以找到这个不合格的球。

考虑这个问题之前,可以先考虑高中时代,数学老师问过的8球问题。8球问题说的是一共有8个球,其中有一个球偏重了,给你一个天平,问至少称几次可以找到这个球。

一个很显然的办法是,两边各4个,之后拿重的一方再对分称,之后再拿重的一方对分称,一共三次就可以称出来。但这不是最优的,记得当时大部分同学都是这么考虑的,只有一个许杨冰同学不是这样,她说称两次即可知道。方法是,左边放三个,右边放三个,如果是左边重,则球一定在这3个中,从这个三个中取两个,天平两边各放一个,如果两边一样重,则偏重的球是剩下的那一个,如果两边不一样重,则偏重的一方就是那个球。当时就觉得许同学非同一般,后来高考时她考了全班第一。

大三的时候,学习了信息论,发现这个问题可以用信息论的观点来解释。考虑上面的8球问题,当只有3个球时,只称一次即可知道是哪一个球偏重了,也就是说,一次称球,可以知道3种情况,那么2此称球就可以知道9种情况。而8球问题,只有8种情况,所以只需称两次即可找到那个球。考虑上面的13球问题,这里一共有26种情况,1号球偏重,1号球偏轻,2号球偏重,2号球偏轻。。。,因为两次称球可以知道9种情况,那么三次称球可以知道27种情况,而13球一共只有26中情况,所以13球问题只需称3次就可以找到那个球,剩下的问题就是如何称了。

考虑之后,给出了一种解法。为了方便,我们给球编号,1,2,3,4,,,13。
1.首先把1,2,3,4放在左边天平,把5,6,7,8放在右边天平,
2.如果天平一样重,则那个球在剩下的5个球中,其它8个为标准球。之后在这5个球中取3个球,放在左边,取3个标准球放在天平右边,分三种情况
A 如果一样重,则不合格球在剩下的两个球中,对于剩下的两个球,取其中一个出来称,如果偏重或者偏轻,则找到了那个不合格球,如果一样重,则不合格球是剩下的一个(注意,这里我们不能知道它是偏重或者偏轻)。
B 如果左边轻,之后再称一次就可以知道是哪个球偏轻。
C 如果左边重,之后再称一次就可以知道是哪个球偏轻。
3.如果不一样重,则那个球在这8个球中。假设是左边重了,则剩下可能的8种情况,1,2,3,4号偏重,5,6,7,8号偏轻。之后的取法可以这样,左边放三个标准球再加上8号球,右边放5,6,7和4号球。依然分三种情况
A 如果一样重,则1 2 3号球偏重,称一次即可知道结果
B 如果左边重,则5 6 7 号球偏轻,称一次即可知道结果
C 如果左边轻,则8号球偏轻或者4号球偏重,称一次即可知道结果。

现在再来考虑,2时,剩下5个球的情况,5个球的时候,一共有10种情况,9号偏重,9号偏轻,,,13号偏重,所以称两次是无法知道具体是哪一个球偏重或者偏轻,这也是为什么在2的A情况中,如果一样重,则不合格球是剩下的一个,但我们无法知道它是偏重或者偏轻。所幸题目只要求我们找到那个球就可以了,没有要求知道它是偏重或者偏轻。

那么如果一定要找到那个球,且知道它是偏重或者偏轻呢?这样的话就不是这种方法能解决的了,需要精心设计的方法,继续考虑,等知道了再分享。

联系作者