blogjava-凯发k8网页登录http://www.blogjava.net/libin2722/虚其心,可解天下之问;专其心,可治天下之学;静其心,可悟天下之理;恒其心,可成天下之业。zh-cnsat, 08 apr 2023 20:41:01 gmtsat, 08 apr 2023 20:41:01 gmt60身份证js校验http://www.blogjava.net/libin2722/archive/2017/04/14/432452.html礼物礼物fri, 14 apr 2017 02:37:00 gmthttp://www.blogjava.net/libin2722/archive/2017/04/14/432452.htmlhttp://www.blogjava.net/libin2722/comments/432452.htmlhttp://www.blogjava.net/libin2722/archive/2017/04/14/432452.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/432452.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/432452.html身份证号校验 ///校验参数配置项 if (!value) return false; if (value.length == 0) { return "身份证号不可以为空!"; } if (value.length != 18) { return "18位身份证号长度错误!"; } value = value.touppercase(); var city = { 11: "北京", 12: "天津", 13: "河北", 14: "山西", 15: "内蒙古", 21: "辽宁", 22: "吉林", 23: "黑龙江 ", 31: "上海", 32: "江苏", 33: "浙江", 34: "安徽", 35: "福建", 36: "江西", 37: "山东", 41: "河南", 42: "湖北 ", 43: "湖南", 44: "广东", 45: "广西", 46: "海南", 50: "重庆", 51: "四川", 52: "贵州", 53: "云南", 54: "西藏 ", 61: "陕西", 62: "甘肃", 63: "青海", 64: "宁夏", 65: "新疆", 71: "台湾", 81: "香港", 82: "澳门", 91: "国外 " }; if (!value || !/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[012])(0[1-9]|[012]\d|3[01])\d{3}(\d|x)$/i.test(value)) { return "身份证号码格式错误,请重新输入!"; } else if (!city[value.substr(0, 2)]) { return "无效的地区编码,请重新输入!"; } else { //18位身份证需要验证最后一位校验位 value = value.split(''); //∑(ai×wi)(mod 11) //加权因子 var factor = [7, 9, 10, 5, 8, 4, 2, 1, 6, 3, 7, 9, 10, 5, 8, 4, 2]; //校验位 var parity = [1, 0, 'x', 9, 8, 7, 6, 5, 4, 3, 2]; var sum = 0; var ai = 0; var wi = 0; for (var i = 0; i < 17; i ) { ai = value[i]; wi = factor[i]; sum = ai * wi; } var last = parity[sum % 11]; if (parity[sum % 11] != value[17]) { return "无效的身份证号,请重新输入!!"; } } return; },

礼物 2017-04-14 10:37
]]>
mysql导入.sql文件及常用命令http://www.blogjava.net/libin2722/articles/427346.html礼物礼物wed, 16 sep 2015 00:49:00 gmthttp://www.blogjava.net/libin2722/articles/427346.htmlhttp://www.blogjava.net/libin2722/comments/427346.htmlhttp://www.blogjava.net/libin2722/articles/427346.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/427346.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/427346.html mysql导入.sql文件及常用命令

在mysql qurey   brower中直接导入*.sql脚本,是不能一次执行多条sql命令的,在mysql中执行sql文件的命令:

mysql> source   d:/myprogram/database/db.sql;

另附mysql常用命令:

一) 连接mysql:

    格式: mysql -h主机地址 -u用户名 -p用户密码

1、例1:连接到本机上的mysql

    首先在打开dos窗口,然后进入mysql安装目录下的bin目录下,例如: d:/mysql/bin,再键入命令mysql -uroot -p,回车后提示你输密码,如果刚安装好mysql,超级用户root是没有密码的,故直接回车即可进入到mysql中了,mysql的提示符是:mysql>

2、例2:连接到远程主机上的mysql (远程:ip地址)

    假设远程主机的ip为:10.0.0.1,用户名为root,密码为123。则键入以下命令:

   mysql -h10.0.0.1 -uroot -p123

   (注:u与root可以不用加空格,其它也一样)

3、退出mysql命令

    exit (回车)

(二) 修改密码:

    格式:mysqladmin -u用户名 -p旧密码 password 新密码

1、例1:给root加个密码123。首先在dos下进入目录c:/mysql/bin,然后键入以下命令:

    mysqladmin -uroot -password 123

    注:因为开始时root没有密码,所以-p旧密码一项就可以省略了。

2、例2:再将root的密码改为456

    mysqladmin -uroot -pab12 password 456

(三) 增加新用户:(注意:和上面不同,下面的因为是mysql环境中的命令,所以后面都带一个分号作为命令结束符)

    格式:grant select on 数据库.* to 用户名@登录主机 identified by "密码"

    例1、增加一个用户test1密码为abc,让他可以在任何主机上登录,并对所有数据库有查询、插入、修改、删除的权限。首先用以root用户连入mysql,然后键入以下命令:     grant select,insert,update,delete on *.* to   identified by "abc";

    如果你不想test2有密码,可以再打一个命令将密码消掉。     grant select,insert,update,delete on mydb.* to   identified by "";

(四) 显示命令

1、显示数据库列表:

    show databases;     刚开始时才两个数据库:mysql和test。mysql库很重要它里面有mysql的系统信息,我们改密码和新增用户,实际上就是用这个库进行操作。

2、显示库中的数据表:

    use mysql; //打开库    show tables;

3、显示数据表的结构:

    describe 表名;

4、建库:

    create database 库名;

5、建表:

    use 库名;     create table 表名 (字段设定列表);

6、删库和删表:

    drop database 库名;     drop table 表名;

7、将表中记录清空:

    delete from 表名;

8、显示表中的记录:

    select * from 表名;

导出sql脚本

mysqldump -u 用户名 -p 数据库名 > 存放位置

mysqldump -u root -p test > c:/a.sql

导入sql脚本

mysql -u 用户名 -p 数据库名 < 存放位置

mysqljump -u root -p test < c:/a.sql

注意,test数据库必须已经存在

mysql导出导入命令的用例

1.导出整个数据库

mysqldump -u 用户名 -p 数据库名 > 导出的文件名

mysqldump -u wcnc -p smgp_apps_wcnc > wcnc.sql

2.导出一个表

mysqldump -u 用户名 -p 数据库名表名> 导出的文件名

mysqldump -u wcnc -p smgp_apps_wcnc users> wcnc_users.sql

3.导出一个数据库结构

mysqldump -u wcnc -p -d --add-drop-table smgp_apps_wcnc >d:wcnc_db.sql

-d 没有数据 --add-drop-table 在每个create语句之前增加一个drop table

4.导入数据库

常用source 命令

进入mysql数据库控制台,

如mysql -u root -p

mysql>use 数据库

然后使用source命令,后面参数为脚本文件(如这里用到的.sql)

mysql>source d:wcnc_db.sql



礼物 2015-09-16 08:49
]]>
error 2006 (hy000) at line xx: mysql server has gone away 解决方法 http://www.blogjava.net/libin2722/articles/427345.html礼物礼物wed, 16 sep 2015 00:48:00 gmthttp://www.blogjava.net/libin2722/articles/427345.htmlhttp://www.blogjava.net/libin2722/comments/427345.htmlhttp://www.blogjava.net/libin2722/articles/427345.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/427345.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/427345.html1.执行批量的mysql语句,例如备份恢复的时候,时间过长。
对应:修改my.cnf中的wait_timeout和interactive_timeout变量
在一些不便修改的情形下,如租用的空间,可以采取sql语句修改,如何做呢?

解决办法

找到my.ini文件

添加一句max_allowed_packet=16m,如果不行将16m再加大

加大wait_timeout也可起一定作用

eg:

wait_timeout=2880000
interactive_timeout = 2880000
max_allowed_packet = 100m

应用时记住重启数据库哦~~

除此之外,可能还有一些别的buffer_size的变量会影响到,也值得注意
例如
read_buffer_size
read_rnd_buffer_size


礼物 2015-09-16 08:48
]]>
ajax session timeout 超时 处理http://www.blogjava.net/libin2722/articles/407255.html礼物礼物thu, 05 dec 2013 08:11:00 gmthttp://www.blogjava.net/libin2722/articles/407255.htmlhttp://www.blogjava.net/libin2722/comments/407255.htmlhttp://www.blogjava.net/libin2722/articles/407255.html#feedback1http://www.blogjava.net/libin2722/comments/commentrss/407255.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/407255.html * author : larry li
 * date : 2013-12-5
 * email : larry.li@aicent.com
 */
var session = function() {
    var defaults = {
            title        : 'session notification',
            message      : 'your session is about to expire.',
            keepaliveurl : '/admin/session/keep-alive',
            redirurl     : '/account/timed-out',
            logouturl    : '/account/logout',
            warnafter    : 900000, // 15 minutes
            redirafter   : 1200000 // 20 minutes
    };
    
    var o = defaults, dialogtimer, redirtimer;
    
    var controlredirtimer = function(action) {
        switch(action) {
            case 'start':
                // dialog has been shown, if no action taken during redir period, redirect
                redirtimer = settimeout(function(){
                    window.location = o.redirurl;
                }, o.redirafter - o.warnafter);
                break;
    
            case 'stop':
                cleartimeout(redirtimer);
                break;
            case 'restart':
                cleartimeout(redirtimer);
                redirtimer = settimeout(function(){
                    window.location = o.redirurl;
                }, o.redirafter - o.warnafter);
                break;
        }
    };
    
    var controldialogtimer = function(action) {
        switch(action) {
            case 'start':
                dialogtimer = settimeout(function(){
                    $('#sessiontimeout-dialog').modal('show');
                    controlredirtimer('start');
                }, o.warnafter);
                break;
            case 'stop':
                cleartimeout(dialogtimer);
                break;
            case 'restart':
                cleartimeout(dialogtimer);
                dialogtimer = settimeout(function(){
                    $('#sessiontimeout-dialog').modal('show');
                    controlredirtimer('restart');
                }, o.warnafter);
                break;
        }
    };
    
    var dokeepalive = function() {
        $.ajax({
            type: 'post',
            url: o.keepaliveurl,
            success: function() {
                // stop redirect timer and restart warning timer
                controlredirtimer('restart');
                controldialogtimer('restart');
            }
        });
    };
    
    return {
        sessiontimeout: function(options) {
            if ( options ) { o = $.extend( defaults, options ); }
            
            var warning_dialog = '';
            
            $('body').append(warning_dialog);
            
            $('#sessiontimeout-dialog-logout').on('click', function () { window.location = o.logouturl; });
            
            $('#_close,#sessiontimeout-dialog-keepalive').click(function() {
                dokeepalive();
            });
            // begin warning period
            controldialogtimer('start');
        },
        
        sessiontimeoutkeepalive: function() {
            controlredirtimer('restart');
            controldialogtimer('restart');
        }
    };
}();

$(function() {
    session.sessiontimeout({
        title: 'session timeout notification',
        message: 'your session is about to expire.',
        keepaliveurl: contextpath '/admin/session/keep-alive',
        redirurl: contextpath '/account/login',
        logouturl: contextpath '/account/logout',
        warnafter: 1500000,
        redirafter: 1780000
    });
    
    $(document).ajaxcomplete(function() {
        session.sessiontimeoutkeepalive();
    });
});

礼物 2013-12-05 16:11
]]>
忘掉jquery,使用javascript原生apihttp://www.blogjava.net/libin2722/articles/406911.html礼物礼物thu, 28 nov 2013 01:31:00 gmthttp://www.blogjava.net/libin2722/articles/406911.htmlhttp://www.blogjava.net/libin2722/comments/406911.htmlhttp://www.blogjava.net/libin2722/articles/406911.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/406911.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/406911.html阅读全文

礼物 2013-11-28 09:31
]]>
ehcache详细解读http://www.blogjava.net/libin2722/articles/406569.html礼物礼物wed, 20 nov 2013 04:53:00 gmthttp://www.blogjava.net/libin2722/articles/406569.htmlhttp://www.blogjava.net/libin2722/comments/406569.htmlhttp://www.blogjava.net/libin2722/articles/406569.html#feedback1http://www.blogjava.net/libin2722/comments/commentrss/406569.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/406569.html阅读全文

礼物 2013-11-20 12:53
]]>
how can i print sql query result log with log4j?http://www.blogjava.net/libin2722/articles/405551.html礼物礼物wed, 23 oct 2013 06:34:00 gmthttp://www.blogjava.net/libin2722/articles/405551.htmlhttp://www.blogjava.net/libin2722/comments/405551.htmlhttp://www.blogjava.net/libin2722/articles/405551.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/405551.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/405551.html阅读全文

礼物 2013-10-23 14:34
]]>
repositorieshttp://www.blogjava.net/libin2722/articles/404849.html礼物礼物thu, 10 oct 2013 15:08:00 gmthttp://www.blogjava.net/libin2722/articles/404849.htmlhttp://www.blogjava.net/libin2722/comments/404849.htmlhttp://www.blogjava.net/libin2722/articles/404849.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/404849.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/404849.html atlassian http://maven.atlassian.com/repository/public true false maven.org.repo2 repository of maven.org http://search.maven.org/#search search.maven.org repository of maven.org http://search.maven.org itextpdf.com maven repository for itext http://maven.itextpdf.com repository.jboss.com jboss repository for maven http://repository.jboss.com snapshots.jboss.org jboss snapshot repository for maven http://snapshots.jboss.org/maven2 java.net repository of java.net http://download.java.net/maven/1 deltaset.org repository of deltaset http://deltaset.googlecode.com/svn/maven2 prime.com repository of primefaces http://repository.prime.com.tr/org com.springsource.repository.maven.milestone spring framework maven milestone releases (maven central format) http://maven.springframework.org/milestone maven-repository2.dev.java.net java.net repository for maven 2 http://download.java.net/maven/2 mvnrepository.com mvnrepository.com http://mvnrepository.com www.mvnbrowser.com www.mvnbrowser.com http://www.mvnbrowser.com objectweb objectweb repository http://maven.objectweb.org/maven2 ops4j.repository ops4j repository http://repository.ops4j.org/maven2 codehaus snapshots http://snapshots.repository.codehaus.org/ apache-maven-snapshots repository of snapshots http://repository.apache.org/snapshots apache.snapshots asf maven 2 snapshot http://people.apache.org/builds/struts/2.1.8.1/m2-staging-repository com.springsource.repository.maven.snapshot springsource enterprise bundle maven repository - springsource snapshot releases http://maven.springframework.org/snapshot

