All posts by dotte

“推荐系统”精品资料合集

推荐系统的搭建是个复杂工程,涉及到实时计算、离线计算,以及各种数据采集、流转等,对自建推荐系统来说,更是很有困难。云栖社区将在6月16日晚20点组织一场在线分享《21天搭建推荐系统》,主要介绍推荐系统基本原理,并以阿里云推荐引擎为基础,展示如何快速搭建推荐系统。

为了帮助大家做好内容知识储备,云栖社区收集整理了一批学习资料,希望对大家学习推荐系统有所帮助,内容主要包括杂志、优秀的知乎问答、优秀图书及优秀博文。如果你也有好的学习资料,欢迎留言,或邮件我们 yqeditor@list.alibaba-inc.com,感谢您的支持!

杂志:

  1. 架构师特刊

《架构师特刊:推荐系统(理论篇)》

内容目录:

  • 第1章 推荐算法简介
  • 第2章 协同过滤推荐算法
  • 第3章 基于内容的过滤算法
  • 第4章 混合推荐算法
  • 第5章 如何选择推荐算法
  • 第6章 推荐系统和搜索引擎的关系

《架构师特刊:推荐系统(实践篇)》

内容目录:

  • 第1章 微博推荐架构的演进
  • 第2章 Netflix的推荐系统和架构
  • 第3章 博客推荐系统
  • 第4章 Spotify每周歌曲推荐算法解析
  • 第5章 达观个性化推荐系统实践

书籍

《推荐系统实践》

c3c91e060804a11b2177d0ee08ee5c2d96420a28

作者:项亮、陈义

图书简介:本书从数据出发,一步步地介绍在得到什么数据的时候可以设计怎样的推荐系统。面向广大的推荐系统开发人员,以实战为基础,深入浅出地介绍每种推荐方法背后的理论基础,着重讨论每种算法的实现、在实际系统中的效果、方法的优点、缺陷以及解决方法。本书的几位作者是目前国内推荐系统方面做得最好的技术人员。

我们搜索到了两篇关于本书的优秀学习笔记,也放在这里让大家参考:

《推荐系统》

f89eb45611e0e8058f991e9a2c65820fa633e358

作者:Dietmar Jannach, Markus Zanker, Alexander Felfernig, Gerhard Friedrich

关于本书作者,图灵社区做了一次访谈(英文):

知乎问答

优秀博文推荐

阿里云推荐系统(背景资料)

from:https://yq.aliyun.com/articles/54403

浅谈测试代码覆盖率

经常有人问这样的问题:“我们在做单元测试,那测试覆盖率要到多少才行?”。答案其实很简答,“作为指标的测试覆盖率都是没有用处的。”

Martin Fowler(重构那本书的作者)曾经写过一篇博客来讨论这个问题,他指出:把测试覆盖作为质量目标没有任何意义,而我们应该把它作为一种发现未被测试覆盖的代码的手段。

代码覆盖率的意义

Alt text

  1. 分析未覆盖部分的代码,从而反推在前期测试设计是否充分,没有覆盖到的代码是否是测试设计的盲点,为什么没有考虑到?需求/设计不够清晰,测试设计的理解有误,工程方法应用后的造成的策略性放弃等等,之后进行补充测试用例设计。
  2. 检测出程序中的废代码,可以逆向反推在代码设计中思维混乱点,提醒设计/开发人员理清代码逻辑关系,提升代码质量。
  3. 代码覆盖率高不能说明代码质量高,但是反过来看,代码覆盖率低,代码质量不会高到哪里去,可以作为测试自我审视的重要工具之一。

代码覆盖率工具

目前Java常用覆盖率工具Jacoco、Emma和Cobertura

覆盖率工具工作流程

Alt text 1. 对Java字节码进行插桩,On-The-Fly和Offine两种方式。
2. 执行测试用例,收集程序执行轨迹信息,将其dump到内存。
3. 数据处理器结合程序执行轨迹信息和代码结构信息分析生成代码覆盖率报告。
4. 将代码覆盖率报告图形化展示出来,如html、xml等文件格式。

插桩原理

Alt text

主流代码覆盖率工具都采用字节码插桩模式,通过钩子的方式来记录代码执行轨迹信息。其中字节码插桩又分为两种模式On-The-Fly和Offine。 On-The-Fly模式优点在于无需修改源代码,可以在系统不停机的情况下,实时收集代码覆盖率信息。Offine模式优点在于系统启动不需要额外开启 代理,但是只能在系统停机的情况下才能获取代码覆盖率。 基于以上特性,同时由于公司使用JDK8,我们采用Jacoco来获取集成测试代码覆盖率,单元测试使用Cobertura。

On-The-Fly插桩 Java Agent

  • JVM中通过-javaagent参数指定特定的jar文件启动Instrumentation的代理程序
  • 代理程序在每装载一个class文件前判断是否已经转换修改了该文件,如果没有则需要将探针插入class文件中。
  • 代码覆盖率就可以在JVM执行代码的时候实时获取。
  • 典型代表:Jacoco

On-The-Fly插桩 Class Loader

  • 自定义classloader实现自己的类装载策略,在类加载之前将探针插入class文件中
  • 典型代表:Emma

Offine插桩

  • 在测试之前先对文件进行插桩,生成插过桩的class文件或者jar包,执行插过桩的class文件或者jar包之后,会生成覆盖率信息到文件,最后统一对覆盖率信息进行处理,并生成报告。
  • Offline插桩又分为两种:
    • Replace:修改字节码生成新的class文件
    • Inject:在原有字节码文件上进行修改
  • 典型代表:Cobertura

On-The-Fly和Offine比较

  • On-The-Fly模式更加方便的获取代码覆盖率,无需提前进行字节码插桩,可以实时获取代码覆盖率信息
  • Offline模式适用于以下场景:
    • 运行环境不支持java agent
    • 部署环境不允许设置JVM参数
    • 字节码需要被转换成其他虚拟机字节码,如Android Dalvik VM
    • 动态修改字节码过程中和其他agent冲突
    • 无法自定义用户加载类

实践应用

单元测试覆盖率

目前有赞开发人员会写单元测试用例,为了能够引入持续集成,我们选取了Sonar+Cobertura来获取单元测试覆盖率。 我们将代码覆盖率绑定到代码编译阶段,这样每次代码编译就能够执行单元测试同时获取代码单元测试覆盖率

