yum通过ssh代理安装

在机房的机器有时候请第三方服务公司安装完系统后没有检查网络,结果上不了网,最后连安装个gcc都不行。没有办法,只能通过代理安装,方法很简单。 需要有一台可以上网的linux机器,假设是A机器IP是192.168.1.100,另外一台不能上网的是B机器IP是192.168.2.200 用Xshell(或者其他ssh客户端)登录B机器,使用下面的命令登录到A机器: ssh -D 1080 root@192.168.1.100 输入A机器的密码,这时候ssh会开一个1080监听端口,所有发往这个端口的请求被转发到ssh所连接的机器,然后通过所连接的机器转发请求,这样就实现了ssh代理。ssh现在支持的协议是socks4和socks5。 然后在另外一个终端登录B机器,修改/etc/yum.conf文件,在文件最后添加下面一行: proxy=socks5h://localhost:1080 保存退出,这时候你再运行yum命令,完全不障碍。 其实都已经开了1080端口了,其他任何支持代理设置的程序都可以使用此socks5h://localhost:1080进行代理,比如: curl -x socks5h://localhost:1080 http://www.baidu.com 如果其他的方式,比如ftp之类的,也需要使用代码的话,可以把下面的内容保存到一个文件proxy.sh,然后使用source proxy.sh加载一下 #!/bin/sh # add follows to the end (set proxy settings to the environment variables) MY_PROXY_URL="socks5h://localhost:1080" HTTP_PROXY=$MY_PROXY_URL HTTPS_PROXY=$MY_PROXY_URL FTP_PROXY=$MY_PROXY_URL http_proxy=$MY_PROXY_URL https_proxy=$MY_PROXY_URL ftp_proxy=$MY_PROXY_URL export HTTP_PROXY HTTPS_PROXY FTP_PROXY http_proxy https_proxy ftp_proxy 例子 pip pip使用代理的时候有一点区别,需要把上面proxy.sh里面的协议socks5h修改成socks5才可以使用。 Enjoy ^_^.

July 7, 2018

使用Clojure开发Web入门系列(四)

在(三)介绍并使用了Hiccup这个生成html的库,甚是方便,但是对于前后端分离的一些web站点也不是太方便。接下来介绍另外一种方法来渲染html页面,selmer。如果你是一个PHP程序员,那么你会发现他跟smarty有几分相似。 零、添加依赖 在project.clj的dependencies添加[selmer "1.11.8"] 一、修改代码 修改系列三里面的代码到selmer实现。 home 首先在resources目录下添加home.html,内容如下: <h1>Home</h1> 在resources目录添加是因为selmer默认会去classpath指定的路径里面找对应的模板文件。 修改core.clj,在:require后面添加selmer:[selmer.parser :refer [render-file]] 修改defroutes app,在添加一条路由规则: (GET "/home" [] (render-file "home.html" {})) 访问http://localhost:3000/home,可以看到html模板里面的内容已经显示出来了。如果没有运行程序请执行:lein run form 现在来修改表单页面,使用resources/index.html作为模板文件,内容如下: <!DOCTYPE html> <html> <body> <h1>Hello form</h1> <form action="/message" method="post"> <div> <label for="name">名字:</label> <input name="name" type="text" /> </div> <div> <label for="message">消息:</label> <textarea cols="80" name="message" rows="5"></textarea> </div> <div><input type="submit" value="提交" /></div> </form> </body> </html> 修改defroutes app里面"/"的定义为: (GET "/" [] (render-file "index.html" {})) 访问http://localhost:3000,表单出来了。 message 修改表单提交后的页面。 先在建立消息模板文件resources/message.html,内容如下: <!DOCTYPE html> <html> <body> <h2>{{ name }}</h2> <p>{{ message }}</p> </body> </html> {{ name }}和{{ message }}是占位符,selmer把render-file的第二个map参数解析到模板文件里面,{{ name }}对应的是:name的值。 ...

