在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 |
找到my.ini文件
添加一句max_allowed_packet=16m,如果不行将16m再加大
加大wait_timeout也可起一定作用
eg:
wait_timeout=2880000
interactive_timeout
max_allowed_packet
应用时记住重启数据库哦~~
林花谢了春红, 太匆匆, 无奈朝来寒雨晚来风。 胭脂泪, 相留醉, 几时重, 自是人生长恨水长东。 ** @author winter lau (http://my.oschina.net/javayou)
一 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
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]
......
|
电影a
|
电影b
|
电影c
|
电影d
|
张三
|
喜欢
|
|
|
|
李四
|
喜欢
|
喜欢
|
喜欢
|
喜欢
|
王五
|
不喜欢
|
|
不喜欢
|
不喜欢
|
赵六
|
喜欢
|
喜欢
|
|
喜欢
|
简介: 随着 web 技术的发展,使得内容的创建和分享变得越来越容易。每天都有大量的图片、博客、视频发布到网上。信息的极度爆炸使得人们找到他们需要的信息将变得越来越难。传统的搜索技术是一个相对简单的帮助人们找到信息的工具,也广泛的被人们所使用,但搜索引擎并不能完全满足用户对信息发现的需求,原因一是用户很难用恰当的关键词描述自己的需求,二是基于关键词的信息检索在很多情况下是不够的。而推荐引擎的出现,使用户获取信息的方式从简单的目标明确的数据的搜索转换到更高级更符合人们使用习惯的上下文信息更丰富的信息发现。
发布日期: 2011 年 3 月 16 日
级别: 高级
访问情况 : 65031 次浏览
评论: 11 ( | - 登录)
“探索推荐引擎内部的秘密”系列将带领读者从浅入深的学习探索推荐引擎的机制,实现方法,其中还涉及一些基本的优化方法,例如聚类和分类的应用。同时在理论讲解的基础上,还会结合 apache mahout 介绍如何在大规模数据上实现各种推荐策略,进行策略优化,构建高效的推荐引擎的方法。本文作为这个系列的第一篇文章,将深入介绍推荐引擎的工作原理,和其中涉及的各种推荐机制,以及它们各自的优缺点和适用场景,帮助用户清楚的了解和快速构建适合自己的推荐引擎。
如今已经进入了一个数据爆炸的时代,随着 web 2.0 的发展, web 已经变成数据分享的平台,那么,如何让人们在海量的数据中想要找到他们需要的信息将变得越来越难。
在这样的情形下,搜索引擎(google,bing,百度等等)成为大家快速找到目标信息的最好途径。在用户对自己需求相对明确的时候,用搜索引擎很方便的通过关键字搜索很快的找到自己需要的信息。但搜索引擎并不能完全满足用户对信息发现的需求,那是因为在很多情况下,用户其实并不明确自己的需要,或者他们的需求很难用简单的关键字来表述。又或者他们需要更加符合他们个人口味和喜好的结果,因此出现了推荐系统,与搜索引擎对应,大家也习惯称它为推荐引擎。
随着推荐引擎的出现,用户获取信息的方式从简单的目标明确的数据的搜索转换到更高级更符合人们使用习惯的信息发现。
如今,随着推荐技术的不断发展,推荐引擎已经在电子商务 (e-commerce,例如 amazon,当当网 ) 和一些基于 social 的社会化站点 ( 包括音乐,电影和图书分享,例如豆瓣,mtime 等 ) 都取得很大的成功。这也进一步的说明了,web2.0 环境下,在面对海量的数据,用户需要这种更加智能的,更加了解他们需求,口味和喜好的信息发现机制。
前面介绍了推荐引擎对于现在的 web2.0 站点的重要意义,这一章我们将讲讲推荐引擎到底是怎么工作的。推荐引擎利用特殊的信息过滤技术,将不同的物品或内容推荐给可能对它们感兴趣的用户。
图 1 给出了推荐引擎的工作原理图,这里先将推荐引擎看作黑盒,它接受的输入是推荐的数据源,一般情况下,推荐引擎所需要的数据源包括:
显式的用户反馈能准确的反应用户对物品的真实喜好,但需要用户付出额外的代价,而隐式的用户行为,通过一些分析和处理,也能反映用户的喜好,只是数据不是很精确,有些行为的分析存在较大的噪音。但只要选择正确的行为特征,隐式的用户反馈也能得到很好的效果,只是行为特征的选择可能在不同的应用中有很大的不同,例如在电子商务的网站上,购买行为其实就是一个能很好表现用户喜好的隐式反馈。
推荐引擎根据不同的推荐机制可能用到数据源中的一部分,然后根据这些数据,分析出一定的规则或者直接对用户对其他物品的喜好进行预测计算。这样推荐引擎可以在用户进入的时候给他推荐他可能感兴趣的物品。
推荐引擎的分类可以根据很多指标,下面我们一一介绍一下:
根据这个指标,推荐引擎可以分为基于大众行为的推荐引擎和个性化推荐引擎
这是一个最基本的推荐引擎分类,其实大部分人们讨论的推荐引擎都是将个性化的推荐引擎,因为从根本上说,只有个性化的推荐引擎才是更加智能的信息发现过程。
其实这里讲的是如何发现数据的相关性,因为大部分推荐引擎的工作原理还是基于物品或者用户的相似集进行推荐。那么参考图 1 给出的推荐系统原理图,根据不同的数据源发现数据相关性的方法可以分为以下几种:
可以想象在海量物品和用户的系统中,推荐引擎的计算量是相当大的,要实现实时的推荐务必需要建立一个推荐模型,关于推荐模型的建立方式可以分为以下几种:
其实在现在的推荐系统中,很少有只使用了一个推荐策略的推荐引擎,一般都是在不同的场景下使用不同的推荐策略从而达到最好的推荐效果,例如 amazon 的推荐,它将基于用户本身历史购买数据的推荐,和基于用户当前浏览的物品的推荐,以及基于大众喜好的当下比较流行的物品都在不同的区域推荐给用户,让用户可以从全方位的推荐中找到自己真正感兴趣的物品。
这一章的篇幅,将详细介绍各个推荐机制的工作原理,它们的优缺点以及应用场景。
基于人口统计学的推荐机制(demographic-based recommendation)是一种最易于实现的推荐方法,它只是简单的根据系统用户的基本信息发现用户的相关程度,然后将相似用户喜爱的其他物品推荐给当前用户,图 2 给出了这种推荐的工作原理。
从图中可以很清楚的看到,首先,系统对每个用户都有一个用户 profile 的建模,其中包括用户的基本信息,例如用户的年龄,性别等等;然后,系统会根据用户的 profile 计算用户的相似度,可以看到用户 a 的 profile 和用户 c 一样,那么系统会认为用户 a 和 c 是相似用户,在推荐引擎中,可以称他们是“邻居”;最后,基于“邻居”用户群的喜好推荐给当前用户一些物品,图中将用户 a 喜欢的物品 a 推荐给用户 c。
这种基于人口统计学的推荐机制的好处在于:
那么这个方法的缺点和问题是什么呢?这种基于用户的基本信息对用户进行分类的方法过于粗糙,尤其是对品味要求较高的领域,比如图书,电影和音乐等领域,无法得到很好的推荐效果。可能在一些电子商务的网站中,这个方法可以给出一些简单的推荐。另外一个局限是,这个方法可能涉及到一些与信息发现问题本身无关却比较敏感的信息,比如用户的年龄等,这些用户信息不是很好获取。
基于内容的推荐是在推荐引擎出现之初应用最为广泛的推荐机制,它的核心思想是根据推荐物品或内容的元数据,发现物品或者内容的相关性,然后基于用户以往的喜好记录,推荐给用户相似的物品。图 3 给出了基于内容推荐的基本原理。
图 3 中给出了基于内容推荐的一个典型的例子,电影推荐系统,首先我们需要对电影的元数据有一个建模,这里只简单的描述了一下电影的类型;然后通过电影的元数据发现电影间的相似度,因为类型都是“爱情,浪漫”电影 a 和 c 被认为是相似的电影(当然,只根据类型是不够的,要得到更好的推荐,我们还可以考虑电影的导演,演员等等);最后实现推荐,对于用户 a,他喜欢看电影 a,那么系统就可以给他推荐类似的电影 c。
这种基于内容的推荐机制的好处在于它能很好的建模用户的口味,能提供更加精确的推荐。但它也存在以下几个问题:
虽然这个方法有很多不足和问题,但他还是成功的应用在一些电影,音乐,图书的社交站点,有些站点还请专业的人员对物品进行基因编码,比如潘多拉,在一份报告中说道,在潘多拉的推荐引擎中,每首歌有超过 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 站点中,物品的个数是远远小于用户的数量的,而且物品的个数和相似度相对比较稳定,同时基于项目的机制比基于用户的实时性更好一些。但也不是所有的场景都是这样的情况,可以设想一下在一些新闻推荐系统中,也许物品,也就是新闻的个数可能大于用户的个数,而且新闻的更新程度也有很快,所以它的形似度依然不稳定。所以,其实可以看出,推荐策略的选择其实和具体的应用场景有很大的关系。
基于模型的协同过滤推荐
基于模型的协同过滤推荐就是基于样本的用户喜好信息,训练一个推荐模型,然后根据实时的用户喜好的信息进行预测,计算推荐。
基于协同过滤的推荐机制是现今应用最为广泛的推荐机制,它有以下几个显著的优点:
而它也存在以下几个问题:
在现行的 web 站点上的推荐往往都不是单纯只采用了某一种推荐的机制和策略,他们往往是将多个方法混合在一起,从而达到更好的推荐效果。关于如何组合各个推荐机制,这里讲几种比较流行的组合方法。
介绍完推荐引擎的基本原理,基本推荐机制,下面简要分析几个有代表性的推荐引擎的应用,这里选择两个领域:amazon 作为电子商务的代表,豆瓣作为社交网络的代表。
推荐在电子商务中的应用 – amazon
amazon 作为推荐引擎的鼻祖,它已经将推荐的思想渗透在应用的各个角落。amazon 推荐的核心是通过数据挖掘算法和比较用户的消费偏好于其他用户进行对比,借以预测用户可能感兴趣的商品。对应于上面介绍的各种推荐机制,amazon 采用的是分区的混合的机制,并将不同的推荐结果分不同的区显示给用户,图 6 和图 7 展示了用户在 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 公司立场、战略和观点。
学习
讨论
com.alibaba.druid.support.spring.stat.druidstatinterceptor是一个标准的spring methodinterceptor。可以灵活进行aop配置。
spring aop的配置文档:
druid-stat-interceptor
com.mycompany.service.*
com.mycompany.dao.*
有些情况下,可能你需要配置proxy-target-class,例如:
xxx-dao
xxx-service
druid-stat-interceptor
来看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的方法来进行测试,直观的感受下性能上的差异
结果
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