<plugin>  
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>cobertura-maven-plugin</artifactId>
    <version>2.7</version>
    <configuration>
        <formats>
            <format>xml</format>
        </formats>
    </configuration>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>cobertura</goal>
            </goals>
        </execution>
    </executions>
</plugin>  

生成代码覆盖率文件以后,通过Jenkins SonarQube Scanner或者执行mvn sonar:sonar将该文件上传至Sonar 服务器,就可以解析该文件,生成图形化的界面

集成测试覆盖率

测试人员执行集成测试测试用例时(包括手工执行和自动化执行),我们需要代码覆盖率来发现测试用例设计的遗漏,及时补充用例来覆盖未被覆盖到的代码。

被测系统,在服务启动时,都会通过javaagent的方式做On-The-Fly插桩

  • 被测服务器启动之后,测试人员手工执行测试用例,Jacoco Agent会实时将代码覆盖率信息传输给Jacoco Prase Server,该服务器保存了被测代码源文件以及编译后的目标文件,服务器会结合源文件、目标文件以及代码覆盖率信息生成图表化的覆盖率文件。
  • 自动化执行测试用例完成之后,获取代码覆盖率信息,通过Jenkins Jacoco插件解析,获取图表化的覆盖率文件。 获取代码覆盖率报告之后,结合git获取的本次代码变动信息,得到测试用例覆盖的变动文件的测试覆盖率统计信息。来分析是否有由于测试用例设计遗漏导致的 代码没有覆盖或者是开发的无效代码导致该代码无法被覆盖,如果测试用例设计有所遗漏,可以对照的增加相应的用例;如果是无效代码可以删除。

自动化集成流程

Alt text 1. 业务开发完成之后,开发人员做单元测试,单元测试完成之后,保证单元测试全部通过同时单元测试代码覆盖率达到一定程度(这个需要开发和测试约定,理论上越高越好),开发提测。
2. 测试人员根据测试用例进行测试(包括手工测试和自动化测试),结合git获取本次变动代码的覆盖率信息。行覆盖率需达到100%,分支达到50%以上,这个需要具体场景具体分析。
3. 测试通过之后,代码合并至主干,进行自动化回归。
4. 回归测试通过之后,代码可以上线。

基于这套流程,我们可以将单元测试代码覆盖率和集成测试代码覆盖率整合到持续集成流程中,如果代码覆盖率达不到我们设置的某个值时,可以终止流程继续下去获取需要人工确认之后,继续流程。

总结

本文主要介绍了Java代码覆盖率统计原理以及结合有赞测试的工程实践介绍了代码覆盖率该如何应用的实际测试中。不管是白盒测试还是黑盒测试,代码 覆盖率统计都是必不可少的一环,它可以直接反映本次测试的遗漏点(不是100%反映)。结合到自动发布场景也是一个较好地衡量指标。

最后再重申一下本文开篇的观点:

  • 代码覆盖率统计是用来发现没有被测试覆盖的代码
  • 代码覆盖率统计不能完全用来衡量代码质量

from:http://tech.youzan.com/code-coverage/

Ubuntu10下搭建MySQL Proxy读写分离

一、MySQL-Proxy基础

MySQL Proxy是一个处于你的Client端和MySQL server端之间的简单程序,它可以监测、分析或改变它们的通信。它使用灵活,没有限制,常见的用途包括:负载平衡,故障、查询分析,查询过滤和修改等等。

p_1

(Figure1:MySQL Proxy)

MySQL-Proxy, announced in June, is a binary application that sits between your MySQL client and server, and supports the embedded scripting language Lua. The proxy can  be used to analyze, monitor and transform communication, and supports a wide range of scenarios including:

One of the more powerful features of MySQL Proxy is the ability to do “Read/Write Splitting“. The basic concept is to have a master database handle transactional queries while slaves handle SELECT queries. Replication is used to synchronize the changes due to transactional queries with the slaves in the cluster. 

MySQL-Proxy是处在你的MySQL数据库客户和服务端之间的程序,它还支持嵌入性脚本语言Lua。这个代理可以用来分析、监控和变换(transform)通信数据,它支持非常广泛的使用场景:

  • 负载平衡和故障转移处理
  • 查询分析和日志
  • SQL宏(SQL macros)
  • 查询重写(query rewriting)
  • 执行shell命令

MySQL Proxy更强大的一项功能是实现“读写分离(Read/Write Splitting)”。基本的原理是让主数据库处理事务性查询,而从数据库处理SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从数据库。

 

二、实战过程

测试环境:Ubuntu 10.04.2 LTS + MySQL5.1.41-3ubuntu12.10-log

192.168.1.147  proxy 代理 入口

192.168.1.126  master  主机 只写

192.168.1.145  slaver  从机 只读

程序上只需要链接到192.168.1.147,而192.168.1.126和192.168.1.145对于程序来说是透明的,你完全不需要理会,也不需要知道192.168.1.126和192.168.1.145,你对数据库的所有操作都只对192.168.1.147进行操作。

1.     安装脚本lua

#apt-get install lua5.1

MySQL-Proxy的读写分离主要是通过rw-splitting.lua脚本实现的,因此需要安装lua。

2.     安装配置MySQL-Proxy

#apt-get  mysql-proxy