July 1, 2018

Solr开发分词插件

如果已经有了一个自定义的分词库,那要怎么才能集成到Solr里面去呢,本文带你一步一步入坑–不对–,带你集成自定义分词库。 如果还没有自定义的分词库,希望写自己的Solr分词插件,可以先参考自定义Lucene的分词器Analyzer 根据自定义Lucene的分词器Analyzer一文,假设现在已经具备了DemoTokenizer类。因为在Solr里面可以只需要Tokenizer就可以了,而不一定需要Analyzer。 先看一下Solr里schema配置分词的定义: <fieldType name="text_demo" class="solr.TextField" positionIncrementGap="100"> <analyzer> <tokenizer class="com.example.lucene.DemoTokenizerFactory" wordType="hello" /> <!-- some other filters --> <filter class="solr.LowerCaseFilterFactory"/> </analyzer> </fieldType> 这里配置了一个字段类型为text_demo,使用了com.example.lucene.DemoTokenizerFactory这个工厂方法来处理对应字段的分词,同时还设置了一个属性wordType值为hello,在后面的代码中读取这个属性的值。这里配置了DemoTokenizerFactory分词处理类,那么就必须要有这么一个类了: package com.example.lucene; import org.apache.lucene.analysis.Tokenizer; import org.apache.lucene.analysis.util.TokenizerFactory; import org.apache.lucene.util.AttributeFactory; import java.util.Map; // 需要继承org.apache.lucene.analysis.util.TokenizerFactory类并实现create方法 public class DemoTokenizerFactory extends TokenizerFactory { // 可以保存在上面schema定义的额外的属性参数 private String wordType = ""; // 需要一个构造方法,通过构造方法的args参数来读取schema设置的自定义的参数 public DemoTokenizerFactory(Map<String, String> args) { super(args); // 调用完父类的构造函数后,可以读取schema里tokenizer节点定义的wordType参数 // 保存在类属性里面,然后在create方法来使用这个传入的参数 wordType = args.getOrDefault("wordType", ""); } @Override public Tokenizer create(AttributeFactory factory) { // 在这里直接new一个tokenizer对象即可 return new DemoTokenizer(); } } 通过上面定义的DemoTokenizerFactory工厂类,就可以提供Solr需要的自定义分词功能了。如果你的自定义分词器需要额外的参数,比如调用一个rest api来进行分词,需要一个host和port,就可以通过在schema定义属性的办法来使分词可以更有弹性和适应不同的rest api而不需要改Solr自定义分词代码。 ...

May 19, 2018

Solr实现句子段落搜索

如果想要在Solr实现在某个句子/段落搜索的话,需要一点点技巧来达到这个需求。首先是在索引的时候做一点点手脚,然后再查询的时候再用点魔法就可以实现了。 索引处理 假设有一个文档,内容字段包含如下文本: sentence abc. sentence axx. another paragraph, sentence xyz. 这里有四个句子,以半角的.分割;两个段落,空行分割。 在索引的时候,先把句子拆开,使用content.sentence字段来索引每个句子,content.sentence为多值类型的字段。同样的处理方法把段落分开,使用content.paragraph字段来索引每个段落。配置如下 <field name="content.sentence" type="text" indexed="true" stored="true" multiValued="true"/> <field name="content.paragraph" type="text" indexed="true" stored="true" multiValued="true"/> 索引里面的一点小技巧就是在配置分词的时候,设置positionIncrementGap参数,假设下面是配置text这个fieldtype: <fieldType name="text" class="solr.TextField" positionIncrementGap="501"> 这里设置positionIncrementGap为501,为啥是501后面详细说明。索引数据的时候记得拆分句子和段落到对应的字段,对应字段是数组类型,如句子: {"content.sentence": ["sentence abc.", "sentence axx.", "another paragraph.", "sentence xyz."]} 到这里索引就配置完了。 查询魔法 说是魔法,其实也就是一点小技巧,使用Solr的phrase query,然后设置slop即可。比如在句子中查询: q=content.sentence:"sentence abc"~500 这个意思就是在content.sentence字段查询短语sentence abc,slop设置为500。 slop的意思是经过多少个步骤可以转换成sentence abc。这个跟编辑距离的概念是一样的,具体Solr/Lucene内部使用得是什么距离需要去阅读源码(或者看文档)。 多值字段每一个内容在保存位置信息的时候会根据positionIncrementGap的值设置偏移,如果第一个值最后的position是2,那么第二个值的开始就是2+positionIncrementGap。 这里的查询用得是500,上面索引配置的是501,差一个位置就可以确保前一个值和后一个值中间隔开500个字符,由于这个值是固定的,所以要确保一个段落要在500个词以内才可以。句子也是一样的道理。