礼物 2013-10-10 23:08
]]>
ehcache 配置参数说明http://www.blogjava.net/libin2722/articles/404115.html礼物礼物mon, 16 sep 2013 02:43:00 gmthttp://www.blogjava.net/libin2722/articles/404115.htmlhttp://www.blogjava.net/libin2722/comments/404115.htmlhttp://www.blogjava.net/libin2722/articles/404115.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/404115.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/404115.html <   ehcache       xmlns:xsi   =   "http://www.w3.org/2001/xmlschema-instance"          xsi:nonamespaceschemalocation   =   "ehcache.xsd"   >       
     <   diskstore       path   =   "java.io.tmpdir"   />       
     <   defaultcache       
       maxelementsinmemory   =   "10000"       
       maxelementsondisk   =   "0"       
       eternal   =   "true"       
       overflowtodisk   =   "true"       
       diskpersistent   =   "false"       
       timetoidleseconds   =   "0"       
       timetoliveseconds   =   "0"       
       diskspoolbuffersizemb   =   "50"       
       diskexpirythreadintervalseconds   =   "120"       
       memorystoreevictionpolicy   =   "lfu"       
       />       
     <   cache       name   =   "mycache"       
       maxelementsinmemory   =   "100"       
       maxelementsondisk   =   "0"       
       eternal   =   "false"       
       overflowtodisk   =   "false"       
       diskpersistent   =   "false"       
       timetoidleseconds   =   "120"       
       timetoliveseconds   =   "120"       
       diskspoolbuffersizemb   =   "50"       
       diskexpirythreadintervalseconds   =   "120"       
       memorystoreevictionpolicy   =   "fifo"       
       />       
  ehcache   >
   
diskstore  :指定数据存储位置,可指定磁盘中的文件夹位置
defaultcache : 默认的管理策略

以下属性是必须的:
  1. name:  cache的名称,必须是唯一的(ehcache会把这个cache放到hashmap里)。
  2. maxelementsinmemory:   在内存中缓存的element的最大数目 
  3. maxelementsondisk:   在磁盘上缓存的element的最大数目,默认值为0,表示不限制。 
  4. eternal:   设定缓存的elements是否永远不过期。如果为true,则缓存的数据始终有效,如果为false那么还要根据timetoidleseconds,timetoliveseconds判断 
  5. overflowtodisk:  如果内存中数据超过内存限制,是否要缓存到磁盘上。

以下属性是可选的:  
  1. timetoidleseconds:  对象空闲时间,指对象在多长时间没有被访问就会失效。只对eternal为false的有效。默认值0,表示一直可以访问。
  2. timetoliveseconds:  对象存活时间,指对象从创建到失效所需要的时间。只对eternal为false的有效。默认值0,表示一直可以访问。
  3. diskpersistent:  是否在磁盘上持久化。指重启jvm后,数据是否有效。默认为false。
  4. diskexpirythreadintervalseconds:  对象检测线程运行时间间隔。标识对象状态的线程多长时间运行一次。
  5. diskspoolbuffersizemb:  diskstore使用的磁盘大小,默认值30mb。每个cache使用各自的diskstore。
  6. memorystoreevictionpolicy:  如果内存中数据超过内存限制,向磁盘缓存时的策略。默认值lru,可选fifo、lfu。
缓存的3 种清空策略  
fifo ,first in first out (先进先出).

lfu , less frequently used (最少使用).意思是一直以来最少被使用的。缓存的元素有一个hit 属性,hit 值最小的将会被清出缓存。

lru ,least recently used(最近最少使用). (ehcache 默认值).缓存的元素有一个时间戳,当缓存容量满了,而又需要腾出地方来缓存新的元素的时候,那么现有缓存元素中时间戳离当前时间最远的元素将被清出缓存。


礼物 2013-09-16 10:43
]]>
oschina架构中,依照“管理重于配置”的思路使用servlet设计的mvchttp://www.blogjava.net/libin2722/articles/403043.html礼物礼物mon, 19 aug 2013 08:41:00 gmthttp://www.blogjava.net/libin2722/articles/403043.htmlhttp://www.blogjava.net/libin2722/comments/403043.htmlhttp://www.blogjava.net/libin2722/articles/403043.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/403043.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/403043.htmlpackage my.mvc; import java.io.*; import java.lang.reflect.*; import java.net.urldecoder; import java.util.*; import javax.servlet.*; import javax.servlet.http.*; import my.db.dbexception; import my.util.resourceutils; import org.apache.commons.lang.stringutils; import org.apache.commons.lang.math.numberutils; /** * 业务处理方法入口,uri的映射逻辑: * /action/xxxxxx/xxxx -> com.dlog4j.action.xxxxxxaction.xxxx(req,res) *
	林花谢了春红,
	太匆匆,
	无奈朝来寒雨晚来风。
	胭脂泪,
	相留醉,
	几时重,
	自是人生长恨水长东。
 * 