当前获取到的版本是:mysql-proxy 0.8.0(查看版本命令:#mysql-proxy -V)

3.     修改rw-splitting.lua

       #vim /usr/share/mysql-proxy/rw-splitting.lua

配置并使用rw-splitting.lua读写分离脚本,脚本目录是 /usr/share/mysql-proxy,修改读写分离脚本rw-splitting.lua,修改默认连接数,进行快速测试,如果不修改连接数的话要达到连接数为4时才会启用读写分离。

— connection pool

if not proxy.global.config.rwsplit then

proxy.global.config.rwsplit = {

min_idle_connections = 1, //默认为4

max_idle_connections = 1, //默认为8

is_debug = false

}

end

这是因为mysql-proxy会检测客户端连接,当连接没有超过min_idle_connections预设值时, 不会进行读写分离, 即查询操作会发生到Master上。

4.     新建文件夹/var/log/mysql-proxy/和文件mysql-proxy.log

       #mkdir /var/log/mysql-proxy

       #vi mysql-proxy.log

5.     执行读写分离

#sudo mysql-proxy –proxy-read-only-backend-addresses=192.168.1.145:3306 –proxy-backend-addresses=192.168.1.126:3306 –proxy-lua-script=/usr/share/mysql-proxy/rw-splitting.lua >/var/log/mysql-proxy/mysql-proxy.log &

参数说明:

192.168.1.147  proxy 代理 入口

192.168.1.126  master  主机 只写

192.168.1.145  slaver  从机 只读

       当运行sudo mysql-proxy 上面语句后,查询进程没有4040的时候,需要重启mysql ( sudo /etc/init.d/mysql restart) 之后再输入proxy设置。

6.     查看进程端口

#netstat -ant

#netstat –ntl

p_2

(Figure2:端口)

tcp        0      0 0.0.0.0:4040            0.0.0.0:*               LISTEN    

tcp        0      0 0.0.0.0:4041            0.0.0.0:*               LISTEN    

7.     查看数据库链接

mysql> show processlist\G;

p_3

(Figure3:进程)

可以看到,产生了一个新连接。如果想杀掉某个链接,可以使用mysql>help kill查看kill的帮助信息,杀掉36进程的命令:mysql>kill 36;

8.     测试读写分离

1)     在mysql-proxy机子进入MySQL

#mysql -u gaizai -p -P4040 -h 192.168.1.147

必须指定-h参数,不然报下面错误:

p_4

(Figure4:出错)

2)     显示数据库列表:

mysql> show databases;

如果你是搭建MySQL-Proxy成功的话,你上面查看到的数据库列表应该是192.168.1.145服务器上的数据库列表。(可以在145和126分别创建不同的数据库进行测试)

3)     进入测试数据库:

mysql> use weibo;

4)     查询表记录:

mysql>select * from blog;

5)     插入一条记录:

mysql> INSERT INTO `blog` (`TaskID`, `Content`, `Quote`, `Author`, `Time`, `Url`, `ImageUrl`, `Transmits`, `Comments`, `Hash`, `AddOn`) VALUES(’10’,’fefef’,’fefef’,’efef’,NOW(),’http://www.cnblogs.com/zgx/archive/2011/09/13/2174823.html’,NULL,’0′,’0′,’33333333′,NOW());

6)     查询表记录:

mysql>select * from blog;

对比两次查询表的记录,看记录是否有变化,我们插入了数据(确认插入成功),但两次的数据是没有变化的,这就对了,这就是读写分离了(我们读的是145的数据库,插入的是126的数据库,而我们的145与126又没有设置Replication;如果之前设置了,请先停止后进行测试)

注:有时候mysql_proxy(38)库里会显示出数据,重启系统系统,重新启动mysql后就没有此现象了。

7)     进入主写服务器(192.168.1.126) 查看数据

#mysql -u gaizai -p -h 192.168.1.126

mysql> use weibo;

mysql>select * from blog;

可以查看已经写入了一条记录。

8)     进入从读服务器(192.168.1.145)

#mysql -u gaizai -p -h 192.168.1.145

mysql> use weibo;

mysql>select * from blog;

因为没有数据显示,说明只能读,不能写。

在使用工具SQLyog执行查询时,在Proxy服务器上会自动显示下面的信息:

 p_5

(Figure5:信息)

9.     MySQL-Proxy+Replication

上面的测试只是测试了插入数据后,在没有进行Master与Slave的Replication设置的情况下,读取Master与Slave的数据是不同,如果想达到Figure1的效果,我们还需要设置Master与Slave之间的数据复制(Replication),详情请参考:Ubuntu10下MySQL搭建Master Slave

三、MySQL-Proxy命令

帮助命令:$mysql-proxy –help-all

查看下MySQL Proxy的版本:$ mysql-proxy -V 

编译启动脚本:$vi /etc/init.d/mysql-proxy

启动命令:$ /etc/init.d/mysql-proxy start

停止命令:$ /etc/init.d/mysql-proxy stop

重启命令:$ /etc/init.d/mysql-proxy restart

 

四、注意事项

1.      在启动mysql-proxy的时候,可以把启动命令保存为文件:

建议使用配置文件的形式启动, 注意配置文件必须是660权限, 否则无法启动. 如果有多个Slave的话, proxy-read-only-backend-addresses参数可以配置多个以逗号分隔的IP:Port从库列表。

杀掉mysql-proxy进程:# killall mysql-proxy 

新建一个文件:# vi /etc/mysql-proxy.cnf

在文件中输入两个分隔符中间的内容:

——————————————————

[mysql-proxy]

admin-username=viajarchen

admin-password=123123

admin-lua-script = /usr/share/mysql-proxy//admin-sql.lua 

proxy-backend-addresses=192.168.1.126:3306

proxy-read-only-backend-addresses=192.168.1.145:3306

proxy-lua-script=/usr/share/mysql-proxy/rw-splitting.lua

log-file=/var/tmp/mysql-proxy.log

log-level=debug

daemon=true

keepalive=true

max-open-files=1024

——————————————————

设置权限:# chmod 660 /etc/mysql-proxy.cnf

或者#chmod +x /etc/init.d/mysql-proxy

设置启动文件:# mysql-proxy –defaults-file=/etc/mysql-proxy.cnf

查看信息:# ps -ef | grep mysql-proxy | grep -v grep

root      1869     1  0 18:16 ?        00:00:00 /usr/local/mysql-proxy/libexec/mysql-proxy –defaults-file=/etc/mysql-proxy.cnf

root      1870  1869  0 18:16 ?        00:00:00 /usr/local/mysql-proxy/libexec/mysql-proxy –defaults-file=/etc/mysql-proxy.cnf

查看日志:# tail -50f /var/tmp/mysql-proxy.log

2.      mysql-proxy参数

–admin-address=host:port 指定一个mysqo-proxy的管理端口, 缺省是4041;

-P, –proxy-address=<host:port> 是mysql-proxy 服务器端的监听端口, 缺省是4040;

-r, –proxy-read-only-backend-addresses=<host:port> 只读Slave的地址和端口, 缺省为不设置;

-b, –proxy-backend-addresses=<host:port> 远程Master地址和端口, 可设置多个做failover和load balance, 缺省是127.0.0.1:3306;

–defaults-file=<file>配置文件, 可以把mysql-proxy的参数信息置入一个配置文件里;

–daemon mysql-proxy以守护进程方式运行

–keepalive try to restart the proxy if it crashed, 保持连接启动进程会有2个, 一号进程用来监视二号进程, 如果二号进程死掉自动重启proxy。