April 17, 2018

Python的日志模块

Python3的日志模块(logging)简单而又强大,通过简单的配置可以实现日志写入不同的地方,对于开发和线上环境的debug有很大的帮助。 超简单例子 一个简单的例子 import logging logging.warning('Watch out!') # 打印输出到控制台 logging.info('I told you so') # 不会打印输出 如果保存为python文件(example.py),然后在控制台运行(python example.py)将看到下面的输出: WARNING:root:Watch out! 默认情况logging模块只会输出WARNING级别以及往上的ERROR, CRITICAL级别的消息。 写入到文件 import logging logging.basicConfig(filename='example.log',level=logging.DEBUG) logging.debug('This message should go to the log file') logging.info('So should this') logging.warning('And this, too') 保存为example2.py,运行python example2.py后,打开example.log文件,内容如下: DEBUG:root:This message should go to the log file INFO:root:So should this WARNING:root:And this, too 这个例子设置了日志级别为logging.DEBUG,日志文件也会记录相应级别的日志消息。 需要注意logging.basicConfig需要放在最前面调用,之后才可以调用logging.debug, logging.info。logging.basicConfig是一次性调用的函数,调用过一次,其他的调用将不再生效。 多次运行上面的例子,日志文件只会记录一次日志消息,如果要记录每次运行的消息,需要指定filemode参数: logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG) 从多个模块记录日志 假设你的项目由多个模块缓存,应该在程序入口处(或者在其他的调用info, debug函数之前)对日志模块进行配置。 # myapp.py import logging import mylib def main(): logging.basicConfig(filename='myapp.log', level=logging.INFO) logging.info('Started') mylib.do_something() logging.info('Finished') if __name__ == '__main__': main() # mylib.py import logging def do_something(): logging.info('Doing something') 运行myapp.py(python myapp.py)文件将会在myapp.log日志文件看到如下的输出信息: ...

March 27, 2018

Emacs下Python开发配置

Python开发环境配置其实比较简单,而我一直没有配置好是参照了网上各种各样的配置,导致了非常混乱的配置,这次自己亲自测试安装自己需要的Emacs包来配置。 需要的Emacs包 Elpy company-mode anaconda-mode 就这三个包就可以了。Elpy是一个很强大的Python集成开发环境了,后面两个其实就是做自动补全用的。如果启动Emacs后,执行M-x elpy-config没有办法出来配置的界面,可能是Emacs没有识别到python, pip, conda等命令,可以安装下面的包来解决: exec-path-from-shell 需要的Python包 Elpy的github页面已经列出来了: # Either of these pip install rope pip install jedi # flake8 for code checks pip install flake8 # and autopep8 for automatic PEP8 formatting pip install autopep8 # and yapf for code formatting pip install yapf 另外anaconda-mode需要安装setuptools pip install setuptools Emacs配置 下面是最简单的配置,~/.emacs.d/init.el (require 'package) (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/")) (package-initialize) (package-refresh-contents) (defvar my-packages '(elpy company anaconda-mode exec-path-from-shell)) (mapc #'(lambda (package) (unless (package-installed-p package) (package-install package))) my-packages) (exec-path-from-shell-initialize) (elpy-enable) (add-hook 'after-init-hook 'global-company-mode) (add-hook 'python-mode-hook 'anaconda-mode) (add-hook 'python-mode-hook 'anaconda-eldoc-mode) 常用按键 Keybinding Function Description M-. anaconda-mode-find-definitions 跳转到定义处。如果不使用anaconda-mode,则是绑定到elpy的elpy-goto-definition,elpy有时候工作得不是很好 M-? anaconda-mode-show-doc 在另外一个window中显示光标当前所在位置符号的文档 M-, anaconda-mode-find-assignments 跳转到变量赋值位置 M-r anaconda-mode-find-references 在另外一个window中显示光标当前所在位置变量的所有引用 M-* anaconda-mode-go-back 返回上一个位置 show一下我的.emacs.d配置,欢迎交流。