* @author winter lau (http://my.oschina.net/javayou)
*/ public final class actionservlet extends httpservlet { private final static string error_page = "error_page"; private final static string goto_page = "goto_page"; private final static string this_page = "this_page"; private final static string error_msg = "error_msg"; private final static string utf_8 = "utf-8"; private list action_packages = null; private final static threadlocal g_json_enabled = new threadlocal(); @override public void init() throws servletexception { string tmp = getinitparameter("packages"); action_packages = arrays.aslist(stringutils.split(tmp,',')); string initial_actions = getinitparameter("initial_actions"); for(string action : stringutils.split(initial_actions,',')) try { _loadaction(action); } catch (exception e) { log("failed to initial action : " action, e); } } @override public void destroy() { for(object action : actions.values()){ try{ method dm = action.getclass().getmethod("destroy"); if(dm != null){ dm.invoke(action); log("!!!!!!!!! " action.getclass().getsimplename() " destroy !!!!!!!!!"); } }catch(nosuchmethodexception e){ }catch(exception e){ log("unabled to destroy action: " action.getclass().getsimplename(), e); } } super.destroy(); } @override protected void doget(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception { process(requestcontext.get(), false); } @override protected void dopost(httpservletrequest req, httpservletresponse resp) throws servletexception, ioexception { process(requestcontext.get(), true); } /** * 执行action方法并进行返回处理、异常处理 * @param req * @param resp * @param is_post * @throws servletexception * @throws ioexception */ protected void process(requestcontext req, boolean is_post) throws servletexception, ioexception { try{ req.response().setcontenttype("text/html;charset=utf-8"); if(_process(req, is_post)){ string gp = req.param(goto_page); if(stringutils.isnotblank(gp)) req.redirect(gp); } }catch(invocationtargetexception e){ throwable t = e.getcause(); if(t instanceof actionexception) handleactionexception(req, (actionexception)t); else if(t instanceof dbexception) handledbexception(req, (dbexception)t); else throw new servletexception(t); }catch(actionexception t){ handleactionexception(req, t); }catch(ioexception e){ throw e; }catch(dbexception e){ handledbexception(req, e); }catch(exception e){ log("exception in action process.", e); throw new servletexception(e); }finally{ g_json_enabled.remove(); } } /** * action业务异常 * @param req * @param resp * @param t * @throws servletexception * @throws ioexception */ protected void handleactionexception(requestcontext req, actionexception t) throws servletexception, ioexception { handleexception(req, t.getmessage()); } protected void handledbexception(requestcontext req, dbexception e) throws servletexception, ioexception { log("dbexception in action process.", e); handleexception(req, resourceutils.getstring("error", "database_exception", e.getcause().getmessage())); } /** * url解码 * * @param url * @param charset * @return */ private static string _decode { if (stringutils.isempty(url)) return ""; try { return urldecoder.decode(url, charset); } catch (exception e) { } return url; } protected void handleexception(requestcontext req, string msg) throws servletexception, ioexception { string ep = req.param(error_page); if(stringutils.isnotblank(ep)){ if(ep.charat(0)=='%') ep = _decode; ep = ep.trim(); if(ep.charat(0)!='/'){ req.redirect(req.contextpath() "/"); } else{ req.request().setattribute(error_msg, msg); req.forward(ep.trim()); } } else{ if(g_json_enabled.get()) req.output_json("msg", msg); else req.print(msg); } } /** * 业务逻辑处理 * @param req * @param resp * @param is_post_method * @throws illegalaccessexception * @throws instantiationexception * @throws ioexception * @throws servletexception * @throws ioexception * @throws invocationtargetexception * @throws illegalargumentexception */ private boolean _process(requestcontext req, boolean is_post) throws instantiationexception, illegalaccessexception, ioexception, illegalargumentexception, invocationtargetexception { string requesturi = req.uri(); string[] parts = stringutils.split(requesturi, '/'); if(parts.length<2){ req.not_found(); return false; } //加载action类 object action = this._loadaction(parts[1]); if(action == null){ req.not_found(); return false; } string action_method_name = (parts.length>2)?parts[2]:"index"; method m_action = this._getactionmethod(action, action_method_name); if(m_action == null){ req.not_found(); return false; } //判断action方法是否只支持post if (!is_post && m_action.isannotationpresent(annotation.postmethod.class)){ req.not_found(); return false; } g_json_enabled.set(m_action.isannotationpresent(annotation.jsonoutputenabled.class)); if(m_action.isannotationpresent(annotation.userrolerequired.class)){ iuser loginuser = req.user(); if(loginuser == null){ string this_page = req.param(this_page, ""); throw req.error("user_not_login", this_page); } if(loginuser.isblocked()) throw req.error("user_blocked"); annotation.userrolerequired urr = (annotation.userrolerequired) m_action.getannotation(annotation.userrolerequired.class); if(loginuser.getrole() < urr.role()) throw req.error("user_role_deny"); } //调用action方法之准备参数 int arg_c = m_action.getparametertypes().length; switch(arg_c){ case 0: // login() m_action.invoke(action); break ; case 1: m_action.invoke(action, req); break; case 2: // login(httpservletrequest req, httpservletresponse res) m_action.invoke(action, req.request(), req.response()); break ; case 3: // login(httpservletrequest req, httpservletresponse res, string[] extparams) stringbuilder args = new stringbuilder(); for(int i=3;i 0) args.append('/'); args.append(parts[i]); } boolean islong = m_action.getparametertypes()[2].equals(long.class); m_action.invoke(action, req.request(), req.response(), islong ? numberutils.tolong( args.tostring(), -1l) : args.tostring()); break ; default: req.not_found(); return false; } return true; } /** * 加载action类 * @param act_name * @return * @throws instantiationexception * @throws illegalaccessexception * @throws classnotfoundexception */ protected object _loadaction(string act_name) throws instantiationexception,illegalaccessexception { object action = actions.get(act_name); if(action == null){ for(string pkg : action_packages){ string cls = pkg '.' stringutils.capitalize(act_name) "action"; action = _loadactionoffullname(act_name, cls); if(action != null) break; } } return action ; } private object _loadactionoffullname(string act_name, string cls) throws illegalaccessexception, instantiationexception { object action = null; try { action = class.forname(cls).newinstance(); try{ method action_init_method = action.getclass().getmethod("init", servletcontext.class); action_init_method.invoke(action, getservletcontext()); }catch(nosuchmethodexception e){ }catch(invocationtargetexception excp) { excp.printstacktrace(); } if(!actions.containskey(act_name)){ synchronized(actions){ actions.put(act_name, action); } } } catch (classnotfoundexception excp) {} return action; } /** * 获取名为{method}的方法 * @param action * @param method * @return */ private method _getactionmethod(object action, string method) { string key = action.getclass().getsimplename() '.' method; method m = methods.get(key); if(m != null) return m; for(method m1 : action.getclass().getmethods()){ if(m1.getmodifiers()==modifier.public && m1.getname().equals(method)){ synchronized(methods){ methods.put(key, m1); } return m1 ; } } return null; } private final static hashmap actions = new hashmap(); private final static hashmap methods = new hashmap(); }

礼物 2013-08-19 16:41
]]>
class卸载、热替换和tomcat的热部署的分析http://www.blogjava.net/libin2722/articles/396091.html礼物礼物tue, 05 mar 2013 09:16:00 gmthttp://www.blogjava.net/libin2722/articles/396091.htmlhttp://www.blogjava.net/libin2722/comments/396091.htmlhttp://www.blogjava.net/libin2722/articles/396091.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/396091.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/396091.html这篇文章主要是分析tomcat中关于热部署和jsp更新替换的原理,在此之前先介绍class的热替换和class的卸载的原理。

一 class的热替换
classloader中重要的方法
loadclass
      classloader.loadclass(...) 是classloader的入口点。当一个类没有指明用什么加载器加载的时候,jvm默认采用appclassloader加载器加载没有加载过的class,调用的方法的入口就是loadclass(...)。如果一个class被自定义的classloader加载,那么jvm也会调用这个自定义的classloader.loadclass(...)方法来加载class内部引用的一些别的class文件。重载这个方法,能实现自定义加载class的方式,抛弃双亲委托机制,但是即使不采用双亲委托机制,比如java.lang包中的相关类还是不能自定义一个同名的类来代替,主要因为jvm解析、验证class的时候,会进行相关判断。
 
defineclass
      系统自带的classloader,默认加载程序的是appclassloader,classloader加载一个class,最终调用的是defineclass(...)方法,这时候就在想是否可以重复调用defineclass(...)方法加载同一个类(或者修改过),最后发现调用多次的话会有相关错误:
...
java.lang.linkageerror
attempted duplicate class definition
...
所以一个class被一个classloader实例加载过的话,就不能再被这个classloader实例再次加载(这里的加载指的是,调用了defileclass(...)放方法,重新加载字节码、解析、验证。)。而系统默认的appclassloader加载器,他们内部会缓存加载过的class,重新加载的话,就直接取缓存。所与对于热加载的话,只能重新创建一个classloader,然后再去加载已经被加载过的class文件。www.2cto.com

下面看一个class热加载的例子:
代码:hotswapurlclassloader自定义classloader,实现热替换的关键
  1 package testjvm.testclassloader;
  2
  3 import java.io.file;
  4 import java.io.filenotfoundexception;
  5 import java.net.malformedurlexception;
  6 import java.net.url;
  7 import java.net.urlclassloader;
  8 import java.util.hashmap;
  9 import java.util.map;
 10
 11 /**
 12  * 只要功能是重新加载更改过的.class文件,达到热替换的作用
 13  * @author banana
 14  */
 15 public class hotswapurlclassloader extends urlclassloader {
 16     //缓存加载class文件的最后最新修改时间
 17     public static map cachelastmodifytimemap = new hashmap();
 18     //工程class类所在的路径
 19     public static string projectclasspath = "d:/ecpworkspace/zjob-note/bin/";
 20     //所有的测试的类都在同一个包下
 21     public static string packagepath = "testjvm/testclassloader/";
 22    
 23     private static hotswapurlclassloader hcl = new hotswapurlclassloader();
 24    
 25     public hotswapurlclassloader() {
 26         //设置classloader加载的路径
 27         super(getmyurls());
 28     }
 29    
 30     public static hotswapurlclassloader  getclassloader(){
 31         return hcl;
 32     }
 33
 34     private static  url[] getmyurls(){
 35         url url = null;
 36         try {
 37             url = new file(projectclasspath).touri().to;
 38         } catch (malformedurlexception e) {
 39             e.printstacktrace();
 40         }
 41         return new url[] { url };
 42     }
 43    
 44     /**
 45      * 重写loadclass,不采用双亲委托机制("java."开头的类还是会由系统默认classloader加载)
 46      */
 47     @override
 48     public class loadclass(string name,boolean resolve) throws classnotfoundexception {
 49         class clazz = null;
 50         //查看hotswapurlclassloader实例缓存下,是否已经加载过class
 51         //不同的hotswapurlclassloader实例是不共享缓存的
 52         clazz = findloadedclass(name);
 53         if (clazz != null ) {
 54             if (resolve){
 55                 resolveclass(clazz);
 56             }
 57             //如果class类被修改过,则重新加载
 58             if (ismodify(name)) {
 59                 hcl = new hotswapurlclassloader();
 60                 clazz = customload(name, hcl);
 61             }
 62             return (clazz);
 63         }
 64
 65         //如果类的包名为"java."开始,则有系统默认加载器appclassloader加载
 66         if(name.startswith("java.")){
 67             try {
 68                 //得到系统默认的加载cl,即appclassloader
 69                 classloader system = classloader.getsystemclassloader();
 70                 clazz = system.loadclass(name);
 71                 if (clazz != null) {
 72                     if (resolve)
 73                         resolveclass(clazz);
 74                     return (clazz);
 75                 }
 76             } catch (classnotfoundexception e) {
 77                 // ignore
 78             }
 79         }
 80        
 81         return customload(name,this);
 82     }
 83
 84     public class load(string name) throws exception{
 85         return loadclass(name);
 86     }
 87
 88     /**
 89      * 自定义加载
 90      * @param name
 91      * @param cl
 92      * @return
 93      * @throws classnotfoundexception
 94      */
 95     public class customload(string name,classloader cl) throws classnotfoundexception {
 96         return customload(name, false,cl);
 97     }
 98
 99     /**
100      * 自定义加载
101      * @param name
102      * @param resolve
103      * @return
104      * @throws classnotfoundexception
105      */
106     public class customload(string name, boolean resolve,classloader cl)
107             throws classnotfoundexception {
108         //findclass()调用的是urlclassloader里面重载了classloader的findclass()方法
109         class clazz = ((hotswapurlclassloader)cl).findclass(name);
110         if (resolve)
111             ((hotswapurlclassloader)cl).resolveclass(clazz);
112         //缓存加载class文件的最后修改时间
113         long lastmodifytime = getclasslastmodifytime(name);
114         cachelastmodifytimemap.put(name,lastmodifytime);
115         return clazz;
116     }
117    
118     public class loadclass(string name) throws classnotfoundexception {
119         return loadclass(name,false);
120     }
121    
122     @override
123     protected class findclass(string name) throws classnotfoundexception {
124         // todo auto-generated method stub
125         return super.findclass(name);
126     }
127    
128     /**
129      * @param name
130      * @return .class文件最新的修改时间
131      */
132     private long getclasslastmodifytime(string name){
133         string path = getclasscompletepath(name);
134         file file = new file(path);
135         if(!file.exists()){
136             throw new runtimeexception(new filenotfoundexception(name));
137         }
138         return file.lastmodified();
139     }
140    
141     /**
142      * 判断这个文件跟上次比是否修改过
143      * @param name
144      * @return
145      */
146     private boolean ismodify(string name){
147         long lastmodify = getclasslastmodifytime(name);
148         long previousmodifytime = cachelastmodifytimemap.get(name);
149         if(lastmodify>previousmodifytime){
150             return true;
151         }
152         return false;
153     }
154    
155     /**
156      * @param name
157      * @return .class文件的完整路径 (e.g. e:/a.class)
158      */
159     private string getclasscompletepath(string name){
160         string simplename = name.substring(name.lastindexof(".") 1);
161         return projectclasspath packagepath simplename ".class";
162     }
163    
164 }
165

代码:hot被用来修改的类
1 package testjvm.testclassloader;
2
3 public class hot {
4     public void hot(){
5         system.out.println(" version 1 : " this.getclass().getclassloader());
6     }
7 }
8

代码:testhotswap测试类
 1 package testjvm.testclassloader;
 2
 3 import java.lang.reflect.method;
 4
 5 public class testhotswap {
 6
 7     public static void main(string[] args) throws exception {
 8         //开启线程,如果class文件有修改,就热替换
 9         thread t = new thread(new monitorhotswap());
10         t.start();
11     }
12 }
13
14 class monitorhotswap implements runnable {
15     // hot就是用于修改,用来测试热加载
16     private string classname = "testjvm.testclassloader.hot";
17     private class hotclazz = null;
18     private hotswapurlclassloader hotswapcl = null;
19
20     @override
21     public void run() {
22         try {
23             while (true) {
24                 initload();
25                 object hot = hotclazz.newinstance();
26                 method m = hotclazz.getmethod("hot");
27                 m.invoke(hot, null); //打印出相关信息
28                 // 每隔10秒重新加载一次
29                 thread.sleep(10000);
30             }
31         } catch (exception e) {
32             e.printstacktrace();
33         }
34     }
35
36     /**
37      * 加载class
38      */
39     void initload() throws exception {
40         hotswapcl = hotswapurlclassloader.getclassloader();
41         // 如果hot类被修改了,那么会重新加载,hotclass也会返回新的
42         hotclazz = hotswapcl.loadclass(classname);
43     }
44 }

     在测试类运行的时候,修改hot.class文件
hot.class
原来第五行:system.out.println(" version 1 : " this.getclass().getclassloader());
改后第五行:system.out.println(" version 2 : " this.getclass().getclassloader());
  
输出
 version 1 : testjvm.testclassloader.hotswapurlclassloader@610f7612
 version 1 : testjvm.testclassloader.hotswapurlclassloader@610f7612
 version 2 : testjvm.testclassloader.hotswapurlclassloader@45e4d960
 version 2 : testjvm.testclassloader.hotswapurlclassloader@45e4d960
     所以hotswapurlclassloader是重加载了hot类 。注意上面,其实当加载修改后的hot时,hotswapurlclassloader实例跟加载没修改hot的hotswapurlclassloader不是同一个。
图:hotswapurlclassloader加载情况

     总结:上述类热加载,需要自定义classloader,并且只能重新实例化classloader实例,利用新的classloader实例才能重新加载之前被加载过的class。并且程序需要模块化,才能利用这种热加载方式。

二 class卸载
      在java中class也是可以unload。jvm中class和meta信息存放在permgen space区域。如果加载的class文件很多,那么可能导致permgen space区域空间溢出。引起:java.lang.outofmemoryerrorpermgen space.  对于有些class我们可能只需要使用一次,就不再需要了,也可能我们修改了class文件,我们需要重新加载 newclass,那么oldclass就不再需要了。那么jvm怎么样才能卸载class呢。

      jvm中的class只有满足以下三个条件,才能被gc回收,也就是该class被卸载(unload):
   - 该类所有的实例都已经被gc。
   - 加载该类的classloader实例已经被gc。
   - 该类的java.lang.class对象没有在任何地方被引用。

     gc的时机我们是不可控的,那么同样的我们对于class的卸载也是不可控的。

例子:
代码:simpleurlclassloader,一个简单的自定义classloader
  1 package testjvm.testclassloader;
  2
  3 import java.io.file;
  4 import java.net.malformedurlexception;
  5 import java.net.url;
  6 import java.net.urlclassloader;
  7
  8 public class simpleurlclassloader extends urlclassloader {
  9     //工程class类所在的路径
 10     public static string projectclasspath = "e:/ide/work_place/zjob-note/bin/";
 11     //所有的测试的类都在同一个包下
 12     public static string packagepath = "testjvm/testclassloader/";
 13    
 14     public simpleurlclassloader() {
 15         //设置classloader加载的路径
 16         super(getmyurls());
 17     }
 18    
 19     private static  url[] getmyurls(){
 20         url url = null;
 21         try {
 22             url = new file(projectclasspath).touri().to;
 23         } catch (malformedurlexception e) {
 24             e.printstacktrace();
 25         }
 26         return new url[] { url };
 27     }
 28    
 29     public class load(string name) throws exception{
 30         return loadclass(name);
 31     }
 32
 33     public class loadclass(string name) throws classnotfoundexception {
 34         return loadclass(name,false);
 35     }
 36    
 37     /**
 38      * 重写loadclass,不采用双亲委托机制("java."开头的类还是会由系统默认classloader加载)
 39      */
 40     @override
 41     public class loadclass(string name,boolean resolve) throws classnotfoundexception {
 42         class clazz = null;
 43         //查看hotswapurlclassloader实例缓存下,是否已经加载过class
 44         clazz = findloadedclass(name);
 45         if (clazz != null ) {
 46             if (resolve){
 47                 resolveclass(clazz);
 48             }
 49             return (clazz);
 50         }
 51
 52         //如果类的包名为"java."开始,则有系统默认加载器appclassloader加载
 53         if(name.startswith("java.")){
 54             try {
 55                 //得到系统默认的加载cl,即appclassloader
 56                 classloader system = classloader.getsystemclassloader();
 57                 clazz = system.loadclass(name);
 58                 if (clazz != null) {
 59                     if (resolve)
 60                         resolveclass(clazz);
 61                     return (clazz);
 62                 }
 63             } catch (classnotfoundexception e) {
 64                 // ignore
 65             }
 66         }
 67        
 68         return customload(name,this);
 69     }
 70
 71     /**
 72      * 自定义加载
 73      * @param name
 74      * @param cl
 75      * @return
 76      * @throws classnotfoundexception
 77      */
 78     public class customload(string name,classloader cl) throws classnotfoundexception {
 79         return customload(name, false,cl);
 80     }
 81
 82     /**
 83      * 自定义加载
 84      * @param name
 85      * @param resolve
 86      * @return
 87      * @throws classnotfoundexception
 88      */
 89     public class customload(string name, boolean resolve,classloader cl)
 90             throws classnotfoundexception {
 91         //findclass()调用的是urlclassloader里面重载了classloader的findclass()方法
 92         class clazz = ((simpleurlclassloader)cl).findclass(name);
 93         if (resolve)
 94             ((simpleurlclassloader)cl).resolveclass(clazz);
 95         return clazz;
 96     }
 97    
 98     @override
 99     protected class findclass(string name) throws classnotfoundexception {
100         return super.findclass(name);
101     }
102 }
103

代码:a
1 public class a { 
2 //  public static final level customlevel = new level("test", 550) {}; // 内部类
3 }
代码:testclassunload,测试类
 1 package testjvm.testclassloader;
 2
 3 public class testclassunload {
 4
 5     public static void main(string[] args) throws exception {
 6         simpleurlclassloader loader = new simpleurlclassloader();
 7         // 用自定义的加载器加载a
 8         class clazza = loader.load("testjvm.testclassloader.a");
 9         object a = clazza.newinstance();
10         // 清除相关引用
11         a = null;
12         clazza = null;
13         loader = null;
14         // 执行一次gc垃圾回收
15         system.gc();
16         system.out.println("gc over");
17     }
18 }
19

      运行的时候配置vm参数: -verbose:class;用于查看class的加载与卸载情况。如果用的是eclipse,在run configurations中配置此参数即可。
图:run configurations配置   

输出结果
.....
[loaded java.net.uri$parser from e:\java\jdk1.7.0_03\jre\lib\rt.jar]
[loaded testjvm.testclassloader.a from file:/e:/ide/work_place/zjob-note/bin/]
[unloading class testjvm.testclassloader.a]
gc over
[loaded sun.misc.cleaner from e:\java\jdk1.7.0_03\jre\lib\rt.jar]
[loaded java.lang.shutdown from e:\java\jdk1.7.0_03\jre\lib\rt.jar]
......



礼物 2013-03-05 17:16
]]>
个性化推荐技术漫谈http://www.blogjava.net/libin2722/articles/396041.html礼物礼物mon, 04 mar 2013 08:39:00 gmthttp://www.blogjava.net/libin2722/articles/396041.htmlhttp://www.blogjava.net/libin2722/comments/396041.htmlhttp://www.blogjava.net/libin2722/articles/396041.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/396041.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/396041.html如果说过去的十年是搜索技术大行其道的十年,那么个性化推荐技术将成为未来十年中最重要的革新之一。目前几乎所有大型的电子商务系统,如amazon、cdnow、netflix等,都不同程度地使用了各种形式的推荐系统。而近来以“发现”为核心的网站正开始在互联网上崭露头角,比如侧重于音乐推荐的八宝盒,侧重于图书推荐的豆瓣等等。
 
那么,一个好的推荐系统需要满足什么目标呢?
个性化推荐系统必须能够基于用户之前的口味和喜好提供相关的精确的推荐,而且这种口味和喜欢的收集必须尽量少的需要用户的劳动。推荐的结果必须能够实时计算,这样才能够在用户离开网站前之前获得推荐的内容,并且及时的对推荐结果作出反馈。实时性也是推荐系统与通常的数据挖掘技术显著不同的一个特点。
 
一个完整的推荐系统由三部分构成:行为记录模块、模型分析模块和推荐模块。行为记录模块负责记录能够体现用户喜好的行为,比如购买、下载、评分等。这部分看起来简单,其实需要非常仔细的设计。比如说购买和评分这两种行为表达潜在的喜好程度就不尽相同完善的行为记录需要能够综合多种不同的用户行为,处理不同行为的累加。模型分析模块的功能则实现了对用户行为记录的分析,采用不同算法建立起模型描述用户的喜好信息。最后,通过推荐模块,实时的从内容集筛选出目标用户可能会感兴趣的内容推荐给用户。因此,除了推荐系统本身,为了实现推荐,还需要一个可供推荐的内容集。比如,对于音乐推荐系统来说,一个音乐库就是这样的内容集。我们对内容集本身需要提供的信息要求非常低,在经典的协同过滤算法下,内容集甚至只需要提供id就足够。而对于基于内容的推荐系统来说,由于往往需要对内容进行特征抽取和索引,我们就会需要提供更多的领域知识和内容属性。这种情况下,还是拿音乐举例,歌手、流派之类的属性和音频信息就成为必需的内容集信息。

迄今为止在个性化推荐系统中,协同过滤(collaborative filtering)技术是应用最成功的技术。目前国内外互联网上有许多大型网站已经应用这项技术为用户更加智能的推荐内容。如果你想要研究协同过滤,一定不能错过movielens()。它是协同过滤最著名的研究项目之一。
 
第一代的协同过滤技术,又被称为基于用户(user-based)的协同过滤。基于用户的协同过滤,基本原理是基于用户行为选择的相关性。用户的行为选择这里指的是下载、购买、评价等等能够显式或者隐式体现出用户喜好的行为。在一个典型的基于协同过滤技术的推荐系统中,输入数据通常可以表述为一个m×n 的用户内容矩阵r,m是用户数,n是内容数。矩阵的值与内容的类型有关,通常由行为记录模块决定。如果内容是网上书店中的书,则矩阵的值可以表示用户购买与否,例如1表示购买,0表示没有购买;或者表示用户对它的评价有多高,这样的评价值就可以有几个等级,比如常见的1~5级评价制。
 
基于用户的协同过滤,通过比较目标用户的一系列行为选择和其他用户之间的相似性,来识别出一组相互具有类似喜好的用户,又可以称为“同好”。一旦系统能够识别一个用户的同好用户,就能够将他们最感兴趣的内容作为当前用户的推荐结果推荐给这个用户。也就是说,以前的行为选择与你相似的用户,在以后的行为中很可能也会和你相似。因此将这些用户做为基准来向你推荐内容。
 