–log-level=debug定义log日志级别,由高到低分别有

(error|warning|info|message|debug)

–proxy-lua-script=file指定一个Lua脚本程序来控制mysql-proxy的运行和设置,这个脚本在每次新建连接和脚本发生修改的的时候将重新调用。

–max-open-files:指定最大档案开启数为1024,否则会有【could not raise RLIMIT_NOFILE to 8192, Invalid argument (22). Current limit still 1024.】的log讯息出现。

3.      当MySQL主从复制在 show slave status\G 时出现Slave_IO_Running或Slave_SQL_Running 的值不为YES时,,需要首先通过 stop slave 来停止从服务器,然后再进行测试读写分离。

4.      MySQL-Proxy的rw-splitting.lua脚本在网上有很多版本,但是最准确无误的版本仍然是源码包中所附带的lib/rw-splitting.lua脚本,如果有lua脚本编程基础的话,可以在这个脚本的基础上再进行优化;

5.      MySQL-Proxy实际上非常不稳定,在高并发或有错误连接的情况下,进程很容易自动关闭,因此打开–keepalive参数让进程自动恢复是个比较好的办法,但还是不能从根本上解决问题,因此通常最稳妥的做法是在每个从服务器上安装一个MySQL-Proxy供自身使用,虽然比较低效但却能保证稳定性;

6.      一主多从的架构并不是最好的架构,通常比较优的做法是通过程序代码和中间件等方面,来规划,比如单双server-id号分开写入等方式来实现两个或多个主服务器;

7.      MySQL-Cluster 的稳定性也不是太好;

8.      Amoeba for MySQL 是一款优秀的中间件软件,同样可以实现读写分离,负载均衡等功能,并且稳定性要大大超过MySQL-Proxy,建议大家用来替代MySQL-Proxy,甚至MySQL-Cluster。

9.      mysql proxy不支持old_password。另外也可以通过查看密码长度的方式来判断:select length(password) from mysql.user如果长度为16位则是old_password无疑。

10.   安装了mysql-proxy实现读写分离,有master x 1, slave x 2。为了测试failover,停掉了一个slave,然后mysql-proxy会一直报错,提示无法连接。这个情况比单点的mysql还糟糕,挂掉一个就全挂掉!mysql的工程师给提供了一段代码,替换掉:

src/network-mysqld-proxy.c的NETWORK_MYSQLD_PLUGIN_PROTO函数可以解决这个问题。network-mysqld-proxy-function.c文件。

(经过测试:我停止掉slave数据库,proxy的查询就会转移到master上,当把slave启动后,proxy依然在读master,当有新的链接进来的时候才会去读取slave的数据)

11.   如果在mysql-proxy的机器上也安装了mysql的话,新手就会在这个时候混乱了,到底要如何进行测试和链接呢?比如使用命令:#mysql -u gaizai -p -P4040 -h 192.168.1.147是表示登陆本机的4040端口,使用gaizai帐号,这个帐号可以不是本地mysql的帐号,这样就比较容易区分了。

12.   在上述环境中,mysql-proxy、mysql-master、mysql-slave三台服务器均存在单点故障。为了避免mysql-proxy单点隐患有两种方法:一种方法是mysql-proxy配合keepalived做双机,另一种方法是将mysql-proxy和应用服务安装到同一台服务器上;为了避免mysql-master单点故障可以使用DRBD+heartbear做双机;为了避免mysql-slave单点故障可以添加多台mysql-slave,mysql-proxy会自动屏蔽后端发生故障的mysql-slave。

13.   用sysbench (或者super-smack)测试mysql性能:

#sysbench –test=oltp –mysql-table-engine=innodb –oltp-table-size=1000 –mysql-socket=/tmp/mysql.sock –mysql-password=123456 –mysql-user=gaizai –mysql-host=192.168.1.126 –mysql-db=weibo –num-threads=15 prepare

#sysbench –test=oltp –mysql-table-engine=innodb –oltp-table-size=1000 –mysql-socket=/tmp/mysql.sock –mysql-password=123456 –mysql-user=gaizai –mysql-host=192.168.1.126 –mysql-db=weibo –oltp-test-mode=complex run

14.   关于mysql-proxy的启动和关闭的shell脚本的编写:

15.   读写分离不能回避的问题之一就是延迟,可以考虑Google提供的SemiSyncReplicationDesign补丁。

16.   MySQL-Proxy缺省使用的是4040端口,如果你想透明的把3306端口的请求转发给4040的话,那么可以:iptables -t nat -I PREROUTING -s ! 127.0.0.1 -p tcp –dport 3306 -j REDIRECT –to-ports 4040如果想删除这条规则,可以把上面例子中的-I换成-D。参考链接

17.   当使用bigint 时,mysql_insert_id()存在问题,详情见手册,不过对于大多数人而言,bigint基本不会遇到,所以你可以无视这个问题)注:对于这两个问题,官方BUG库里有人给出了相应的补丁

 

五、错误

在执行命令的时候出现了下面的错误:

p_6

(Figure6:错误信息)

could not raise RLIMIT_NOFILE to 8192

这个一个警告级别的错误,意思是MySQL Proxy在你的系统上不能把open files limit提升到8192,不过没关系的,MySQL Proxy依然好好的运行在你的电脑上。

可以通过设置启动–max-open-files参数解决

MySQL Proxy安装和使用(一)

mysql proxy master and slave test

加入–max-open-files=8192后报下面的错误:

p_7

(Figure7:错误信息)

 

六、疑问与解答

1.      当slave宕机后,mysql-proxy是如何读取的?(经过测试:我停止掉slave数据库,proxy的查询就会转移到master上,当把slave启动后,proxy依然在读master,当有新的链接进来的时候才会重新去读取slave的数据。有时可能需要重启下mysql-proxy)

2.      如何知道mysql-proxy当前执行的select是在哪台机器上执行的?

3.      当slave宕机一段时间后,如果再次同步master的缺失的数据?

4.      当配置中设置了proxy-read-only-backend-addresses=192.168.1.145:3306

,192.168.1.147:3306类似这样的两个slave,如果两个slave的数据不同步,那么是怎么读取数据的?# tail -50f /var/tmp/mysql-proxy.log测试