March 20, 2018

Solr控制脚本参考

Solr包含了一个命令行工具bin/solr可以用来执行非常多的常用操作。可以启动、停止Solr,创建删除collection/core,对ZooKeeper的操作,以及检查solr状态和配置分片。 bin/solr的使用格式如下: bin/solr cmd [options] 启动 Start 启动与重启 start命令用来启动solr。restart可以用来重启solr,不管是从停止状态还是在运行状态。 start和restart有很多的选项,可以指定运行在SolrCloud模式,可以使用自带的样例配置集,同时还可以指定hostname, port, ZooKeeper。 bin/solr start [options] bin/solr start -help bin/solr restart [options] bin/solr restart -help 当使用restart命令时,命令参数必须与start的命令参数一致。重启的过程是先执行stop命令停止solr,然后再启动solr,所以restart的参数必须要跟start的参数一致。 启动参数 bin/solr命令行脚本提供了非常多的选项来定制solr服务,例如改变监听的端口。其实默认的参数已经能够满足很多情况的需求了。 -a "<string>" 指定JVM参数,例如-X。如果是以-D传递的JVM参数,-a选项可以忽略。 Example: bin/solr start -a "-Xdebug -Xrunjdwp:transport=dt_socket, server=y,suspend=n,address=1044" -cloud 在SolrCloud模式启动,同时启动内置的ZooKeeper。这个选项可以简写为:-c。如果已经有一个ZooKeeper实例在运行,可以使用-z选项参数替换内置的ZooKeeper。查看更多SolrCloud细节。 Example:bin/solr start -c -d <dir> 定义server目录,默认为server。server目录的作用是提供web服务,rest api。这个选项一般不需要覆盖。当在同一台机器启动多个solr实例时,更常用的办法是使用-s选项来指定不同的solr.home,以存放不同的配置和数据。 Example:bin/solr start -d newServerDir -e <name> 以样例配置启动solr。solr提供的这些样例配置以帮助你快速开始熟悉solr的使用,或者某些特性。 这些样例包括: cloud techproducts dih schemaless 点击Running with Example Configurations查看详情。 Example:bin/solr start -e schemaless -f 在前台运行。使用-e选项的时候此选项不能使用。 Example:bin/solr start -f -h <hostname> 指定hostname,如果此选项没有指定,默认使用localhost。 ...

March 19, 2018

Solr7中的learnin to rank使用