协同过滤的核心问题是寻找与目标用户兴趣相近的一组用户。这种相似用户通常被称为最近邻居(nearest neighbor)。用户之间的相似度是通过比较两个用户的行为选择矢量得到的。目前,比较行为选择矢量的相似度计算方法有许多种,比较经典的算法包括泊松相关系数(person correlation coefficient)和余弦相似性(cosine-based similarity)。
 
“最近邻居”产生后,我们就能够计算得到用户最可能感兴趣的内容集(也叫做topn推荐集)。为了得到推荐集,分别统计“最近邻居”中的用户对不同内容的兴趣度,取其中排在最前面的内容作为推荐集。下面是一个简化的示例:假如用户张三有两个同好:李四和王五。
 
张三喜欢看电影a;
李四喜欢看电影a,b,c和d;
王五喜欢看电影a,b,d,e和f;
 
这样,推荐系统就能够过滤出相似用户都喜欢的电影b和d作为张三最可能也会喜欢的电影推荐给张三。
 
基于用户的协同过滤技术在个性化推荐系统中获得了极大的成功,但它有自身的局限性。推荐集的产生方式意味着一个内容只有已经被用户选择(购买)后才有机会被推荐给其他用户。对于一个网上书店来说,新上架的书因为还没有被相当数量的用户购买或者评价的记录,便很少有机会被用户的“最近邻居”筛选进入推荐集。这个问题,也被称之为协同过滤的“冷启动”问题。
 
此外,因为计算用户的相似度时,是通过将目标用户的历史行为记录与其他每一个用户的记录相比较得出的,所以对于一个现实的推荐系统来说,扩展性将成为非常严重的问题。设想一下,对于一个拥有上百万用户的网站来说,每计算一个用户都将涉及到上百万次的比较,更不要说其中会带来的大量数据库io操作的开销。
 
于是第二代基于内容项(item-based)的协同过滤技术就产生了。与基于用户的技术不同的是,这种方法比较的是内容项与内容项之间的相似度。item-based 方法同样需要进行三个步骤获得推荐:1)得到内容项(item)的历史评分数据;2)针对内容项进行内容项之间的相似度计算,找到目标内容项的“最近邻居”;3)产生推荐。这里内容项之间的相似度是通过比较两个内容项上的用户行为选择矢量得到的。举个例子,假设用户和内容项如下:
 
 
电影a
电影b
电影c
电影d
张三
喜欢
 
 
 
李四
喜欢
喜欢
喜欢
喜欢
王五
不喜欢
 
不喜欢
不喜欢
赵六
喜欢
喜欢
 
喜欢
 
可以看出,电影a与d是最相似的。因为张三喜欢a,所以电影d就可以推荐给张三。
 
和基于用户的推荐系统相比,基于内容项的推荐系统最大的改进是更具有扩展性。基于内容项的方法通过计算内容项之间的相似性来代替用户之间的相似性。对于通常的互联网应用来说,提供的内容项数量相对较为稳定。比如一个大型网上书店,可能出售的书籍数量也就在几十万上下,而用户数量就可能达到几百万。所以,比起用户,内容项之间的相似性计算需要的计算量要少很多,从而大大降低了在线计算量,提高系统性能。基于内容项的推荐系统应用最为成功的是amazon。amazon为此还申请了一项专利叫做”collaborative recommendations using item-to-item similarity mappings”
 
不论是第一代的基于用户方法,还是第二代的基于内容项方法,都不可避免的遇到数据稀疏的问题。在任何一个网站中,用户的评分记录或者购买记录,相对整个可供选择的内容集来说,都是很小的一部分。所以在许多推荐系统中,每个用户涉及的数据量相当有限,在一些大的系统如amazon中,用户最多不过就评价过上百万本书的1%,造成评估数据相当稀疏。当用户评价过的内容之间找不到交集时,就难以判断用户的口味是否相似,难以找到相似用户集,导致推荐效果大大降低。为了解决用户数据的稀疏问题,最方便的办法就是将用户对没有选择过的内容项的评分设为一个固定的缺省值,例如用户的平均评分。针对如何预测遗漏的评分业内又提出了很多种方法,不过一般来说采用最简单的改进方法就可以有效地提高协同过滤推荐系统的准确度。
 
另外一方面,即便采用了基于内容项的方法,在数据量巨大的时候,计算复杂度仍然成为性能瓶颈。为了进一步解决协同过滤技术的扩展性能问题,目前比较有效的办法是在用户评分数据上做一次聚类分析(clustering)。聚类技术首先将具有相似兴趣爱好的用户分配到相同的分类中。聚类产生之后,它或者将“最近邻居”搜索对象限制在最相近的聚类中,根据类中其他用户的评价预测目标用户的评价,或者用聚类的中心作为近似提取推荐结果。由于用户之间的分类相对变化比较小,因此聚类过程往往可以离线进行,而无需实时计算,这样就大大降低了实时推荐的计算压力,提高推荐系统的速度。一般来说,聚类将用户分为多少个类,推荐系统的整体速度就能够提高多少倍。具体选择什么样的聚类算法,又会因应用领域和数据的分布特性而不同。如果聚类算法选择不当,反而会降低推荐的准确性。近年来,推荐系统的算法技术的发展也有了一些新的方向,比如slopeone,svd等方法,就不一一列举了。
 
在我看来,一个商用推荐系统的尤其关键之处在于对海量用户数据的处理。因为推荐系统是数据优先,数据的积累越多对推荐的精度就越有好处。而当用户的行为数据真正积累到上百万甚至上亿时,如何在合理时间内得出有效的推荐,就是对推荐技术最大的考验。除此之外,一个优秀的推荐系统需要能够结合内容相似与用户行为相。传统的协同过滤方法是忽略内容本身的属性的,这一方面固然是对数据要求少的优点,但另一方面也带来了难以避免的“冷启动”问题。其实,随着标签系统在互联网上的广泛应用,标签本身就不失为是一种很好的内容属性。如何利用也是值得大家探讨的。充分利用到内容本身的属性,将不同的相似性结合起来,这会给基于协同过滤的推荐技术带来新的动力。最后一点,设计良好的推荐技术要能够从用户对推荐内容的反馈中自行调整和学习。因为实际上每个用户对于推荐的内容都有不同的要求,比如有的用户可能偏好比较热门的内容,有的用户更愿意发现冷门的内容。针对不同用户的反馈来不断学习每个用户的特征,才能够避免所采用算法本身先天的偏差,获得较为理想的效果。


礼物 2013-03-04 16:39
]]>
探索推荐引擎内部的秘密,第 1 部分: 推荐引擎初探http://www.blogjava.net/libin2722/articles/396035.html礼物礼物mon, 04 mar 2013 06:30:00 gmthttp://www.blogjava.net/libin2722/articles/396035.htmlhttp://www.blogjava.net/libin2722/comments/396035.htmlhttp://www.blogjava.net/libin2722/articles/396035.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/396035.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/396035.html

简介: 随着 web 技术的发展,使得内容的创建和分享变得越来越容易。每天都有大量的图片、博客、视频发布到网上。信息的极度爆炸使得人们找到他们需要的信息将变得越来越难。传统的搜索技术是一个相对简单的帮助人们找到信息的工具,也广泛的被人们所使用,但搜索引擎并不能完全满足用户对信息发现的需求,原因一是用户很难用恰当的关键词描述自己的需求,二是基于关键词的信息检索在很多情况下是不够的。而推荐引擎的出现,使用户获取信息的方式从简单的目标明确的数据的搜索转换到更高级更符合人们使用习惯的上下文信息更丰富的信息发现。

发布日期: 2011 年 3 月 16 日 
级别: 高级 
访问情况 : 65031 次浏览 
评论: 11 ( |  - 登录)

 平均分 (236个评分)

“探索推荐引擎内部的秘密”系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用。同时在理论讲解的基础上,还会结合 apache mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法。本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎。

如今已经进入了一个数据爆炸的时代,随着 web 2.0 的发展, web 已经变成数据分享的平台,那么,如何让人们在海量的数据中想要找到他们需要的信息将变得越来越难。

在这样的情形下,搜索引擎(google,bing,百度等等)成为大家快速找到目标信息的最好途径。在用户对自己需求相对明确的时候,用搜索引擎很方便的通过关键字搜索很快的找到自己需要的信息。但搜索引擎并不能完全满足用户对信息发现的需求,那是因为在很多情况下,用户其实并不明确自己的需要,或者他们的需求很难用简单的关键字来表述。又或者他们需要更加符合他们个人口味和喜好的结果,因此出现了推荐系统,与搜索引擎对应,大家也习惯称它为推荐引擎。

随着推荐引擎的出现,用户获取信息的方式从简单的目标明确的数据的搜索转换到更高级更符合人们使用习惯的信息发现。

如今,随着推荐技术的不断发展,推荐引擎已经在电子商务 (e-commerce,例如 amazon,当当网 ) 和一些基于 social 的社会化站点 ( 包括音乐,电影和图书分享,例如豆瓣,mtime 等 ) 都取得很大的成功。这也进一步的说明了,web2.0 环境下,在面对海量的数据,用户需要这种更加智能的,更加了解他们需求,口味和喜好的信息发现机制。

前面介绍了推荐引擎对于现在的 web2.0 站点的重要意义,这一章我们将讲讲推荐引擎到底是怎么工作的。推荐引擎利用特殊的信息过滤技术,将不同的物品或内容推荐给可能对它们感兴趣的用户。



 

图 1 给出了推荐引擎的工作原理图,这里先将推荐引擎看作黑盒,它接受的输入是推荐的数据源,一般情况下,推荐引擎所需要的数据源包括:

  • 要推荐物品或内容的元数据,例如关键字,基因描述等;
  • 系统用户的基本信息,例如性别,年龄等
  • 用户对物品或者信息的偏好,根据应用本身的不同,可能包括用户对物品的评分,用户查看物品的记录,用户的购买记录等。其实这些用户的偏好信息可以分为两类:
  • 显式的用户反馈:这类是用户在网站上自然浏览或者使用网站以外,显式的提供反馈信息,例如用户对物品的评分,或者对物品的评论。
  • 隐式的用户反馈:这类是用户在使用网站是产生的数据,隐式的反应了用户对物品的喜好,例如用户购买了某物品,用户查看了某物品的信息等等。

显式的用户反馈能准确的反应用户对物品的真实喜好,但需要用户付出额外的代价,而隐式的用户行为,通过一些分析和处理,也能反映用户的喜好,只是数据不是很精确,有些行为的分析存在较大的噪音。但只要选择正确的行为特征,隐式的用户反馈也能得到很好的效果,只是行为特征的选择可能在不同的应用中有很大的不同,例如在电子商务的网站上,购买行为其实就是一个能很好表现用户喜好的隐式反馈。

推荐引擎根据不同的推荐机制可能用到数据源中的一部分,然后根据这些数据,分析出一定的规则或者直接对用户对其他物品的喜好进行预测计算。这样推荐引擎可以在用户进入的时候给他推荐他可能感兴趣的物品。

推荐引擎的分类可以根据很多指标,下面我们一一介绍一下:

  1. 推荐引擎是不是为不同的用户推荐不同的数据

    根据这个指标,推荐引擎可以分为基于大众行为的推荐引擎和个性化推荐引擎

    • 根据大众行为的推荐引擎,对每个用户都给出同样的推荐,这些推荐可以是静态的由系统管理员人工设定的,或者基于系统所有用户的反馈统计计算出的当下比较流行的物品。
    • 个性化推荐引擎,对不同的用户,根据他们的口味和喜好给出更加精确的推荐,这时,系统需要了解需推荐内容和用户的特质,或者基于社会化网络,通过找到与当前用户相同喜好的用户,实现推荐。

    这是一个最基本的推荐引擎分类,其实大部分人们讨论的推荐引擎都是将个性化的推荐引擎,因为从根本上说,只有个性化的推荐引擎才是更加智能的信息发现过程。

  2. 根据推荐引擎的数据源

    其实这里讲的是如何发现数据的相关性,因为大部分推荐引擎的工作原理还是基于物品或者用户的相似集进行推荐。那么参考图 1 给出的推荐系统原理图,根据不同的数据源发现数据相关性的方法可以分为以下几种:

    • 根据系统用户的基本信息发现用户的相关程度,这种被称为基于人口统计学的推荐(demographic-based recommendation)
    • 根据推荐物品或内容的元数据,发现物品或者内容的相关性,这种被称为基于内容的推荐(content-based recommendation)
    • 根据用户对物品或者信息的偏好,发现物品或者内容本身的相关性,或者是发现用户的相关性,这种被称为基于协同过滤的推荐(collaborative filtering-based recommendation)。
  3. 根据推荐模型的建立方式

    可以想象在海量物品和用户的系统中,推荐引擎的计算量是相当大的,要实现实时的推荐务必需要建立一个推荐模型,关于推荐模型的建立方式可以分为以下几种:

    • 基于物品和用户本身的,这种推荐引擎将每个用户和每个物品都当作独立的实体,预测每个用户对于每个物品的喜好程度,这些信息往往是用一个二维矩阵描述的。由于用户感兴趣的物品远远小于总物品的数目,这样的模型导致大量的数据空置,即我们得到的二维矩阵往往是一个很大的稀疏矩阵。同时为了减小计算量,我们可以对物品和用户进行聚类, 然后记录和计算一类用户对一类物品的喜好程度,但这样的模型又会在推荐的准确性上有损失。
    • 基于关联规则的推荐(rule-based recommendation):关联规则的挖掘已经是数据挖掘中的一个经典的问题,主要是挖掘一些数据的依赖关系,典型的场景就是“购物篮问题”,通过关联规则的挖掘,我们可以找到哪些物品经常被同时购买,或者用户购买了一些物品后通常会购买哪些其他的物品,当我们挖掘出这些关联规则之后,我们可以基于这些规则给用户进行推荐。
    • 基于模型的推荐(model-based recommendation):这是一个典型的机器学习的问题,可以将已有的用户喜好信息作为训练样本,训练出一个预测用户喜好的模型,这样以后用户在进入系统,可以基于此模型计算推荐。这种方法的问题在于如何将用户实时或者近期的喜好信息反馈给训练好的模型,从而提高推荐的准确度。

其实在现在的推荐系统中,很少有只使用了一个推荐策略的推荐引擎,一般都是在不同的场景下使用不同的推荐策略从而达到最好的推荐效果,例如 amazon 的推荐,它将基于用户本身历史购买数据的推荐,和基于用户当前浏览的物品的推荐,以及基于大众喜好的当下比较流行的物品都在不同的区域推荐给用户,让用户可以从全方位的推荐中找到自己真正感兴趣的物品。

这一章的篇幅,将详细介绍各个推荐机制的工作原理,它们的优缺点以及应用场景。

基于人口统计学的推荐机制(demographic-based recommendation)是一种最易于实现的推荐方法,它只是简单的根据系统用户的基本信息发现用户的相关程度,然后将相似用户喜爱的其他物品推荐给当前用户,图 2 给出了这种推荐的工作原理。



 