5.      生产环境中除了进行程序调试外,其它不要开启mysql查询日志,因为查询日志记录了客户端的所有语句,频繁的IO操作将会导致mysql整体性能下降。如何设置呢?

6.      mysql-proxy.cnf文件中的管理员帐号和密码有什么用?使用命令进入管理

mysql -u viajarchen -p -P 4041 -h 192.168.1.147 密码是123123

mysql> select * from proxy_connections;

mysql> select * from proxy_config;

p_8

(Figure8:信息)

7.      关于mysql-proxy的启动和关闭的shell脚本的编写?测试

8.      对于/usr/share/mysql-proxy/rw-splitting.lua脚本中的

local min_idle_connections = 4 local max_idle_connections = 8应该如何理解?min的话就是要达到这个值的时候才会读写分离,那么max的是什么意思呢?最大能有8个链接?

9.      mysqld是什么意思?是mysql的守护进程!

10.   HAProxy和keepalived怎么一起搭建使用?能解决什么问题?

 

七、参考文献

ubuntu 9.04 安装mysql-proxy 成功版

ubuntu10.0.4上配置MYSQL主从复制与读写分离(MySQL-Proxy)

[MySQL管理] mysql主从复制,读写分离 (MySQL Proxy)

MySQL Proxy 安装与读写分离体验

MySQL Proxy(官网)

Getting Started with MySQL Proxy(LUA文件介绍)

Read/Write Splitting with MySQL-Proxy(LUA)

MySQL Proxy learns R/W Splitting(牛人)

MySQL-Proxy负载平衡测试遇到的问题及其分析 && MySQL-Proxy工作机制(Lua)

http://www.lua.org

MySQL Proxy(常用命令)

MySQL Proxy 0.8.2 alpha(下载)

MySQL-Haproxy

mysql-proxy读写分离技术文档整理【原创】(sysbench测试)

用sysbench(或者super-smack)测试mysql性能

mysql-proxy读写分离设置(新建启动文件mysql-proxy.cnf +log)

MySQL主从复制(Master-Slave)与读写分离(MySQL-Proxy)实践(主从复制数据+经验分享)

使用MySQL-Proxy读写分离时的注意事项(查询乱码)

MySQL Proxy快速实现读写分离以及负载均衡(启动脚本)

Mysql-proxy主从搭建读写分离全过程(shell脚本启动)

MYSQL-PROXY测试实例(Lua脚本构建自己的轮询连接算法+管理MySQL Proxy )

from:http://www.cnblogs.com/gaizai/archive/2012/11/21/2780816.html

基于 Spark 的文本情感分析

IBM 公司在 2015 年对外宣告了一个新的科技和商务时代的来临—认知时代。这个巨大的转变,来自 IBM 对技术和商业领域的三个重要的洞察力[1]。第一,这个世界被数据所充斥。第二,这个世界通过代码被改造。第三,认知计算的出现。其中,认知计算可以:

  • 通过感知与互动,理解非结构化数据
  • 通过生成假设、评估、辩证、和建议来推理
  • 从专家培训、每一次互动、及持续取得数据中学习。

本文描述了一个基于 Spark 构建的认知系统:文本情感分析系统,分析和理解社交论坛的非结构化文本数据。

基于 Spark 的文本情感分析

文本情感分析是指对具有人为主观情感色彩文本材料进行处理、分析和推理的过程。文本情感分析主要的应用场景是对用户关于某个主题的评论文本进行处理和分析。比如,人们在打算去看一部电影之前,通常会去看豆瓣电影板块上的用户评论,再决定是否去看这部电影。另外一方面,电影制片人会通过对专业论坛上的用户评论进行分析,了解市场对于电影的总体反馈。本文中文本分析的对象为网络短评,为非正式场合的短文本语料,在只考虑正面倾向和负面倾向的情况下,实现文本倾向性的分类。

文本情感分析主要涉及如下四个技术环节。

  1. 收集数据集:本文中,以分析电影《疯狂动物城》的用户评论为例子,采集豆瓣上《疯狂动物城》的用户短评和短评评分作为样本数据,通过样本数据训练分类模型来判断微博上的一段话对该电影的情感倾向。
  2. 设计文本的表示模型:让机器“读懂”文字,是文本情感分析的基础,而这首先要解决的问题是文本的表示模型。通常,文本的表示采用向量空间模型,也就是说采用向量表示文本。向量的特征项是模型中最小的单元,可以是一个文档中的字、词或短语,一个文档的内容可以看成是它的特征项组成的集合,而每一个特征项依据一定的原则都被赋予上权重。
  3. 选择文本的特征:当可以把一个文档映射成向量后,那如何选择特征项和特征值呢?通常的做法是先进行中文分词(­­­­本文使用 jieba 分词工具),把用户评论转化成词语后,可以使用 TF-IDF(Term Frequency–Inverse Document Frequency,词频-逆文档频率)算法来抽取特征,并计算出特征值。
  4. 选择分类模型:常用的分类算法有很多,如:决策树、贝叶斯、人工神经网络、K-近邻、支持向量机等等。在文本分类上使用较多的是贝叶斯和支持向量机。本文中,也以这两种方法来进行模型训练。

为什么采用 Spark

传统的单节点计算已经难以满足用户生成的海量数据的处理和分析的要求。比如,豆瓣网站上《疯狂动物城》电影短评就有 111421 条,如果需要同时处理来自多个大型专业网站上所有电影的影评,单台服务器的计算能力和存储能力都很难满足需求。这个时候需要考虑引入分布式计算的技术,使得计算能力和存储能力能够线性扩展。

Spark 是一个快速的、通用的集群计算平台,也是业内非常流行的开源分布式技术。Spark 围绕着 RDD(Resilient Distributed Dataset)弹性分布式数据集,扩展了广泛使用的 MapReduce[5]计算模型,相比起 Hadoop[6]的 MapReduce 计算框架,Spark 更为高效和灵活。Spark 主要的特点如下:

  1. 内存计算:能够在内存中进行计算,它会优先考虑使用各计算节点的内存作为存储,当内存不足时才会考虑使用磁盘,这样极大的减少了磁盘 I/O,提高了效率。
  2. 惰性求值:RDD 丰富的计算操作可以分为两类,转化操作和行动操作。而当程序调用 RDD 的转化操作(如数据的读取、Map、Filter)的时候,Spark 并不会立刻开始计算,而是记下所需要执行的操作,尽可能的将一些转化操作合并,来减少计算数据的步骤,只有在调用行动操作(如获取数据的行数 Count)的时候才会开始读入数据,进行转化操作、行动操作,得到结果。
  3. 接口丰富:Spark 提供 Scala,Java,Python,R 四种编程语言接口,可以满足不同技术背景的工程人员的需求。并且还能和其他大数据工具密切配合。例如 Spark 可以运行在 Hadoop 之上,能够访问所有支持 Hadoop 的数据源(如 HDFS、Cassandra、Hbase)。

