基于用户标签的推荐系统
拿到了用户标签行为数据,相信大家都可以想到一个最简单的个性化推荐算法。这个算法的描述如下所示:
1)统计每个用户最常用的标签。
2)对于每个标签,统计被打过这个标签次数最多的物品。
3)对于一个用户,首先找到他常用的标签,然后找到具有这些标签的最热门物品推荐给这个用户
未完待续
一个程序员的喃喃自语
拿到了用户标签行为数据,相信大家都可以想到一个最简单的个性化推荐算法。这个算法的描述如下所示:
1)统计每个用户最常用的标签。
2)对于每个标签,统计被打过这个标签次数最多的物品。
3)对于一个用户,首先找到他常用的标签,然后找到具有这些标签的最热门物品推荐给这个用户
未完待续
自己构造json对象,一定要先把字符串变为对象,再把json对象toString拼接,要注意这两个字符串的区别: appid81DBCD4FCxxWD8E8AD7101A155D4BDD7create_user1345form{"标题":"上线单19","num":"1"}order_id1 appid81DBCD4FCxxWD8E8AD7101A155D4BDD7create_user1345form{\"标题\":\"上线单19\",\"num\":\"1\"}order_id1 JSONObject jo = JSONObject.fromObject("{\"标题\":\"上线单19\",\"num\":\"1\"}"); System.out.println("appid81DBCD4FCxxWD8E8AD7101A155D4BDD7create_user1345form"+jo.toString()+"order_id1"); //md5方法,一定要用apache提供的公共开发类,千万不要自己随便从网上瞎找!!! System.out.println(DigestUtils.md5Hex("appid81DBCD4FCxxWD8E8AD7101A155D4BDD7create_user1345form"+jo.toString()+"order_id1")); //下边就是从网上瞎找的,没有用的 System.out.println(MD5Util.md5("appid81DBCD4FCxxWD8E8AD7101A155D4BDD7create_user1345form"+jo.toString()+"order_id1"));
\n是换行,英文是New line,表示使光标到行首
\r是回车,英文是Carriage return,表示使光标下移一格
\r\n表示回车换行
linux,unix: \r\n
windows : \n
Mac OS : \r
基本格式 :
* * * * * command
分 时 日 月 周 命令
第1列表示分钟1~59 每分钟用*或者 */1表示
第2列表示小时1~23(0表示0点)
第3列表示日期1~31
第4列表示月份1~12
第5列标识号星期0~6(0表示星期天)
第6列要运行的命令
xml代码:
<select id="findMenuListByRole" resultType="java.util.Map" parameterType="java.util.List"> select r.`name` as roleName,GROUP_CONCAT(distinct(m.`name`) SEPARATOR ' | ') as menuList from sys_role_menu as rm LEFT JOIN sys_role as r on rm.role_id=r.id LEFT JOIN sys_menu as m on rm.menu_id=m.id where m.name not like '功能菜单' and r.id in <foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach> GROUP BY r.`name` </select>
java代码:
public List<Map<String, String>> findMenuListByRole(List roleIDList);
需要注意的点:
1、resultType=”java.util.Map” 返回值类型
2、parameterType=”java.util.List” 输入的参数
3、将group的值拼接起来 GROUP_CONCAT(distinct(m.`name`) SEPARATOR ‘ | ‘) ;GROUP_CONCAT 有长度限制,group_concat_max_len
4、in的用法
<foreach item="item" index="index" collection="list" open="(" separator="," close=")"> #{item} </foreach>
5、java代码是要注意
List<Map<String, String>>
而不单单是map
6、#相当于对数据 加上 双引号,$相当于直接显示数据
新建一个maven简单工程即可,该工程的目的是将es、log4j等jar包里的class文件重新打包,全部放入到一个jar包里,再放入的过程中将所有“org.apache.logging.log4j”开头的报名改为“my.elasticsearch.log4j”,也就相当于将import log4j的地方统统改了,这样就相当于第三方编写的log4j,pom.xml如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>my.elasticsearch.test</groupId> <artifactId>es-shaded</artifactId> <version>1.0-SNAPSHOT</version> <properties> <elasticsearch.version>5.2.2</elasticsearch.version> </properties> <dependencies> <dependency> <groupId>org.elasticsearch</groupId> <artifactId>elasticsearch</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.elasticsearch.client</groupId> <artifactId>transport</artifactId> <version>${elasticsearch.version}</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.7</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>log4j-over-slf4j</artifactId> <version>1.7.7</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>2.4.1</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <relocations> <relocation> <pattern>org.apache.logging.log4j</pattern> <shadedPattern>my.elasticsearch.log4j</shadedPattern> </relocation> </relocations> <transformers> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer" /> </transformers> </configuration> </execution> </executions> </plugin> </plugins> </build> </project>
运行mvn clean install
将打包好的jar包安装到本地,验证效果如下图:
#相当于对数据 加上 双引号,$相当于直接显示数据
1. #将传入的数据都当成一个字符串,会对自动传入的数据加一个双引号。如:order by #user_id#,如果传入的值是111,那么解析成sql时的值为order by “111”, 如果传入的值是id,则解析成的sql为order by “id”.
2. $将传入的数据直接显示生成在sql中。如:order by $user_id$,如果传入的值是111,那么解析成sql时的值为order by user_id, 如果传入的值是id,则解析成的sql为order by id.
3. #方式能够很大程度防止sql注入。
4.$方式无法防止Sql注入。
5.$方式一般用于传入数据库对象,例如传入表名.
6.一般能用#的就别用$.
MyBatis排序时使用order by 动态参数时需要注意,用$而不是#
字符串替换
默认情况下,使用#{}格式的语法会导致MyBatis创建预处理语句属性并以它为背景设置安全的值(比如?)。这样做很安全,很迅速也是首选做法,有时你只是想直接在SQL语句中插入一个不改变的字符串。比如,像ORDER BY,你可以这样来使用:
ORDER BY ${columnName}
这里MyBatis不会修改或转义字符串。
重要:接受从用户输出的内容并提供给语句中不变的字符串,这样做是不安全的。这会导致潜在的SQL注入攻击,因此你不应该允许用户输入这些字段,或者通常自行转义并检查。
hadoop distcp -D ipc.client.fallback-to-simple-auth-allowed=true -log /temp/tianhailong/ webhdfs://10.11.4.240:50070/test/tianhl webhdfs://10.11.1.10/user/hive
遇到的坑:
1、数据所在的集群所有机器,需要配置同步集群的hosts。
2、带有Kerberos安全认证,需要加参数。-D ipc.client.fallback-to-simple-auth-allowed=true
3、 注意运行日志,需要写入有权限的文件夹。 -log /temp/tianhailong/
4、被写入数据的集群是hive用户写入的,需要找一个hive可以写入的权限的文件夹存放数据。/user/hive
参数说明:
-m <num_maps> | 同时拷贝的最大数目 | 指定了拷贝数据时map的数目。请注意并不是map数越多吞吐量越大。 |
参考网址:
https://community.hortonworks.com/questions/294/running-distcp-between-two-cluster-one-kerberized.html
http://stardust.wang/?p=331
维度表示你要对数据进行分析时所用的一个量, 比如你要分析产品销售情况, 你可以选择按类别来进行分析,或按区域来分析. 这样的按..分析就构成一个维度。前面的示例就可以有两个维度:类型和区域。另外每个维度还可以有子维度(称为属性),例如类别可以有子类型,产品名等属性。
下面是两个常见的维度表结构:
产品维度表:Prod_id, Product_Name, Category, Color, Size, Price
时间维度表:TimeKey, Season, Year, Month, Date
而事实表是数据聚合后依据某个维度生成的结果表。它的结构示例如下:
销售事实表:Prod_id(引用产品维度表), TimeKey(引用时间维度表), SalesAmount(销售总量,以货币计), Unit(销售量)
上面的这些表就是存在于数据仓库中的。从这里可以看出它有几个特点:
1. 维度表的冗余很大,主要是因为维度一般不大(相对于事实表来说的),而维度表的冗余可以使事实表节省很多空间。
2. 事实表一般都很大,如果以普通方式查询的话,得到结果一般发的时间都不是我们可以接受的。所以它一般要进行一些特殊处理。如SQL Server 2005就会对事实表进行如预生成处理等。
3. 维度表的主键一般都取整型值的标志列类型,这样也是为了节省事实表的存储空间。
事实表和维度表的分界线
事实表是用来存储主题的主干内容的。以日常的工作量为例,工作量可能具有如下属性:工作日期,人员,上班时长,加班时长,工作性质,是否外勤,工作内容,审核人。那么什么才是主干内容?很容易看出上班时长,加班时长是主干,也就是工作量主题的基本内容,那么工作日期,人员,工作性质,是否外勤,工作内容是否为主干信息呢?认真分析特征会发现,日期,人员,性质,是否外勤都是可以被分类的,例如日期有年-月-日的层次,人员也有上下级关系,外勤和正常上班也是两类上班考勤记录,而上班时长和加班时长则不具有此类意义。所以一般把能够分类的属性单独列出来,成为维度表,在事实表中维护事实与维度的引用关系。
在上述例子中,事实表可以设计成如下
WorkDate EmployeeID,WorkTypeID,Islegwork,Content,
而时间,员工,工作类型,是否外勤则归为维度表。
总的来看,和其他建立主外键关系的表也都一样。但是维度表的建立是需要有层次的(虽然不是必须,但是也是典型特征),而事实表的建立是针对已经发生的事实的,是历史数据的存档,也就是说是不应该修改的。以测试部测试软件的Bug为例。每个Bug都是一个事实。这个Bug的状态在数据字典里可能设计成新建,转派,修复,拒绝等等。那么在事实表中Bug表中有一个字段为Status。当测试员或者开发人员改变了这个状态的值,事实表中该如何更新呢?是直接更新Status还是什么其他的方式?显然,为了能够追踪这个Bug的历史信息,应该是重新插入一条新的记录。那么这和以往的数据库设计有什么区别呢?可以看出对于原始记录和新插入的记录,其他字段全部是相同的,也就是全部冗余的。如果以BugID作为主键,这时候会发现主键都是冗余的(当然,插入之前只能删除主键)。所以可以看出,事实表一般是没有主键的。数据的质量完全由业务系统来把握。
总的说来,事实表的设计是以能够正确记录历史信息为准则,维度表的设计是以能够以合适的角度来聚合主题内容为准则。
维是分析问题的角度,每一维代表一个统一的访问数据仓库中信息的路径。
在实际问题中,有些维包含多个层次。
事实是各个维度的交点,是对某个特定事件的度量,只有当特定维值的组合没有造成空穴时,一个事实才会存在。事实的数量属性称为度量。
事实数据和维度数据的识别必须依据具体的主题问题而定。“事实表”,用来存储事实的度量(measure)及指向各个维的外键值。维表用来保存该维的元数据,即维的描述信息,包括维的层次及成员类别等
大量的嵌套条件分支是很容易让人望而却步的代码,我们应该极力避免这种代码的出现。尽管结构化原则一直在说一个函数只能有一个出口,但是在大量的嵌套条件分支下,让我们忘了这所谓的规则吧。 有一个专业名词叫卫语句,可以治疗这种恐怖的嵌套条件语句。它的核心思想是,将不满足某些条件的情况放在方法前面,并及时跳出方法,以免对后面的判断造成影响,经过这项手术的代码看起来会非常的清晰。
1.使用卫语句取代嵌套表达式
2.卫语句就是把复杂的条件表达式拆分成多个条件表达式,比如一个很复杂的表达式,嵌套了好几层的if – then-else语句,转换为多个if语句,实现它的逻辑,这多条的if语句就是卫语句.
3有时候条件式可能出现在嵌套n次才能真正执行,其他分支只是简单报错返回的情况,对于这种情况,应该单独检查报错返回的分支,当条件为真时立即返回,这样的单独检查就是卫语句(guard clauses).卫语句可以把我们的视线从异常处理中解放出来,集中精力到正常处理的代码中。