从图中可以很清楚的看到,首先,系统对每个用户都有一个用户 profile 的建模,其中包括用户的基本信息,例如用户的年龄,性别等等;然后,系统会根据用户的 profile 计算用户的相似度,可以看到用户 a 的 profile 和用户 c 一样,那么系统会认为用户 a 和 c 是相似用户,在推荐引擎中,可以称他们是“邻居”;最后,基于“邻居”用户群的喜好推荐给当前用户一些物品,图中将用户 a 喜欢的物品 a 推荐给用户 c。

这种基于人口统计学的推荐机制的好处在于:

  1. 因为不使用当前用户对物品的喜好历史数据,所以对于新用户来讲没有“冷启动(cold start)”的问题。
  2. 这个方法不依赖于物品本身的数据,所以这个方法在不同物品的领域都可以使用,它是领域独立的(domain-independent)。

那么这个方法的缺点和问题是什么呢?这种基于用户的基本信息对用户进行分类的方法过于粗糙,尤其是对品味要求较高的领域,比如图书,电影和音乐等领域,无法得到很好的推荐效果。可能在一些电子商务的网站中,这个方法可以给出一些简单的推荐。另外一个局限是,这个方法可能涉及到一些与信息发现问题本身无关却比较敏感的信息,比如用户的年龄等,这些用户信息不是很好获取。

基于内容的推荐是在推荐引擎出现之初应用最为广泛的推荐机制,它的核心思想是根据推荐物品或内容的元数据,发现物品或者内容的相关性,然后基于用户以往的喜好记录,推荐给用户相似的物品。图 3 给出了基于内容推荐的基本原理。



 

图 3 中给出了基于内容推荐的一个典型的例子,电影推荐系统,首先我们需要对电影的元数据有一个建模,这里只简单的描述了一下电影的类型;然后通过电影的元数据发现电影间的相似度,因为类型都是“爱情,浪漫”电影 a 和 c 被认为是相似的电影(当然,只根据类型是不够的,要得到更好的推荐,我们还可以考虑电影的导演,演员等等);最后实现推荐,对于用户 a,他喜欢看电影 a,那么系统就可以给他推荐类似的电影 c。

这种基于内容的推荐机制的好处在于它能很好的建模用户的口味,能提供更加精确的推荐。但它也存在以下几个问题:

  1. 需要对物品进行分析和建模,推荐的质量依赖于对物品模型的完整和全面程度。在现在的应用中我们可以观察到关键词和标签(tag)被认为是描述物品元数据的一种简单有效的方法。
  2. 物品相似度的分析仅仅依赖于物品本身的特征,这里没有考虑人对物品的态度。
  3. 因为需要基于用户以往的喜好历史做出推荐,所以对于新用户有“冷启动”的问题。

虽然这个方法有很多不足和问题,但他还是成功的应用在一些电影,音乐,图书的社交站点,有些站点还请专业的人员对物品进行基因编码,比如潘多拉,在一份报告中说道,在潘多拉的推荐引擎中,每首歌有超过 100 个元数据特征,包括歌曲的风格,年份,演唱者等等。

随着 web2.0 的发展,web 站点更加提倡用户参与和用户贡献,因此基于协同过滤的推荐机制因运而生。它的原理很简单,就是根据用户对物品或者信息的偏好,发现物品或者内容本身的相关性,或者是发现用户的相关性,然后再基于这些关联性进行推荐。基于协同过滤的推荐可以分为三个子类:基于用户的推荐(user-based recommendation),基于项目的推荐(item-based recommendation)和基于模型的推荐(model-based recommendation)。下面我们一个一个详细的介绍着三种协同过滤的推荐机制。

基于用户的协同过滤推荐

基于用户的协同过滤推荐的基本原理是,根据所有用户对物品或者信息的偏好,发现与当前用户口味和偏好相似的“邻居”用户群,在一般的应用中是采用计算“k- 邻居”的算法;然后,基于这 k 个邻居的历史偏好信息,为当前用户进行推荐。下图 4 给出了原理图。



 

上图示意出基于用户的协同过滤推荐机制的基本原理,假设用户 a 喜欢物品 a,物品 c,用户 b 喜欢物品 b,用户 c 喜欢物品 a ,物品 c 和物品 d;从这些用户的历史喜好信息中,我们可以发现用户 a 和用户 c 的口味和偏好是比较类似的,同时用户 c 还喜欢物品 d,那么我们可以推断用户 a 可能也喜欢物品 d,因此可以将物品 d 推荐给用户 a。

基于用户的协同过滤推荐机制和基于人口统计学的推荐机制都是计算用户的相似度,并基于“邻居”用户群计算推荐,但它们所不同的是如何计算用户的相似度,基于人口统计学的机制只考虑用户本身的特征,而基于用户的协同过滤机制可是在用户的历史偏好的数据上计算用户的相似度,它的基本假设是,喜欢类似物品的用户可能有相同或者相似的口味和偏好。

基于项目的协同过滤推荐

基于项目的协同过滤推荐的基本原理也是类似的,只是说它使用所有用户对物品或者信息的偏好,发现物品和物品之间的相似度,然后根据用户的历史偏好信息,将类似的物品推荐给用户,图 5 很好的诠释了它的基本原理。

假设用户 a 喜欢物品 a 和物品 c,用户 b 喜欢物品 a,物品 b 和物品 c,用户 c 喜欢物品 a,从这些用户的历史喜好可以分析出物品 a 和物品 c 时比较类似的,喜欢物品 a 的人都喜欢物品 c,基于这个数据可以推断用户 c 很有可能也喜欢物品 c,所以系统会将物品 c 推荐给用户 c。

与上面讲的类似,基于项目的协同过滤推荐和基于内容的推荐其实都是基于物品相似度预测推荐,只是相似度计算的方法不一样,前者是从用户历史的偏好推断,而后者是基于物品本身的属性特征信息。



 

同时协同过滤,在基于用户和基于项目两个策略中应该如何选择呢?其实基于项目的协同过滤推荐机制是 amazon 在基于用户的机制上改良的一种策略,因为在大部分的 web 站点中,物品的个数是远远小于用户的数量的,而且物品的个数和相似度相对比较稳定,同时基于项目的机制比基于用户的实时性更好一些。但也不是所有的场景都是这样的情况,可以设想一下在一些新闻推荐系统中,也许物品,也就是新闻的个数可能大于用户的个数,而且新闻的更新程度也有很快,所以它的形似度依然不稳定。所以,其实可以看出,推荐策略的选择其实和具体的应用场景有很大的关系。

基于模型的协同过滤推荐

基于模型的协同过滤推荐就是基于样本的用户喜好信息,训练一个推荐模型,然后根据实时的用户喜好的信息进行预测,计算推荐。

基于协同过滤的推荐机制是现今应用最为广泛的推荐机制,它有以下几个显著的优点:

  1. 它不需要对物品或者用户进行严格的建模,而且不要求物品的描述是机器可理解的,所以这种方法也是领域无关的。
  2. 这种方法计算出来的推荐是开放的,可以共用他人的经验,很好的支持用户发现潜在的兴趣偏好

而它也存在以下几个问题:

  1. 方法的核心是基于历史数据,所以对新物品和新用户都有“冷启动”的问题。
  2. 推荐的效果依赖于用户历史偏好数据的多少和准确性。
  3. 在大部分的实现中,用户历史偏好是用稀疏矩阵进行存储的,而稀疏矩阵上的计算有些明显的问题,包括可能少部分人的错误偏好会对推荐的准确度有很大的影响等等。
  4. 对于一些特殊品味的用户不能给予很好的推荐。
  5. 由于以历史数据为基础,抓取和建模用户的偏好后,很难修改或者根据用户的使用演变,从而导致这个方法不够灵活。

在现行的 web 站点上的推荐往往都不是单纯只采用了某一种推荐的机制和策略,他们往往是将多个方法混合在一起,从而达到更好的推荐效果。关于如何组合各个推荐机制,这里讲几种比较流行的组合方法。

  1. 加权的混合(weighted hybridization): 用线性公式(linear formula)将几种不同的推荐按照一定权重组合起来,具体权重的值需要在测试数据集上反复实验,从而达到最好的推荐效果。
  2. 切换的混合(switching hybridization):前面也讲到,其实对于不同的情况(数据量,系统运行状况,用户和物品的数目等),推荐策略可能有很大的不同,那么切换的混合方式,就是允许在不同的情况下,选择最为合适的推荐机制计算推荐。
  3. 分区的混合(mixed hybridization):采用多种推荐机制,并将不同的推荐结果分不同的区显示给用户。其实,amazon,当当网等很多电子商务网站都是采用这样的方式,用户可以得到很全面的推荐,也更容易找到他们想要的东西。
  4. 分层的混合(meta-level hybridization): 采用多种推荐机制,并将一个推荐机制的结果作为另一个的输入,从而综合各个推荐机制的优缺点,得到更加准确的推荐。

介绍完推荐引擎的基本原理,基本推荐机制,下面简要分析几个有代表性的推荐引擎的应用,这里选择两个领域:amazon 作为电子商务的代表,豆瓣作为社交网络的代表。

推荐在电子商务中的应用 – amazon

amazon 作为推荐引擎的鼻祖,它已经将推荐的思想渗透在应用的各个角落。amazon 推荐的核心是通过数据挖掘算法和比较用户的消费偏好于其他用户进行对比,借以预测用户可能感兴趣的商品。对应于上面介绍的各种推荐机制,amazon 采用的是分区的混合的机制,并将不同的推荐结果分不同的区显示给用户,图 6 和图 7 展示了用户在 amazon 上能得到的推荐。



 


 

amazon 利用可以记录的所有用户在站点上的行为,根据不同数据的特点对它们进行处理,并分成不同区为用户推送推荐:

  • 今日推荐 (today's recommendation for you): 通常是根据用户的近期的历史购买或者查看记录,并结合时下流行的物品给出一个折中的推荐。
  • 新产品的推荐 (new for you): 采用了基于内容的推荐机制 (content-based recommendation),将一些新到物品推荐给用户。在方法选择上由于新物品没有大量的用户喜好信息,所以基于内容的推荐能很好的解决这个“冷启动”的问题。
  • 捆绑销售 (frequently bought together): 采用数据挖掘技术对用户的购买行为进行分析,找到经常被一起或同一个人购买的物品集,进行捆绑销售,这是一种典型的基于项目的协同过滤推荐机制。
  • 别人购买 / 浏览的商品 (customers who bought/see this item also bought/see): 这也是一个典型的基于项目的协同过滤推荐的应用,通过社会化机制用户能更快更方便的找到自己感兴趣的物品。

值得一提的是,amazon 在做推荐时,设计和用户体验也做得特别独到:

amazon 利用有它大量历史数据的优势,量化推荐原因。

  • 基于社会化的推荐,amazon 会给你事实的数据,让用户信服,例如:购买此物品的用户百分之多少也购买了那个物品;
  • 基于物品本身的推荐,amazon 也会列出推荐的理由,例如:因为你的购物框中有 ***,或者因为你购买过 ***,所以给你推荐类似的 ***。

另外,amazon 很多推荐是基于用户的 profile 计算出来的,用户的 profile 中记录了用户在 amazon 上的行为,包括看了那些物品,买了那些物品,收藏夹和 wish list 里的物品等等,当然 amazon 里还集成了评分等其他的用户反馈的方式,它们都是 profile 的一部分,同时,amazon 提供了让用户自主管理自己 profile 的功能,通过这种方式用户可以更明确的告诉推荐引擎他的品味和意图是什么。

推荐在社交网站中的应用 – 豆瓣

豆瓣是国内做的比较成功的社交网站,它以图书,电影,音乐和同城活动为中心,形成一个多元化的社交网络平台,自然推荐的功能是必不可少的,下面我们看看豆瓣是如何推荐的。



 

当你在豆瓣电影中将一些你看过的或是感兴趣的电影加入你看过和想看的列表里,并为它们做相应的评分,这时豆瓣的推荐引擎已经拿到你的一些偏好信息,那么它将给你展示如图 8 的电影推荐。



 

豆瓣的推荐是通过“豆瓣猜”,为了让用户清楚这些推荐是如何来的,豆瓣还给出了“豆瓣猜”的一个简要的介绍。

你的个人推荐是根据你的收藏和评价自动得出的,每个人的推荐清单都不同。你的收藏和评价越多,豆瓣给你的推荐会越准确和丰富。
每天推荐的内容可能会有变化。随着豆瓣的长大,给你推荐的内容也会越来越准。

这一点让我们可以清晰明了的知道,豆瓣必然是基于社会化的协同过滤的推荐,这样用户越多,用户的反馈越多,那么推荐的效果会越来越准确。

相对于 amazon 的用户行为模型,豆瓣电影的模型更加简单,就是“看过”和“想看”,这也让他们的推荐更加专注于用户的品味,毕竟买东西和看电影的动机还是有很大不同的。

另外,豆瓣也有基于物品本身的推荐,当你查看一些电影的详细信息的时候,他会给你推荐出“喜欢这个电影的人也喜欢的电影”, 如图 10,这是一个基于协同过滤的应用。



 

在网络数据爆炸的年代,如何让用户更快的找到想要的数据,如何让用户发现自己潜在的兴趣和需求,无论是对于电子商务还是社会网络的应用都是至关重要的。推荐引擎的出现,使得这个问题越来越被大家关注。但对大多数人来讲,也许还在惊叹它为什么总是能猜到你到底想要些什么。推荐引擎的魔力在于你不清楚在这个推荐背后,引擎到底记录和推理了些什么。

通过这篇综述性的文章,你可以了解,其实推荐引擎只是默默的记录和观察你的一举一动,然后再借由所有用户产生的海量数据分析和发现其中的规律,进而慢慢的了解你,你的需求,你的习惯,并默默的无声息的帮助你快速的解决你的问题,找到你想要的东西。

其实,回头想想,很多时候,推荐引擎比你更了解你自己。

通过第一篇文章,相信大家对推荐引擎有一个清晰的第一印象,本系列的下一篇文章将深入介绍基于协同过滤的推荐策略。在现今的推荐技术和算法中,最被大家广泛认可和采用的就是基于协同过滤的推荐方法。它以其方法模型简单,数据依赖性低,数据方便采集,推荐效果较优等多个优点成为大众眼里的推荐算法“no.1”。本文将带你深入了解协同过滤的秘密,并给出基于 apache mahout 的协同过滤算法的高效实现。apache mahout 是 asf 的一个较新的开源项目,它源于 lucene,构建在 hadoop 之上,关注海量数据上的机器学习经典算法的高效实现。

感谢大家对本系列的关注和支持。

本人所发表的内容仅为个人观点,不代表 ibm 公司立场、战略和观点。


学习

  • , thomas hess, 2009: 推荐引擎的总结性文章,thomas 给出推荐引擎的模型,各种推荐机制的工作原理,并分析了推荐引擎面临的众多问题。

  • , adomavicius, g.; tuzhilin, a., 2005:2005 年的论文,对现今流行的推荐技术进行总结,深入具体的实现技术方法,同时也提出了对下一代推荐引擎的展望。

  • , montaner, m.; lopez, b.; de la rosa, j. l., 2003, 对互联网上推荐引擎进行总结,给出的不同推荐方法的分类和特点,帮助读者对推荐引擎有全面的认识。

  • amazon: :推荐技术的先驱,amazon 在 b2c 领域的推荐技术值得大家参考。

  • 豆瓣::作为国内社交网络的先驱,豆瓣在推荐技术上也处于领先的位置,同时对于不同内容的推荐策略有深入的研究。

  • :对个性化推荐技术的基本原理进行简要介绍,提出了作者对优秀的个性化推荐的多角度认识

  • :推荐系统的 google 讨论组,有很多关于推荐引擎的有趣讨论

  • :关于推荐引擎算法的资源

  • :关于推荐引擎的设计方法的介绍

  • :这个演示给出了如何构建一个推荐引擎,并结合例子详细介绍了基于协同过滤的推荐策略。

  • :数百篇关于 web 编程各个方面的文章。 


  • :这是有关 ajax 编程模型信息的一站式中心,包括很多文档、教程、论坛、blog、wiki 和新闻。任何 ajax 的新信息都能在这里找到。

  • ,这是有关 web 2.0 相关信息的一站式中心,包括大量 web 2.0 技术文章、教程、下载和相关技术资源。您还可以通过 栏目,迅速了解 web 2.0 的相关概念。

  • 查看 ,了解更多和 html5 相关的知识和动向。

讨论

  • 加入 


礼物 2013-03-04 14:30
]]>
一个类引发的回忆http://www.blogjava.net/libin2722/archive/2013/03/01/395890.html礼物礼物fri, 01 mar 2013 01:52:00 gmthttp://www.blogjava.net/libin2722/archive/2013/03/01/395890.htmlhttp://www.blogjava.net/libin2722/comments/395890.htmlhttp://www.blogjava.net/libin2722/archive/2013/03/01/395890.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/395890.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/395890.html