什么是learning to rank在此往篇文章不做介绍,这里只介绍如何使用。主要针对cloud模式启动的solr。使用的版本是solr-7.1.0,本文以外的请参考官方文档 安装 solr-ltr-7.1.0.jar已经自带在solr的发行包里面,只需要在solrconfig.xml配置即可,把下面的内容添加到solrconfig.xml <lib dir="${solr.install.dir:../../../..}/dist/" regex="solr-ltr-\d.*\.jar" /> <queryParser name="ltr" class="org.apache.solr.ltr.search.LTRQParserPlugin"/> <cache name="QUERY_DOC_FV" class="solr.search.LRUCache" size="4096" initialSize="2048" autowarmCount="4096" regenerator="solr.search.NoOpRegenerator" /> <transformer name="features" class="org.apache.solr.ltr.response.transform.LTRFeatureLoggerTransformerFactory"> <str name="fvCacheName">QUERY_DOC_FV</str> </transformer> 添加了以上的配置后还需要把dist目录下的solr-ltr-7.1.0.jar拷贝到server/solr-webapp/webapp/WEB-INF/lib/目录下面,如果不添加的话,用rest api设置model的时候会报class not found exception。 上传feature [ { "store": "featureStore", "name": "title", "class": "org.apache.solr.ltr.feature.SolrFeature", "params": { "q": "{!func}query({!v=title:${query}})" } }, { "store": "featureStore", "name": "content", "class": "org.apache.solr.ltr.feature.SolrFeature", "params": { "q": "{!func}query({!v=content:${query}})" } }, { "store": "featureStore", "name": "originalScore", "class": "org.apache.solr.ltr.feature.OriginalScoreFeature", "params": {} }, { "store": "featureStore", "name": "level", "class": "org.apache.solr.ltr.feature.FieldValueFeature", "params": { "field": "level" } }, { "store": "featureStore", "name": "year", "class": "org.apache.solr.ltr.feature.FieldValueFeature", "params": { "field": "year" } } ] 上面是四个feature: ...

March 19, 2018

Java快速排序算法

来一个Java版本的快速排序。 public class QuickSort { public static void main(String[] args) { int[] arr = {5, 2, 4, 7, 1, 8, 3, 4}; printArray(arr); quickSort(arr, 0, arr.length - 1); printArray(arr); } static void quickSort(int[] arr, int i, int j) { if (i < j) { int pos = partition(arr, i, j); printArray(arr); System.out.println("分别排左边和右边"); quickSort(arr, 0, pos - 1); quickSort(arr, pos + 1, j); } } static int partition(int[] arr, int i, int j) { int pivot = arr[j]; System.out.println("基准值:" + pivot); int cursor = i; System.out.println("游标:" + cursor); for (int k = i; k < j; k++) { System.out.println("循环到第[" + k + "]个值"); if (arr[k] <= pivot) { System.out.println("交换位置[" + cursor + "]与[" + k + "]的值"); swap(arr, k, cursor); cursor += 1; } System.out.print("循环完成后:"); printArray(arr); System.out.println("游标:" + cursor); } System.out.println("交换位置[" + cursor + "]与[" + j + "]的值"); swap(arr, j, cursor); System.out.println("游标:" + cursor); return cursor; } static void swap(int[] arr, int i, int j) { int tmp = arr[i]; arr[i] = arr[j]; arr[j] = tmp; } static void printArray(int[] arr) { StringBuilder sb = new StringBuilder(); for (int anArr : arr) { sb.append(anArr).append(" "); } System.out.println(sb.toString().trim()); } } 输出如下: ...

March 12, 2018

Clojure压缩目录为zip

创建zip压缩文件主要思想: 创建ZipOutputStream 创建ZipEntry,并调用putNextEntry copy文件到output stream 调用closeEntry关闭entry (require '[clojure.java.io :as io] '[clojure.string :as str]) (import (java.io FileOutputStream) (java.util.zip ZipEntry ZipOutputStream)) (defn zip-dir "以zip格式压缩目录path" [path zip-file] (let [root-path (.toPath (io/file path))] (with-open [zip (ZipOutputStream. (FileOutputStream. zip-file))] (doseq [f (file-seq (io/file path))] (let [p (.toPath f) subpath (str/replace (str (.relativize root-path p)) "\\" "/") path-name (if (.isDirectory f) (str subpath "/") subpath)] (when-not (= "" subpath) (.putNextEntry zip (ZipEntry. path-name)) (when (.isFile f) (io/copy f zip)) (.closeEntry zip))))))) 特别需要注意: ...

March 8, 2018