本文以 Spark 的 Python 接口为例,介绍如何构建一个文本情感分析系统。作者采用 Python 3.5.0,Spark1.6.1 作为开发环境,使用 Jupyter Notebook[7]编写代码。Jupyter Notebook 是由 IPython Notebook 演化而来,是一套基于 Web 的交互环境,允许大家将代码、代码执行、数学函数、富文档、绘图以及其它元素整合为单一文件。在运行 pyspark 的之前,需要指定一下 pyspark 的运行环境,如下所示:

清单 1. 指定 pyspark 的 ipython notebook 运行环境
export PYSPARK_PYTHON=ipython3 PYSPARK_DRIVER_PYTHON_OPTS="notebook"

接下里就可以在 Jupyter Notebook 里编写代码了。


基于 Spark 如何构建文本情感分析系统

在本文第 1 章,介绍了文本情感分析主要涉及的四个技术环节。基于 Spark 构建的文本分类系统的技术流程也是这样的。在大规模的文本数据的情况下,有所不同的是文本的特征维度一般都是非常巨大的。试想一下所有的中文字、词有多少,再算上其他的语言和所有能在互联网上找到的文本,那么文本数据按照词的维度就能轻松的超过数十万、数百万维,所以需要寻找一种可以处理极大维度文本数据的方法。

在本文后续章节中,将依次按照基于 Spark 做数据预处理、文本建模、特征提取、训练分类模型、实现待输入文本分类展开讨论。系统的上下文关系图如图 1 所示,系统的功能架构图如图 2 所示。

图 1. 基于 Spark 文本情感分析系统上下文

img001

图 2. 基于 Spark 文本情感分析系统功能架构图

img002

爬取的数据说明