package com.itgenius.netoa.admin;

import java.sql.*;
import javax.sql.*;
import javax.naming.context;
import javax.naming.initialcontext;
import javax.naming.*;

import java.util.list;

public class ejbdao implements applicationutil {
  
private  connection conn=null;
  
private statement st=null;
  
private preparedstatement pst=null;
  
private callablestatement cs=null;
  
private resultset rs=null;
  
private datasource ds=null;
  
private boolean iscorrect=false;

  
public ejbdao() {
  }
  
public void getconnection(){
    
try{
      context ctx 
= new initialcontext();
      ds
=(datasource)ctx.lookup(dsjndi);
      conn
=ds.getconnection();
    }
catch (namingexception ex) {
      ex.printstacktrace();
    }
catch(sqlexception e){
      e.printstacktrace();
    }
  }
  
public void getconnection(string dburl,string dbdriver,string dbusername,string dbpasswd){
  }
  
public void getstatement(){
    
try{
      getconnection();
      st 
= conn.createstatement();
    }
catch (sqlexception ex) {
      ex.printstacktrace();
    }
  }
  
//得到预备状态通道
  public void getpstatement(string sql){
    
try{
      getconnection();
      pst 
= conn.preparestatement(sql);
    }
catch (sqlexception ex) {
    }
  }
  
//执行查询得到结果集
  public resultset getresultset(string sql){
    
try{
       getstatement();
       rs
=st.executequery(sql);
    }
catch(sqlexception ex) {
    }
finally{
       
return rs;
    }
  }
  
//给预备状态通道中的sql的变量付值,然后执行
  public boolean executepstatement(list list){
     iscorrect
=false;
     
try{
          
for(int i = 0; i < list.size(); i){
            pst.setstring((i 
 1), list.get(i).tostring());
          }
          pst.executeupdate();
          iscorrect
=true;
      }
catch (sqlexception ex) {
      }
finally{
         
return iscorrect;
      }
  }
  
//执行新增、修改、删除
  public boolean doupdate(string sql){
    iscorrect
=false;
    
try{
      getstatement();
      st.executeupdate(sql);
      iscorrect
=true;
    }
catch (sqlexception ex){
       ex.printstacktrace();
    }
finally{
      
return iscorrect;
    }
  }
  
//执行存储过程
  public boolean doprocure(string pname,list list){
      iscorrect
=false;
    
try{
        getconnection();
       cs
=conn.preparecall("{call "pname"}");
       
for(int i = 0; i < list.size(); i)
       {
           cs.setstring((i 
 1), list.get(i).tostring());
       }
       cs.execute();
       iscorrect
=true;
    }
catch (sqlexception ex) {
    }
finally{
      
return iscorrect;
    }
  }
  
public void addbatch(list list){
    
try{
      
for(int i=0;i<list.size();i){
        st.addbatch(list.get(i).tostring());
      }
    }
catch(exception e){
    }
  }
  
public boolean executebatch(){
     iscorrect
=false;
     
try{
       st.executebatch();
       iscorrect
=true;
     }
catch(exception e){
        e.printstacktrace();
     }
finally{
        close();
        
return iscorrect;
     }
  }
  
//关闭连接
  public void close(){
      
try{
        
if(rs!=null)
        {
          rs.close();
        }
        
if(st!=null){
          st.close();
        }
        
if(pst!=null)
        {
          pst.close();
        }
        
if(cs!=null)
          cs.close();
        
if(conn!=null)
        conn.close();
      }
catch (sqlexception ex) {
      }
  }

}



礼物 2013-03-01 09:52
]]>
配置_druid和spring关联监控配置http://www.blogjava.net/libin2722/articles/395482.html礼物礼物wed, 20 feb 2013 09:40:00 gmthttp://www.blogjava.net/libin2722/articles/395482.htmlhttp://www.blogjava.net/libin2722/comments/395482.htmlhttp://www.blogjava.net/libin2722/articles/395482.html#feedback2http://www.blogjava.net/libin2722/comments/commentrss/395482.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/395482.htmldruid提供了spring和jdbc的关联监控。

blogjava-凯发k8网页登录

com.alibaba.druid.support.spring.stat.druidstatinterceptor是一个标准的spring methodinterceptor。可以灵活进行aop配置。

spring aop的配置文档: 

按类型拦截配置

				  
  
  
    
    
    
        
            druid-stat-interceptor
        
    
  

		

方法名正则匹配拦截配置

				  
  

    
        
            com.mycompany.service.*
            com.mycompany.dao.*
        
    


    


		

有些情况下,可能你需要配置proxy-target-class,例如:

				
    


		

按照beanid来拦截配置

				  
  

    
    
        
            
            xxx-dao
            xxx-service
        
    
    
        
            druid-stat-interceptor
        
    

		


礼物 2013-02-20 17:40
]]>
atomicintegerhttp://www.blogjava.net/libin2722/archive/2013/01/31/394996.html礼物礼物thu, 31 jan 2013 09:15:00 gmthttp://www.blogjava.net/libin2722/archive/2013/01/31/394996.htmlhttp://www.blogjava.net/libin2722/comments/394996.htmlhttp://www.blogjava.net/libin2722/archive/2013/01/31/394996.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394996.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394996.htmlatomicinteger,一个提供原子操作的integer的类。在java语言中, i和i 操作并不是线程安全的,在使用的时候,不可避免的会用到synchronized关键字。而atomicinteger则通过一种线程安全的加减操作接口。

来看atomicinteger提供的接口。

//获取当前的值

public final int get()

//取当前的值,并设置新的值

 public final int getandset(int newvalue)

//获取当前的值,并自增

 public final int getandincrement()

//获取当前的值,并自减

public final int getanddecrement()

//获取当前的值,并加上预期的值

public final int getandadd(int delta)

... ...


下面是一个对比测试,我们写一个synchronized的方法和一个atomicinteger的方法来进行测试,直观的感受下性能上的差异

[java]  
  1. package  zl.study.concurrency;  
  2. import  java.util.concurrent.atomic.atomicinteger;  
  3. public   class  atomicintegercomparetest {  
  4.     private int value;  
  5.       
  6.     public atomicintegercomparetest(int value){  
  7.         this.value = value;  
  8.     }  
  9.       
  10.     public synchronized int increase(){  
  11.         return value ;  
  12.     }  
  13.       
  14.     public static void main(string args[]){  
  15.         long start = system.currenttimemillis();  
  16.           
  17.         atomicintegercomparetest test = new atomicintegercomparetest(0);  
  18.         forint i=0;i< 1000000;i ){  
  19.             test.increase();  
  20.         }  
  21.         long end = system.currenttimemillis();  
  22.         system.out.println("time elapse:" (end -start));  
  23.           
  24.         long start1 = system.currenttimemillis();  
  25.           
  26.         atomicinteger atomic = new atomicinteger(0);  
  27.           
  28.         forint i=0;i< 1000000;i ){  
  29.             atomic.incrementandget();  
  30.         }  
  31.         long end1 = system.currenttimemillis();  
  32.         system.out.println("time elapse:" (end1 -start1) );  
  33.           
  34.           
  35.     }  
  36. }  

结果

time elapse:31
time elapse:16
由此不难看出,通过jni本地的cas性能远超synchronized关键字

 

reference

http://stackoverflow.com/questions/2443239/java-atomicinteger-what-are-the-differences-between-compareandset-and-weakcompar



礼物 2013-01-31 17:15
]]>
spring通过annotation注册mbean到jmxhttp://www.blogjava.net/libin2722/articles/394995.html礼物礼物thu, 31 jan 2013 09:02:00 gmthttp://www.blogjava.net/libin2722/articles/394995.htmlhttp://www.blogjava.net/libin2722/comments/394995.htmlhttp://www.blogjava.net/libin2722/articles/394995.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394995.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394995.html阅读全文

礼物 2013-01-31 17:02
]]>
bootstrap入门教程 (四)http://www.blogjava.net/libin2722/articles/394967.html礼物礼物thu, 31 jan 2013 03:08:00 gmthttp://www.blogjava.net/libin2722/articles/394967.htmlhttp://www.blogjava.net/libin2722/comments/394967.htmlhttp://www.blogjava.net/libin2722/articles/394967.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394967.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394967.html阅读全文

礼物 2013-01-31 11:08
]]>
bootstrap入门教程 (三)http://www.blogjava.net/libin2722/articles/394961.html礼物礼物thu, 31 jan 2013 02:16:00 gmthttp://www.blogjava.net/libin2722/articles/394961.htmlhttp://www.blogjava.net/libin2722/comments/394961.htmlhttp://www.blogjava.net/libin2722/articles/394961.html#feedback2http://www.blogjava.net/libin2722/comments/commentrss/394961.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394961.html阅读全文

礼物 2013-01-31 10:16
]]>
bootstrap入门教程 (二)http://www.blogjava.net/libin2722/articles/394960.html礼物礼物thu, 31 jan 2013 02:14:00 gmthttp://www.blogjava.net/libin2722/articles/394960.htmlhttp://www.blogjava.net/libin2722/comments/394960.htmlhttp://www.blogjava.net/libin2722/articles/394960.html#feedback1http://www.blogjava.net/libin2722/comments/commentrss/394960.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394960.html阅读全文

礼物 2013-01-31 10:14
]]>
bootstrap入门教程 (一)http://www.blogjava.net/libin2722/articles/394959.html礼物礼物thu, 31 jan 2013 02:08:00 gmthttp://www.blogjava.net/libin2722/articles/394959.htmlhttp://www.blogjava.net/libin2722/comments/394959.htmlhttp://www.blogjava.net/libin2722/articles/394959.html#feedback3http://www.blogjava.net/libin2722/comments/commentrss/394959.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394959.html阅读全文

礼物 2013-01-31 10:08
]]>
linux centos 6.3 tomcat installhttp://www.blogjava.net/libin2722/articles/394027.html礼物礼物wed, 09 jan 2013 07:01:00 gmthttp://www.blogjava.net/libin2722/articles/394027.htmlhttp://www.blogjava.net/libin2722/comments/394027.htmlhttp://www.blogjava.net/libin2722/articles/394027.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394027.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394027.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=apache-tomcat-7.0.34.tar.gz
source=http://mirror.bjtu.edu.cn/apache/tomcat/tomcat-7/v7.0.34/bin/$target

# create a build directory
mkdir -p /opt/install/tomcat && cd /opt/install/tomcat

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y apr-devel openssl-devel

# create a user group
groupadd tomcat
useradd -r -g tomcat tomcat

# compile and deploy
mkdir -p /opt/server/web && mv tmp/* /opt/server/web/tomcat && cd /opt/server/web/tomcat/bin
tar -zxvf tomcat-native.tar.gz && cd tomcat-native-1.1.24-src/jni/native/
./configure \
--with-apr=/usr/bin/apr-1-config \
--with-java-home=/opt/environment/java/1.7.0 \
--with-ssl=yes \
--prefix=/opt/server/web/tomcat
make
make install

cd /opt/server/web/tomcat
curl -o conf/server.xml https://raw.github.com/fly2wind/tsshellscript/master/tomcat/conf/server.xml
curl -o conf/tomcat-users.xml https://raw.github.com/fly2wind/tsshellscript/master/tomcat/conf/tomcat-users.xml
curl -o conf/wrapper.conf https://raw.github.com/fly2wind/tsshellscript/master/tomcat/wrapper/wrapper.conf
curl -o lib/wrapper.jar https://raw.github.com/fly2wind/tsshellscript/master/tomcat/wrapper/wrapper.jar
curl -o lib/wrapper.so https://raw.github.com/fly2wind/tsshellscript/master/tomcat/wrapper/libwrapper.so
curl -o bin/tomcat https://raw.github.com/fly2wind/tsshellscript/master/tomcat/wrapper/tomcat

# postinstallation setup
cd /opt/server/web/tomcat
chown -r tomcat .
chgrp -r tomcat .
chown -r root .
chown -r tomcat conf webapps work temp logs

# configuration
curl -o /etc/init.d/tomcat https://raw.github.com/fly2wind/tsshellscript/master/tomcat/init/tomcat
chmod a x /etc/init.d/tomcat

# additional
chkconfig --add tomcat
chkconfig tomcat on



礼物 2013-01-09 15:01
]]>
linux centos 6.3 nginx installhttp://www.blogjava.net/libin2722/articles/394024.html礼物礼物wed, 09 jan 2013 07:00:00 gmthttp://www.blogjava.net/libin2722/articles/394024.htmlhttp://www.blogjava.net/libin2722/comments/394024.htmlhttp://www.blogjava.net/libin2722/articles/394024.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394024.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394024.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=nginx-1.2.6.tar.gz
source=http://nginx.org/download/nginx-1.2.6.tar.gz

# create a build directory
mkdir -p /opt/install/nginx && cd /opt/install/nginx

# prepare for compilation source
curl -o $target $source
curl -o ngx_devel_kit.tar.gz https://nodeload.github.com/simpl/ngx_devel_kit/tar.gz/v0.2.17
curl -o lua-nginx-module.tar.gz https://nodeload.github.com/chaoslawful/lua-nginx-module/tar.gz/v0.7.12

mkdir -p tmp && tar -zxvf $target -c tmp
tar -zxvf ngx_devel_kit.tar.gz
tar -zxvf lua-nginx-module.tar.gz

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y pcre-devel zlib-devel openssl-devel

# create a user group
groupadd nginx
useradd -r -g nginx nginx

# compile and deploy
mv tmp/* source && cd source

export luajit_lib=/opt/environment/lua/lj2/lib
export luajit_inc=/opt/environment/lua/lj2/include/luajit-2.0

./configure \
--prefix=/opt/server/web/nginx \
--user=nginx \
--group=nginx \
--with-http_ssl_module \
--with-http_gzip_static_module \
--with-http_stub_status_module \
--http-client-body-temp-path=/opt/server/web/nginx/var/tmp/nginx/client-body \
--http-proxy-temp-path=/opt/server/web/nginx/var/tmp/nginx/proxy \
--http-fastcgi-temp-path=/opt/server/web/nginx/var/tmp/nginx/fastcgi \
--http-uwsgi-temp-path=/opt/server/web/nginx/var/tmp/nginx/uwsgi \
--http-scgi-temp-path=/opt/server/web/nginx/var/tmp/nginx/scgi \
--add-module=../ngx_devel_kit-0.2.17 \
--add-module=../lua-nginx-module-0.7.12 \
--with-ld-opt="-wl,-rpath,$luajit_lib"
make
make install

cd /opt/server/web/nginx
mkdir -p var/tmp/nginx var/lock var/run

curl -o conf/nginx.conf https://raw.github.com/fly2wind/tsshellscript/master/nginx/conf/nginx.conf

# postinstallation setup
cd /opt/server/web/nginx
chown -r nginx .
chgrp -r nginx .
chown -r root .
chown -r nginx html var

# configuration
curl -o /etc/init.d/nginx https://raw.github.com/fly2wind/tsshellscript/master/nginx/init/nginx
chmod a x /etc/init.d/nginx

# additional
chkconfig --add nginx
chkconfig nginx on




礼物 2013-01-09 15:00
]]>
linux centos 6.3 python installhttp://www.blogjava.net/libin2722/articles/394025.html礼物礼物wed, 09 jan 2013 07:00:00 gmthttp://www.blogjava.net/libin2722/articles/394025.htmlhttp://www.blogjava.net/libin2722/comments/394025.htmlhttp://www.blogjava.net/libin2722/articles/394025.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394025.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394025.html
#!/bin/sh
########################################################################################
#
# install jdk script
#
# shawn ma
#
########################################################################################
# define
target=python-2.7.3.tar.bz2
source=http://www.python.org/ftp/python/2.7.3/python-2.7.3.tar.bz2

# create a build directory
mkdir -p /opt/install/python && cd /opt/install/python

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -xvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y ncurses-devel openssl-devel readline-devel

# create a user group

# compile and deploy
mv tmp/* source && cd source
./configure \
--prefix=/opt/environment/python/2.7.3
make
make install

cd ..
curl -o http://python-distribute.org/distribute_setup.py
curl -o https://raw.github.com/pypa/pip/master/contrib/get-pip.py
/opt/environment/python/2.7.3/bin/python2.7 distribute_setup.py
/opt/environment/python/2.7.3/bin/python2.7 get-pip.py

# postinstallation setup
export path=$path:/opt/environment/python/2.7.3/bin

# configuration

# additional
sed -i '/export path=/a\export path=$path:\/opt\/environment\/python\/2.7.3\/bin' /etc/profile




礼物 2013-01-09 15:00
]]>
linux centos 6.3 redis installhttp://www.blogjava.net/libin2722/articles/394026.html礼物礼物wed, 09 jan 2013 07:00:00 gmthttp://www.blogjava.net/libin2722/articles/394026.htmlhttp://www.blogjava.net/libin2722/comments/394026.htmlhttp://www.blogjava.net/libin2722/articles/394026.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394026.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394026.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=redis-2.6.7.tar.gz
source=http://redis.googlecode.com/files/redis-2.6.7.tar.gz

# create a build directory
mkdir -p /opt/install/redis && cd /opt/install/redis

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake

# create a user group
groupadd redis
useradd -r -g redis redis

# compile and deploy
mv tmp/* source && cd source
make prefix=/opt/server/cache/redis
make install prefix=/opt/server/cache/redis

cd /opt/server/cache/redis
mkdir -p conf var/run var/lock var/snapshot logs
curl -o conf/redis.conf https://raw.github.com/fly2wind/tsshellscript/master/redis/conf/redis.conf

# postinstallation setup
cd /opt/server/cache/redis
chown -r redis .
chgrp -r redis .
chown -r root .
chown -r redis var logs

# configuration
curl -o /etc/init.d/redis https://raw.github.com/fly2wind/tsshellscript/master/redis/init/redis
chmod a x /etc/init.d/redis

# additional
chkconfig --add redis
chkconfig redis on




礼物 2013-01-09 15:00
]]>
linux centos 6.3 mysql installhttp://www.blogjava.net/libin2722/articles/394022.html礼物礼物wed, 09 jan 2013 06:59:00 gmthttp://www.blogjava.net/libin2722/articles/394022.htmlhttp://www.blogjava.net/libin2722/comments/394022.htmlhttp://www.blogjava.net/libin2722/articles/394022.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394022.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394022.html
#!/bin/sh
########################################################################################
#
# install mysql script
#
# shawn ma
# 2013-01-06
#
########################################################################################
# define
target=mysql-5.5.29.tar.gz
source=http://cdn.mysql.com/downloads/mysql-5.5/$target

# create a build directory
mkdir -p /opt/install/mysql && cd /opt/install/mysql

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y bison ncurses-devel

# create a user group
groupadd mysql
useradd -r -g mysql mysql

# compile and deploy
mv tmp/* source && cd source
cmake \
-dcmake_install_prefix=/opt/server/database/mysql \
-dsysconfdir=/opt/server/database/mysql \
-dmysql_unix_addr=/opt/server/database/mysql/tmp/mysql.sock \
-dmysql_tcp_port=3306 \
-dmysql_datadir=/opt/server/database/mysql/data \
-ddefault_charset=utf8 \
-ddefault_collation=utf8_general_ci \
-dwith_extra_charsets:string=all \
-dwith_innobase_storage_engine=1 \
-dwith_readline=1 \
-denabled_local_infile=1 \
-dwith_debug=off \
-dmysql_user=mysql
make
make install

cd /opt/server/database/mysql
curl -o my.cnf https://raw.github.com/fly2wind/tsshellscript/master/mysql/conf/my.cnf


# postinstallation setup
cd /opt/server/database/mysql
chown -r mysql .
chgrp -r mysql .
scripts/mysql_install_db --user=mysql
chown -r root .
chown -r mysql data

# configuration
curl -o /etc/init.d/mysql https://raw.github.com/fly2wind/tsshellscript/master/mysql/init/mysql
chmod a x /etc/init.d/mysql

/etc/init.d/mysql start
bin/mysqladmin -u root password "tv.xian"
bin/mysql -u root -ptv.xian -e "grant all on *.* to 'root'@'%' identified by 'tv.xian' with grant option; flush privileges;"
bin/mysql -u root -ptv.xian -e "grant replication slave on *.* to 'backup'@'%' identified by 'backup'; flush privileges;";
/etc/init.d/mysql stop

# additional
chkconfig --add mysql
chkconfig mysql on



礼物 2013-01-09 14:59
]]>
linux centos 6.3 mysql slave installhttp://www.blogjava.net/libin2722/articles/394023.html礼物礼物wed, 09 jan 2013 06:59:00 gmthttp://www.blogjava.net/libin2722/articles/394023.htmlhttp://www.blogjava.net/libin2722/comments/394023.htmlhttp://www.blogjava.net/libin2722/articles/394023.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394023.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394023.html
#!/bin/sh
########################################################################################
#
# install mysql script
#
# shawn ma
#
########################################################################################
# define
target=mysql-5.5.29.tar.gz
source=http://cdn.mysql.com/downloads/mysql-5.5/$target

# create a build directory
mkdir -p /opt/install/mysql && cd /opt/install/mysql

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y bison ncurses-devel

# create a user group
groupadd mysql
useradd -r -g mysql mysql

# compile and deploy
mv tmp/* source && cd source
cmake \
-dcmake_install_prefix=/opt/server/database/mysql_slave \
-dsysconfdir=/opt/server/database/mysql_slave \
-dmysql_unix_addr=/opt/server/database/mysql_slave/tmp/mysql.sock \
-dmysql_tcp_port=3307 \
-dmysql_datadir=/opt/server/database/mysql_slave/data \
-ddefault_charset=utf8 \
-ddefault_collation=utf8_general_ci \
-dwith_extra_charsets:string=all \
-dwith_innobase_storage_engine=1 \
-dwith_readline=1 \
-denabled_local_infile=1 \
-dwith_debug=off \
-dmysql_user=mysql
make
make install

# postinstallation setup
cd /opt/server/database/mysql_slave
chown -r mysql .
chgrp -r mysql .
scripts/mysql_install_db --user=mysql
chown -r root .
chown -r mysql data

# configuration
cp support-files/my-medium.cnf my.cnf
sed -i "/\[mysqld\]$/a\datadir         = \/opt\/server\/database\/mysql_slave\/data/" my.cnf
sed -i "s/^server-id.*/server-id       = 2/g" my.cnf
cp support-files/mysql.server /etc/init.d/mysql_slave && chmod a x /etc/init.d/mysql_slave
##chkconfig --add mysql
##chkconfig --level 345 mysql on
##update-rc.d -a mysql
##update-rc.d mysql defaults

# additional
/etc/init.d/mysql_slave start
bin/mysqladmin -u root password "tv.xian"
bin/mysql -u root -ptv.xian -e "grant all on *.* to 'root'@'%' identified by 'tv.xian' with grant option; flush privileges;"
bin/mysql -u root -ptv.xian -e "change master to master_host='192.168.102.128',master_port=3306,master_user='backup',master_password='backup', master_log_file='mysql-bin.000005',master_log_pos=326;"
bin/mysql -u root -ptv.xian -e "start slave;"

/etc/init.d/mysql_slave stop



礼物 2013-01-09 14:59
]]>
linux centos 6.3 lua installhttp://www.blogjava.net/libin2722/articles/394020.html礼物礼物wed, 09 jan 2013 06:58:00 gmthttp://www.blogjava.net/libin2722/articles/394020.htmlhttp://www.blogjava.net/libin2722/comments/394020.htmlhttp://www.blogjava.net/libin2722/articles/394020.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394020.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394020.html
#!/bin/sh
########################################################################################
#
# install lua script
#
# shawn ma
#
########################################################################################
# define
target=luajit-2.0.0.tar.gz
source=http://luajit.org/download/luajit-2.0.0.tar.gz

# create a build directory
mkdir -p /opt/install/lua && cd /opt/install/lua

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies

# create a user group

# compile and deploy
mv tmp/* source && cd source
make prefix=/opt/environment/lua/lj2
make install prefix=/opt/environment/lua/lj2

# postinstallation setup
export path=$path:/opt/environment/lua/lj2/bin

# configuration

# additional






礼物 2013-01-09 14:58
]]>
linux centos 6.3 memcached installhttp://www.blogjava.net/libin2722/articles/394021.html礼物礼物wed, 09 jan 2013 06:58:00 gmthttp://www.blogjava.net/libin2722/articles/394021.htmlhttp://www.blogjava.net/libin2722/comments/394021.htmlhttp://www.blogjava.net/libin2722/articles/394021.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394021.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394021.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=memcached-1.4.15.tar.gz
source=http://memcached.googlecode.com/files/memcached-1.4.15.tar.gz

# create a build directory
mkdir -p /opt/install/memcached && cd /opt/install/memcached

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y libevent-devel

# create a user group
groupadd memcache
useradd -r -g memcache memcache

# compile and deploy
mv tmp/* source && cd source
./configure \
--prefix=/opt/server/cache/memcached
make
make install

cd /opt/server/cache/memcached
mkdir -p conf var/run var/lock logs
curl -o conf/memcached.conf https://raw.github.com/fly2wind/tsshellscript/master/memcached/conf/memcached.conf

# postinstallation setup
cd /opt/server/cache/memcached
chown -r memcache .
chgrp -r memcache .
chown -r root .
chown -r memcache var logs

# configuration
curl -o /etc/init.d/memcached https://raw.github.com/fly2wind/tsshellscript/master/memcached/init/memcached
chmod a x /etc/init.d/memcached

# additional
chkconfig --add memcached
chkconfig memcached on




礼物 2013-01-09 14:58
]]>
linux centos 6.3 erlang installhttp://www.blogjava.net/libin2722/articles/394018.html礼物礼物wed, 09 jan 2013 06:57:00 gmthttp://www.blogjava.net/libin2722/articles/394018.htmlhttp://www.blogjava.net/libin2722/comments/394018.htmlhttp://www.blogjava.net/libin2722/articles/394018.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394018.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394018.html
#!/bin/sh
########################################################################################
#
# install jdk script
#
# shawn ma
#
########################################################################################
# define
target=otp_r15b03-1.tar.gz
source=https://nodeload.github.com/erlang/otp/tar.gz/otp_r15b03-1

# create a build directory
mkdir -p /opt/install/erlang && cd /opt/install/erlang

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y ncurses-devel openssl-devel

# create a user group

# compile and deploy
mv tmp/* source && cd source
./otp_build autoconf
./configure \
--prefix=/opt/environment/erlang/r15b03 \
--enable-threads \
--enable-smp-support \
--enable-kernel-poll \
--enable-hipe \
--without-termcap \
--without-javac \
--with-ssl
make
make install

# postinstallation setup
export path=$path:/opt/environment/erlang/r15b03/bin

# configuration

# additional
# export path user
sed -i '/export path=/a\export path=$path:\/opt\/environment\/erlang\/r15b03\/bin' /etc/profile



礼物 2013-01-09 14:57
]]>
linux centos 6.3 graphicsmagick installhttp://www.blogjava.net/libin2722/articles/394019.html礼物礼物wed, 09 jan 2013 06:57:00 gmthttp://www.blogjava.net/libin2722/articles/394019.htmlhttp://www.blogjava.net/libin2722/comments/394019.htmlhttp://www.blogjava.net/libin2722/articles/394019.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394019.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394019.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=graphicsmagick-latest.tar.gz
source=ftp://ftp.graphicsmagick.org/pub/graphicsmagick/graphicsmagick-latest.tar.gz

# create a build directory
mkdir -p /opt/install/graphicsmagick && cd /opt/install/graphicsmagick

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y libpng-devel libjpeg-devel libtiff-devel jasper-devel freetype-devel

# create a user group

# compile and deploy
mv tmp/* source && cd source
./configure \
--prefix=/opt/tools/graphicsmagick \
--enable-shared \
--enable-static \
--with-quantum-depth=16 \
--with-ttf \
--with-jpeg \
--with-jp2 \
--with-png \
--with-zlib

make
make install

cd /opt/server/cache/memcached
mkdir -p conf var/run var/lock logs
curl -o conf/memcached.conf https://raw.github.com/fly2wind/tsshellscript/master/memcached/conf/memcached.conf

# postinstallation setup
cd /opt/server/cache/memcached
chown -r memcache .
chgrp -r memcache .
chown -r root .
chown -r memcache var logs

# configuration
curl -o /etc/init.d/memcached https://raw.github.com/fly2wind/tsshellscript/master/memcached/init/memcached
chmod a x /etc/init.d/memcached

# additional
chkconfig --add memcached
chkconfig memcached on




礼物 2013-01-09 14:57
]]>
linux centos 6.3 ejabberd installhttp://www.blogjava.net/libin2722/articles/394017.html礼物礼物wed, 09 jan 2013 06:55:00 gmthttp://www.blogjava.net/libin2722/articles/394017.htmlhttp://www.blogjava.net/libin2722/comments/394017.htmlhttp://www.blogjava.net/libin2722/articles/394017.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/394017.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/394017.html
#!/bin/sh
########################################################################################
#
# install ejabberd server
#
# shawn ma
#
########################################################################################
# define
target=v2.1.11.tar.gz
source=https://nodeload.github.com/processone/ejabberd/tar.gz/v2.1.11

# create a build directory
mkdir -p /opt/install/ejabberd && cd /opt/install/ejabberd

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies
yum install -y gcc gcc-c make cmake autoconf automake
yum install -y expat-devel

# create a user group
groupadd ejabberd
useradd -r -g ejabberd ejabberd

# compile and deploy
mv tmp/* source && cd source\src
./configure \
--prefix=/opt/server/xmpp/ejabberd \
--enable-user=ejabberd \
--enable-full-xml \
--enable-nif
make
make install

cd /opt/server/xmpp/ejabberd
curl -o etc/ejabberd/ejabberd.cfg https://raw.github.com/fly2wind/tsshellscript/master/ejabberd/conf/ejabberd.cfg
curl -o etc/ejabberd/ejabberdctl.cfg https://raw.github.com/fly2wind/tsshellscript/master/ejabberd/conf/ejabberdctl.cfg
curl -o etc/ejabberd/inetrc https://raw.github.com/fly2wind/tsshellscript/master/ejabberd/conf/inetrc

# postinstallation setup
cd /opt/server/xmpp/ejabberd
chown -r ejabberd .
chgrp -r ejabberd .
chown -r root .
chown -r ejabberd var

# configuration
sed -i "/^erl=.*/a\pmd=\/opt\/environment\/erlang\/r15b03\/bin\/epmd" sbin/ejabberdctl
sed -i -e "s/epmd -names | grep -q name || epmd -kill/\$pmd -names | grep -q name || \$pmd -kill/" sbin/ejabberdctl
curl -o /etc/init.d/ejabberd https://raw.github.com/fly2wind/tsshellscript/master/ejabberd/init/ejabberd
chmod a x /etc/init.d/ejabberd