为了说明文本分类系统的构建过程,作者爬取了豆瓣网络上《疯狂动物城》的短评和评分(https://movie.douban.com/subject/25662329/comments)。示例数据如下所示:

表 1. 示例数据
评分 评论文本
5 做冰棍那机智的不像话!!!全片最爱!!!想吃!!!
5 绝对的好片子裂墙推荐。实在是因为另一场满了…随手挑了这个片子。真是 5 分钟一小笑 10 分钟哄堂大笑。看那个又懒又慢树獭简直要锤墙了。旁边法国妹子精辟的吐槽!看!这是我们法国人。我要憋到内伤了。最后散场大家都静坐着等着整首歌放完…五星好评。2016 年度十佳。
5 不要看任何影评,如果可以预告片都别看,直接买票就好了。你要啥这电影里有啥!
3 最精彩的动画是用想象力拍出真实世界难以实现的故事,而不是用动物化填充一段如果是真人就普通到不能再普通的烂俗故事。笑料有,萌趣有,但更有的是莫名其妙的主旋律和政治正确,恐怕没有评分所体现的那么出色。
4 换了新领导就是不一样。迪士尼暗黑大电影,洛杉矶罪案片风格和内核。还真是动物乌托邦,美国针对有色人种,欧洲针对难民,天朝针对公知和五毛吗?人设精彩,细节丰富,但要说创意超《头脑特工队》显然就不实事求是了。
…… ………………

表格中每一行为一条评论数据,按照“评分,评论文本”排放,中间以制表符切分,评分范围从 1 分到 5 分,这样的数据共采集了 116567 条。

数据预处理

这一节本文是要说明用 Spark 是如何做数据清洗和抽取的。在该子系统中输入为爬虫的数据,输出为包含相同数量好评和坏评的 Saprk 弹性分布式数据集。

Spark 数据处理主要是围绕 RDD(Resilient Distributed Datasets) 弹性分布式数据集对象展开,本文首先将爬虫数据载入到 Spark 系统,抽象成为一个 RDD。可以用 distinct 方法对数据去重。数据转换主要是用了 map 方法,它接受传入的一个数据转换的方法来按行执行方法,从而达到转换的操作它只需要用一个函数将输入和输出映射好,那么就能完成转换。数据过滤使用 filter 方法,它能够保留判断条件为真的数据。可以用下面这个语句,将每一行文本变成一个 list,并且只保留长度为 2 的数据。

清单 2. Spark 做数据预处理
originData=sc.textFile('YOUR_FILE_PATH')
originDistinctData=originData.distinct()
rateDocument=originDistinctData.map(lambda line : line.split('\t')).\
filter(lambda line : len(line)==2)
清单 3. 统计数据基本信息
fiveRateDocument=rateDocument.filter(lambda line : int(line[0])==5)
fiveRateDocument.count()

本文得到,五分的数据有 30447 条,4 分、3 分、2 分、1 分的数据分别有 11711 条,123 条,70 条。打五分的毫无疑问是好评;考虑到不同人对于评分的不同偏好,对于打四分的数据,本文无法得知它是好评还是坏评;对于打三分及三分以下的是坏评。

下面就可以将带有评分数据转化成为好评数据和坏评数据,为了提高计算效率,本文将其重新分区。

清单 4. 合并负样本数据
negRateDocument=oneRateDocument.union(twoRateDocument).\
union(threeRateDocument)
negRateDocument.repartition(1)

通过计算得到,好评和坏评分别有 30447 条和 2238 条,属于非平衡样本的机器模型训练。本文只取部分好评数据,好评和坏评的数量一样,这样训练的正负样本就是均衡的。最后把正负样本放在一起,并把分类标签和文本分开,形成训练数据集

清单 5. 生̧成训练数̧据集
posRateDocument=sc.parallelize(fiveRateDocument.take(negRateDocument.count())).repartition(1)
allRateDocument=negRateDocument.union(posRateDocument)
allRateDocument.repartition(1)
rate=allRateDocument.map(lambda s : ReduceRate(s[0]))
document=allRateDocument.map(lambda s: s[1])

文本的向量表示和文本特征提取

这一节中,本文主要介绍如何做文本分词,如何用 TF-IDF 算法抽取文本特征。将输入的文本数据转化为向量,让计算能够“读懂”文本。

解决文本分类问题,最重要的就是要让文本可计算,用合适的方式来表示文本,其中的核心就是找到文本的特征和特征值。相比起英文,中文多了一个分词的过程。本文首先用 jieba 分词器将文本分词,这样每个词都可以作为文本的一个特征。jieba 分词器有三种模式的分词:

  1. 精确模式,试图将句子最精确地切开,适合文本分析;
  2. 全模式,把句子中所有的可以成词的词语都扫描出来, 速度非常快,但是不能解决歧义;
  3. 搜索引擎模式,在精确模式的基础上,对长词再次切分,提高召回率,适合用于搜索引擎分词。

这里本文用的是搜索引擎模式将每一句评论转化为词。

清单 6. 分词
words=document.map(lambda w:"/".\
join(jieba.cut_for_search(w))).\
map(lambda line: line.split("/"))

出于对大规模数据计算需求的考虑,spark 的词频计算是用特征哈希(HashingTF)来计算的。特征哈希是一种处理高维数据的技术,经常应用在文本和分类数据集上。普通的 k 分之一特征编码需要在一个向量中维护可能的特征值及其到下标的映射,而每次构建这个映射的过程本身就需要对数据集进行一次遍历。这并不适合上千万甚至更多维度的特征处理。

特征哈希是通过哈希方程对特征赋予向量下标的,所以在不同情况下,同样的特征就是能够得到相同的向量下标,这样就不需要维护一个特征值及其下表的向量。

要使用特征哈希来处理文本,需要先实例化一个 HashingTF 对象,将词转化为词频,为了高效计算,本文将后面会重复使用的词频缓存。

清单 7. 训练词频矩阵
hashingTF = HashingTF()
tf = hashingTF.transform(words)
tf.cache()

缺省情况下,实例化的 HashingTF 特征维数 numFeatures 取了 220次方维,在 spark 的源码中可以看到,HashingTF 的过程就是对每一个词作了一次哈希并对特征维数取余得到该词的位置,然后按照该词出现的次数计次。所以就不用像传统方法一样每次维护一张词表,运用 HashingTF 就可以方便的得到该词所对应向量元素的位置。当然这样做的代价就是向量维数会非常大,好在 spark 可以支持稀疏向量,所以计算开销并不大。

图 3. HashingTF 源码

img003

词频是一种抽取特征的方法,但是它还有很多问题,比如在这句话中“这几天的天气真好,项目组的老师打算组织大家一起去春游。“的”相比于“项目组”更容易出现在人们的语言中,“的”和“项目组”同样只出现一次,但是项目组对于这句话来说更重要。

本文采用 TF-IDF 作为特征提取的方法,它的权重与特征项在文档中出现的评率成正相关,与在整个语料中出现该特征项的文档成反相关。下面依据 tf 来计算逆词频 idf,并计算出 TF-IDF

清单 8. 计算 TF-IDF 矩阵
idfModel = IDF().fit(tf)
tfidf = idfModel.transform(tf)

至此,本文就抽取出了文本的特征,并用向量去表示了文本。

训练分类模型

在这一小节中,本文介绍如何用 Spark 训练朴素贝叶斯分类模型,这一流程的输入是文本的特征向量及已经标记好的分类标签。在这里本文得到的是分类模型及文本分类的正确率。

现在,有了文本的特征项及特征值,也有了分类标签,需要用 RDD 的 zip 算子将这两部分数据连接起来,并将其转化为分类模型里的 LabeledPoint 类型。并随机将数据分为训练集和测试集,60%作为训练集,40%作为测试集。

清单 9. 生成训练集和测试集
zipped=rate.zip(tfidf)
data=zipped.map(lambda line:LabeledPoint(line[0],line[1]))
training, test = data.randomSplit([0.6, 0.4], seed = 0)

本文用训练数据来训练贝叶斯模型,得到 NBmodel 模型来预测测试集的文本特征向量,并且计算出各个模型的正确率,这个模型的正确率为 74.83%。

清单 10. 训练贝叶斯分类模型
NBmodel = NaiveBayes.train(training, 1.0)
predictionAndLabel = test.map(lambda p : (NBmodel.predict(p.features), p.label))
accuracy = 1.0 * predictionAndLabel.filter(lambda x: 1.0 \
if x[0] == x[1] else 0.0).count() / test.count()

可以看出贝叶斯模型最后的预测模型并不高,但是基于本文采集的数据资源有限,特征提取过程比较简单直接。所以还有很大的优化空间,在第四章中,本文将介绍提高正确率的方法。

分类未标记文档

现在可以用本文训练好的模型来对未标记文本分类,流程是获取用户输入的评论,然后将输入的评论文本分词并转化成 tf-idf 特征向量,然后用 3.4 节中训练好的分类模型来分类。

清单 11. 分类未分类文本
 yourDocument=input("输入待分类的评论:")
 yourwords="/".join(jieba.cut_for_search(yourDocument)).split("/")
yourtf = hashingTF.transform(yourwords)
yourtfidf=idfModel.transform(yourtf)
print('NaiveBayes Model Predict:',NBmodel.predict(yourtfidf),'

当程序输入待分类的评论:“这部电影没有意思,剧情老套,真没劲, 后悔来看了”

程序输出为“NaiveBayes Model Predict: 0.0”。

当程序输入待分类的评论:“太精彩了讲了一个关于梦想的故事剧情很反转制作也很精良”

程序输出为“NaiveBayes Model Predict: 1.0”。

至此,最为简单的文本情感分类系统就构建完整了。


提高正确率的方法

在第三章中,本文介绍了构建文本分类系统的方法,但是正确率只有 74.83%,在这一章中,本文将讲述文本分类正确率低的原因及改进方法。

文本分类正确率低的原因主要有:

  1. 文本预处理比较粗糙,可以进一步处理,比如去掉停用词,去掉低频词;
  2. 特征词抽取信息太少,搜索引擎模式的分词模式不如全分词模式提供的特征项多;
  3. 朴素贝叶斯模型比较简单,可以用其他更为先进的模型算法,如 SVM;
  4. 数据资源太少,本文只能利用了好评、坏评论各 2238 条。数据量太少,由于爬虫爬取的数据,没有进行人工的进一步的筛选,数据质量也得不到 100%的保证。

下面分别就这四个方面,本文进一步深入的进行处理,对模型进行优化。

数据预处理中去掉停用词

停用词是指出现在所有文档中很多次的常用词,比如“的”、“了”、“是”等,可以在提取特征的时候将这些噪声去掉。

首先需要统计一下词频,看哪些词是使用最多的,然后定义一个停用词表,在构建向量前,将这些词去掉。本文先进行词频统计,查看最常用的词是哪些。

清单 12. 统计词频
text=words.flatMap(lambda w:w)
wordCounts = text.map(lambda word: (word, 1))\
.reduceByKey(lambda a, b: a+b).\
sortBy(lambda x: x[1],ascending=False)
wordCounts.take(10)

通过观察,选择出现次数比较多,但是对于文本情感表达没有意义的词,作为停用词,构建停用词表。然后定义一个过滤函数,如果该词在停用词表中那么需要将这个词过滤掉。

清单 13. 去掉停用词

stopwords = set([" ","","","","","",……])

def filterStopWords(line):
 for i in line:
 if i in stopwords:
 line.remove(i)
return line
words=words.map(lambda w : filterStopWords(w))

尝试不用的分词模式

本文在分词的时候使用的搜索引擎分词模式,在这种模式下只抽取了重要的关键字,可能忽略了一些可能的特征词。可以把分词模式切换到全分词模式,尽可能的不漏掉特征词,同样的模型训练,正确率会有 1%~2%的提升。

清单 14. 全分词模式分词
words=document.map(lambda w:"/".join(jieba.\
cut(w, cut_all=True))).\
map(lambda line: line.split("/"))

更换训练模型方法

在不进行深入优化的情况下,SVM 往往有着比其他分类模型更好的分类效果。下面在相同的条件下,运用 SVM 模型训练,最后得到的正确率有 78.59%。

清单 15. 用支持向量机训练分类模型
SVMmodel = SVMWithSGD.train(training, iterations=100)
predictionAndLabel = test.map(lambda p : (SVMmodel.predict(p.features), p.label))
accuracy = 1.0 * predictionAndLabel.filter(lambda x: 1.0 if x[0] == x[1] else 0.0).count() / test.count()

训练数据的问题

本文只是为了演示如何构建这套系统,所以爬取的数据量并不多,获取的文本数据也没有人工的进一步核对其正确性。如果本文能够有更丰富且权威的数据源,那么模型的正确率将会有较大的提高。

作者对中国科学院大学的谭松波教授发布的酒店产品评论文本做了分类系统测试,该数据集是多数学者公认并且使用的。用 SVM 训练的模型正确率有 87.59%。


总结

本文向读者详细的介绍了利用 Spark 构建文本情感分类系统的过程,从数据的清洗、转换,Spark 的 RDD 有 Filter、Map 方法可以轻松胜任;对于抽取文本特征,Spark 针对大规模数据的处理不仅在计算模型上有优化,还做了算法的优化,它利用哈希特征算法来实现 TF-IDF,从而能够支持上千万维的模型训练;对于选择分类模型,Spark 也实现好了常用的分类模型,调用起来非常方便。最后希望这篇文章可以对大家学习 spark 和文本分类有帮助

参考资料

学习

from:http://www.ibm.com/developerworks/cn/cognitive/library/cc-1606-spark-seniment-analysis/index.html

什么是认知物联网?

简单地说,认知物联网是将认知计算技术与互连设备产生的数据和这些设备可以执行的操作结合使用。您可能已经知道物联网,也知道我们所说的传感器和执行器的意思。从认知计算方面讲,物联网又是什么意思呢?当然,认知意味着思考,而计算机不具备普通人类的思考能力,它们现在可以执行一些人类认为是思考 的基本功能。认知涉及三个关键要素:

  • 理解
  • 推理
  • 学习

在计算机中,系统理解 意味着,能够读入大量的结构化和非结构化数据,并从中获取其意义,也就是说,建立一个概念、实体和关系的模型。推理 意味着,使用这个模型能够得出答案或解决相关问题,无需专门对答案和解决方案进行编程。而学习 意味着,能够自动地从数据推断出新的知识,这是大规模理解的一个关键组成部分。

cognitive-iot-blog

构建大规模的概念和关系的复杂模型过于费时,且成本高昂。此外,有许多关系是事先不知道或不明确的,所以只能让机器自动分析大数据集来发现模式,然后才能真正发现这些关系。

会思考的物体

认知计算对于物联网非常重要,这有几个关键原因。

  • 生成数据的速率和规模:学习有助于优化流程或系统,在结合有关系统的传感器数据与其他上下文信息的基础上,使其更加高效。从设备生成的数据快速超越了人类通过分析去发现重要模式和学习的能力。应用机器学习对于能够扩展物联网是必不可少的。
  • 计算转移到物理世界:随着越来越多各种年龄和技术技能水平的人在与物联网系统进行交互,我们需要超越当前的机器接口范式,这种范式要求人类学会与机器交互所需的抽象和专用接口。此外,这种转移需要走向更加以人类为中心的接口。换句话说,人们需要能够用自然语言与物联网系统(物体)进行交互。该系统必须开始理解人类。来自麻省理工媒体实验室 (MIT Media Lab) 的作者 David Rose 提出了术语 “魔法对象 (enchanted objects) ” 来描述看似智能的行为,我们可以通过物联网和认知计算将这些行为注入连接的设备。
  • 多种数据源和数据类型的集成:在物联网中,存在许多数据源,可以提供相关的信息或上下文,有助于更好地理解和制定决策。数据有多种不同的类型,包括数字传感器数据、音频、视频、非结构化的文本数据、位置数据等,消化和分析这些数据类型并通过这些数据类型识别相关性和模式的能力,是一项非常强大的功能。通过掌握上下文可以大大提高对人类操作者的意图的理解,这包括物理环境、时间维度,甚至是情绪状况。通过集成多个不同的数据源可以完善推理和决策,例如,关联传感器数据与声学数据。

人类感知设备

认知物联网 是下一次飞跃,它通过学习并将更多的人类意识注入到与我们交互的设备和环境中,提高传感器驱动的复杂系统的准确性和效率。这一飞跃可以让我们的物体 用我们的语言(而不是其他方式)来理解我们,并与我们进行交互。

参考资料

from:http://www.ibm.com/developerworks/cn/cognitive/blog/what-cognitive-iot/index.html