# additional
chkconfig --add ejabberd
chkconfig ejabberd on




礼物 2013-01-09 14:55
]]>
linux centos 6.3 jdk installhttp://www.blogjava.net/libin2722/articles/393978.html礼物礼物tue, 08 jan 2013 09:38:00 gmthttp://www.blogjava.net/libin2722/articles/393978.htmlhttp://www.blogjava.net/libin2722/comments/393978.htmlhttp://www.blogjava.net/libin2722/articles/393978.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/393978.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/393978.html
#!/bin/sh
########################################################################################
#
# install jdk script
#
# shawn ma
#
########################################################################################
# define
target=jdk-7u10-linux-x64.tar.gz
source=http://www.ganshazi.com/jdk-7u10-linux-x64.tar.gz

# create a build directory
mkdir -p /opt/install/java && cd /opt/install/java

# prepare for compilation source
curl -o $target $source
mkdir -p tmp && tar -zxvf $target -c tmp

# install build dependencies

# create a user group

# compile and deploy
mkdir -p /opt/environment/java && mv tmp/* /opt/environment/java/1.7.0

# postinstallation setup
export path=$path:/opt/environment/java/1.7.0/bin

# configuration

# additional
sed -i '/export path$/a\export path=$path:\/opt\/environment\/java\/1.7\/bin' /etc/profile







礼物 2013-01-08 17:38
]]>
flex摄像头拍照 java上传到数据库 .http://www.blogjava.net/libin2722/articles/355899.html礼物礼物fri, 05 aug 2011 14:32:00 gmthttp://www.blogjava.net/libin2722/articles/355899.htmlhttp://www.blogjava.net/libin2722/comments/355899.htmlhttp://www.blogjava.net/libin2722/articles/355899.html#feedback2http://www.blogjava.net/libin2722/comments/commentrss/355899.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/355899.html阅读全文

礼物 2011-08-05 22:32
]]>
nginx tomcat memcached共享session集群配置http://www.blogjava.net/libin2722/articles/355897.html礼物礼物fri, 05 aug 2011 13:31:00 gmthttp://www.blogjava.net/libin2722/articles/355897.htmlhttp://www.blogjava.net/libin2722/comments/355897.htmlhttp://www.blogjava.net/libin2722/articles/355897.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/355897.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/355897.html1、采用nginx负载均衡 
2、memcached共享session 
3、tomcat集群配置(3台centos 6) 

(172.18.188.64): 操作系统centos 6; 安装nginx、memcached和tomcat 6 
(172.18.188.76): 操作系统centos 6; 安装tomcat 6 
(172.18.188.78): 操作系统centos 6; 安装tomcat 6 

nginx、memcached、tomcat 6安装省略. 

nginx配置如下: 

nginx.conf如下: 
#运行nginx所在的用户名和用户组 
#user  root root; 

#启动进程数 
worker_processes 8; 
#全局错误日志及pid文件 
error_log /usr/local/webserver/nginx/logs/nginx_error.log crit; 

pid /usr/local/webserver/nginx/nginx.pid; 

#specifies the value for maximum file descriptors that can be opened by this process. 

worker_rlimit_nofile 65535; 
#工作模式及连接数上限 
events 
{ 
  use epoll; 
  worker_connections 65535; 
} 
#设定http服务器,利用它的反向代理功能提供负载均衡支持 
http 
{ 
  #设定mime类型 
  include       mime.types; 
  default_type  application/octet-stream; 
  include /usr/local/webserver/nginx/conf/proxy.conf; 
  #charset  gb2312; 
  #设定请求缓冲   
  server_names_hash_bucket_size 128; 
  client_header_buffer_size 32k; 
  large_client_header_buffers 4 32k; 
  #client_max_body_size 8m; 
     
  sendfile on; 
  tcp_nopush     on; 

  keepalive_timeout 60; 

  tcp_nodelay on; 

#  fastcgi_connect_timeout 300; 
#  fastcgi_send_timeout 300; 
#  fastcgi_read_timeout 300; 
#  fastcgi_buffer_size 64k; 
#  fastcgi_buffers 4 64k; 
#  fastcgi_busy_buffers_size 128k; 
#  fastcgi_temp_file_write_size 128k; 

  gzip on; 
  gzip_min_length  1k; 
  gzip_buffers     4 16k; 
  gzip_http_version 1.0; 
  gzip_comp_level 2; 
  gzip_types       text/plain application/x-javascript text/css application/xml; 
  gzip_vary on; 

  #limit_zone  crawler  $binary_remote_addr  10m; 
###禁止通过ip访问站点 
#  server{ 
#       server_name _; 
#       return 404; 
#       } 

upstream tserver { 
    server 172.18.188.64:8080 weight=1; 
    server 172.18.188.76:8080 weight=1; 
    server 172.18.188.78:8080 weight=1; 
} 

  server 
  { 
    listen       80; 
    server_name  vmwarehost; 
    index index.html index.htm index.jsp; 
    root  /home/www/web/root; 

    #limit_conn   crawler  20;   
    
    location / 
    { 
    proxy_pass http://tserver; 
    }  
    
    location /nginxstatus 
    { 
      stub_status on; 
      access_log off; 
    }    
   
    location ~ .*\.(htm|html|gif|jpg|jpeg|png|bmp|swf|ico)$ 
    { 
      expires      30d; 
    } 

    location ~ .*\.(js|css)?$ 
    { 
      expires      1h; 
    }   

#定义访问日志的写入格式 
     log_format  access  '$remote_addr - $remote_user [$time_local] "$request" ' 
              '$status $body_bytes_sent "$http_referer" ' 
              '"$http_user_agent" $http_x_forwarded_for'; 
              access_log  /usr/local/webserver/nginx/logs/localhost.log access; 

      } 

} 

proxy.confi配置如下 
#!nginx (-) 
# proxy.conf 
proxy_redirect          off; 
proxy_set_header        host $host; 
proxy_set_header        x-real-ip $remote_addr; 
proxy_set_header       x-forwarded-for   $proxy_add_x_forwarded_for; 
client_max_body_size    10m; 
client_body_buffer_size 128k; 
proxy_connect_timeout   90; 
proxy_send_timeout      90; 
proxy_read_timeout      90; 
proxy_buffer_size       4k; 
proxy_buffers           4 32k; 
proxy_busy_buffers_size 64k; 
proxy_temp_file_write_size 64k; 

tomcat 6 server.xml配置如下: 
 
 
 
 

   
   
   
   
   
   
   
   
   

   
   
     
     
              type="org.apache.catalina.userdatabase" 
              description="user database that can be updated and saved" 
              factory="org.apache.catalina.users.memoryuserdatabasefactory" 
              pathname="conf/tomcat-users.xml" /> 
 
 

   
   
  
     
     
    
    
     
     
               maxhttpheadersize="8192" connectiontimeout="20000" 
               disableuploadtimeout="true" enablelookups="false" 
               redirectport="8443" maxthreads="600" 
               minsparethreads="25" maxsparethreads="75" acceptcount="100" /> 
     
               
     
     

     
     
    maxhttpheadersize="8192" connectiontimeout="20000" 
                  disableuploadtimeout="true" maxthreads="600" 
                  minsparethreads="25" maxsparethreads="75" 
                  enablelookups="false" redirectport="8443" /> 


     

     
     

       
      
          
         
                 channelsendoptions="6"> 
 
            
           
             
                        address="228.0.0.4" 
                        port="45564" 
                        frequency="500" 
                        droptime="3000"/> 
             
                      address="172.18.188.64" 
                      port="4001" 
                      autobind="100" 
                      selectortimeout="5000" 
                      maxthreads="6"/> 

             
               
           
         
             
             
                      
         
 

           
          filter=".*\.gif;.*\.js;.*\.jpg;.*\.png;.*\.htm;.*\.html;.*\.css;.*\.txt;" /> 

           
                        tempdir="/tmp/war-temp/" 
                        deploydir="/tmp/war-deploy/" 
                        watchdir="/tmp/war-listen/" 
                        watchenabled="false"/> 
           
       
 
             

       
       

       
       
             resourcename="userdatabase"/> 

       
       
            unpackwars="true" autodeploy="true" 
            xmlvalidation="false" xmlnamespaceaware="false"> 

         
         

         
         
     
 
   
 
 
 
 

content.xml配置如下 
 

     
    web-inf/web.xml 

     
     

     
     
 
memcachednodes="n1:172.18.188.64:11211" 
requesturiignorepattern=".*\.(png|gif|jpg|css|js)$" 
sessionbackupasync="false" 
sessionbackuptimeout="100" 
transcoderfactoryclass="de.javakaffee.web.msm.serializer.javolution.javolutiontranscoderfactory" 
copycollectionsforserialization="false"/> 
 
memcached启动命令: 
useradd -s /sbin/nologin memcached 
memcached -d -m 2048 -l 172.18.188.64 -p 11211 -u memcached 
ngingx启动命令 
sbin/nginx 
tomcat启动命令(startup.sh) 
分别启动memcached nginx tomcat能实现session的简单共享. 
按照上面配置nginx memcached tomcat启动运行都没有问题,并且可以实现session的共享.但是有2个问题 
一、session的共享是基于访问ip的,即在同一台电脑上开2个ie窗口时,获取到session中内容是相同的,也就是sessionid除了最后面的jvmrout不一样,其他都一样,内容也一样,这样就造成如果2个用户先后在同一台电脑上登录形成session混乱,有没有可能配置成同一ip在不同的ie窗口中不共享session,一个ie窗口对应一个session,而不是一个ip共享一个session.后台的访问依然是由nginx根据weight做分发而不是固定到一台固定的tomcat机器? 
二、memcached 启动是用-m 512发现会有数据丢失而且丢失几率很大,在一个页面上连续不断的刷新时就会发现session中的内容会清空.

礼物 2011-08-05 21:31
]]>
基于词典的正向最大匹配中文分词算法,能实现中英文数字混合分词http://www.blogjava.net/libin2722/articles/355838.html礼物礼物fri, 05 aug 2011 00:34:00 gmthttp://www.blogjava.net/libin2722/articles/355838.htmlhttp://www.blogjava.net/libin2722/comments/355838.htmlhttp://www.blogjava.net/libin2722/articles/355838.html#feedback2http://www.blogjava.net/libin2722/comments/commentrss/355838.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/355838.html阅读全文

礼物 2011-08-05 08:34
]]>
linux下nginx tomcat整合的安装与配置http://www.blogjava.net/libin2722/articles/355631.html礼物礼物wed, 03 aug 2011 01:08:00 gmthttp://www.blogjava.net/libin2722/articles/355631.htmlhttp://www.blogjava.net/libin2722/comments/355631.htmlhttp://www.blogjava.net/libin2722/articles/355631.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/355631.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/355631.html阅读全文

礼物 2011-08-03 09:08
]]>
从 ibatis 到 mybatis - mybatis 简明学习教程http://www.blogjava.net/libin2722/articles/354030.html礼物礼物sun, 10 jul 2011 02:40:00 gmthttp://www.blogjava.net/libin2722/articles/354030.htmlhttp://www.blogjava.net/libin2722/comments/354030.htmlhttp://www.blogjava.net/libin2722/articles/354030.html#feedback3http://www.blogjava.net/libin2722/comments/commentrss/354030.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/354030.html阅读全文

礼物 2011-07-10 10:40
]]>
apache http server与tomcat实现负载均衡和集群http://www.blogjava.net/libin2722/articles/352842.html礼物礼物wed, 22 jun 2011 14:18:00 gmthttp://www.blogjava.net/libin2722/articles/352842.htmlhttp://www.blogjava.net/libin2722/comments/352842.htmlhttp://www.blogjava.net/libin2722/articles/352842.html#feedback2http://www.blogjava.net/libin2722/comments/commentrss/352842.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/352842.html阅读全文

礼物 2011-06-22 22:18
]]>
linux nginx tomcat负载均衡,实现session同步http://www.blogjava.net/libin2722/articles/352841.html礼物礼物wed, 22 jun 2011 14:15:00 gmthttp://www.blogjava.net/libin2722/articles/352841.htmlhttp://www.blogjava.net/libin2722/comments/352841.htmlhttp://www.blogjava.net/libin2722/articles/352841.html#feedback0http://www.blogjava.net/libin2722/comments/commentrss/352841.htmlhttp://www.blogjava.net/libin2722/services/trackbacks/352841.html阅读全文

礼物 2011-06-22 22:15
]]>
网站地图