转载自:https://www.douban.com/note/204399134/

推荐数据的处理是大规模的,在集群环境下一次要处理的数据可能是数GB,所以Mahout针对推荐数据进行了优化。

Preference

在Mahout中,用户的喜好被抽象为一个Preference,包含了userId,itemId和偏好值(user对item的偏好)。Preference是一个接口,它有一个通用的实现是GenericPreference。

Preference

但因为用户的喜好数据是大规模的,我们通常会选择把它放入集合或者数组。但是因为Java的对象的内存消耗机制,在大数据量下使用Collection<Preference>和Preference[]是非常低效的。为什么呢?

在Java中,一个对象占用的字节数 = 基本的8字节 + 基本数据类型所占的字节 + 对象引用所占的字节

(1)先说这基本的8字节

在JVM中,每个对象(数组除外)都有一个头,这个头有两个字,第一个字存储对象的一些标志位信息,如:锁标志位、经历了几次gc等信息;第二个字节是一个引用,指向这个类的信息。JVM为这两个字留了8个字节的空间。 这样一来的话,new Object()就占用了8个字节,那怕它是个空对象

(2) 基本类型所占用的字节数

byte/boolean   1bytes

char/short       2bytes

int/float           4bytes

double/long     8bytes

(3)对象引用所占用的字节数

reference        4bytes

注:实际中,有数据成员的话,要把数据成员按基本类型和对象引用分开统计。基本类型按(2)进行累加,然后对齐到8个倍数;对象引用按每个4字节进行累加,然后对齐到8的倍数。

class test {
Integer i;
long l;
byte b;
}

占 8(基本) + 16(数据成员——基本类型:8 + 1,对齐到8) + 8(数据成员——对象引用Integer,4,对齐到8) = 32字节

如此一来的话,一个GenericPreference的对象就需要占用28个字节,userId(8bytes) + itemId(8bytes) + preference(4bytes) + 基本的8bytes = 28。如果我们使用了Collection<Preference>和Preference[],就会浪费很多这基本的8字节。设想如果我们的数据量是上GB或是上TB,这样的开销是很难承受的。

为此Mahout封装了一个PreferenceArray,用于保存一组用户喜好数据,为了优化性能,Mahout给出了两个实现类:GenericUserPreferenceArray和GenericItemPreferenceArray,分别按照用户和物品本身对用户偏好进行组装,这样就可以压缩用户ID或者物品ID的空间。

PreferenceArray
GenericUserPreferenceArray

我们看到,GenericUserPreferenceArray包含了一个userId,一个itemId的数组long[],一个用户的喜好评分数据float[],而不是一个Preference对象的集合,它只有较少的对象需要被创建和gc的检查。

用《Mahout in action》一书中的原话“mahout has alreadly reinvented an 'array of Java objects'”——"mahout已经重新改造了Java对象数组"。PreferenceArray和它的具体实现减少的内存开销远远比它的的复杂性有价值,它减少了近75%的内存开销(相对于Java的对象集合)

除了PreferenceArray,Mahout中还大量使用了像Map和Set这些非常典型的数据结构,但是Mahout没有直接使用像HashMap和TreeSet这些常用的Java集合实现,取而代之的是专门为Mahout推荐的需要实现了两个API,FastByIDMap和FastIDSet,之所以专门封装了这两个数据结构,主要目的是为了减少内存的开销,提高性能。它们之间主要有以下区别:

* 和HashMap一样,FastByIDMap也是基于hash的。不过FastByIDMap使用的是线性探测来解决hash冲突,而不是分离链;

* FastByIDMap的key和值都是long类型,而不是Object,这是基于节省内存开销和改善性能所作的改良;

* FastByIDMap类似于一个缓存区,它有一个“maximum size”的概念,当我们添加一个新元素的时候,如果超过了这个size,那些使用不频繁的元素就会被移除。

FastByIDMap和FastIDSet在存储方面的改进非常显著。FastIDSet的每个元素平均占14字节,而HashSet而需要84字节;FastByIDMap的每个entry占28字节,而HashMap则需要84字节。

DataModel Mahout推荐引擎实际接受的输入是DataModel,它是对用户喜好数据的压缩表示。DataModel的具体实现支持从任意类型的数据源抽取用户喜好信息,可以很容易的返回输入的喜好数据中关联到一个物品的用户ID列表和count计数,以及输入数据中所有用户和物品的数量。具体实现包括内存版的GenericDataModel,支持文件读取的FileDataModel和支持数据库读取的JDBCDataModel。

DataModel

GenericDataModel是DataModel的内存版实现。适用于在内存中构造推荐数据,它仅只是作为推荐引擎的输入接受用户的喜好数据,保存着一个按照用户ID和物品ID进行散列的PreferenceArray,而PreferenceArray中对应保存着这个用户ID或者物品ID的所有用户喜好数据。

GenericDataModel

FileDataModel支持文件的读取,Mahout对文件的格式没有太多严格的要求,只要满足一下格式就OK:

*  每一行包含一个用户Id,物品Id,用户喜好

*  逗号隔开或者Tab隔开

*  *.zip 和 *.gz 文件会自动解压缩(Mahout 建议在数据量过大时采用压缩的数据存储)

FileDataModel从文件中读取数据,然后将数据以GenericDataModel的形式载入内存,具体可以查看FileDataModel中的buildModel方法。

JDBCDataModel支持对数据库的读取操作,Mahout提供了对MySQL的默认支持MySQLJDBCDataModel,它对用户喜好数据的存储有以下要求:

* 用户ID列需要是BIGINT而且非空

* 物品ID列需要是BIGINT而且非空

* 用户喜好值列需要是FLOAT

* 建议在用户ID和物品ID上建索引

有的时候,我们会忽略用户的喜好值,仅仅只关心用户和物品之间存不存在关联关系,这种关联关系在Mahout里面叫做“boolean preference”。 之所以会有这类喜好,是因为用户和物品的关联要么存在,要么不存在,记住只是表示关联关系存不存在,不代表喜欢和不喜欢。实际上一条“boolean preference”可有三个状态:喜欢、不喜欢、没有任何关系。

在喜好数据中有大量的噪音数据的情况下,这种特殊的喜好评定方式是有意义的。 同时Mahout为“boolean preference”提供了一个内存版的DataModel——GenericBooleanPrefDataModel

GenericBooleanPrefDataModel

可以看到,GenericBooleanPrefDataModel没有对喜好值进行存储,仅仅只存储了关联的userId和itemId,注意和GenericDataModel的差别,GenericBooleanPrefDataModel采用了FastIDSet,只有关联的Id,没有喜好值。因此它的一些方法(继承自DataModel的)如getItemIDsForUser()有更好的执行速度,而getPreferencesFromUser()的执行速度会更差,因为GenericBooleanPrefDataModel本来就没存储喜好值,它默认用户对物品的喜好值都是1.0

@Override
public Float getPreferenceValue(long userID, long itemID) throws NoSuchUserException {
FastIDSet itemIDs = preferenceFromUsers.get(userID);
if (itemIDs == null) {
throw new NoSuchUserException(userID);
}
if (itemIDs.contains(itemID)) {
return 1.0f;
} return null;
}

利用mahout解决冷启动问题的一些建议:

Mahout 中对于冷启动问题并没有专门的实现,原因很简单,目前的 Mahout 只是一个机器学习算法库(框架),它不是一个推荐系统或推荐引擎。不过,我们还是可以利用 Mahout 中提供的一些算法帮助我们解决冷启动。

对于新用户,(1)如果是一个注册用户并且已经登录,但没有发生任何用户行为(比如评论、分享、收藏、购买),那么我们可以拿他的注册信息,根据他的性别、年龄、所在地等信息进行推荐,也就是基于人口统计特征的推荐(Demographic-based);(2)如果是一个注册用户但没有登录,那么我们可以通过 cookie 去识别用户,这个时候 cookie 和 userId 有同等的功效,解决的办法也就和(1)类似了。顺便罗嗦几句,一个成熟的推荐系统能够做到在用户未登录的情况下也能进行推荐,这就告诉我们,标识用户的除了 userId,还有 cookie,所以可以在记录用户喜好的表里增加一列用来存储用户的 cookie,这个视实际情况而定(对于 SNS 站点,如微博需要登录才能使用,不存在此类问题,但是对于淘宝就存在此问题);(3)对于未注册的新访客,因为没有人口统计信息,所以一般通过一些热卖推荐、随机推荐引导用户浏览、点击、收藏、注册,让用户在网站上发生一些有价值的行为,然后再根据这些行为进行推荐。

对于新物品,只要有物品的属性,那怕没有任何人对它进行评分,也是可以进行推荐的,方法就是根据物品的属性去推荐,也就是基于内容的推荐(Content-based),通过物品的属性去计算物品之间的相关度。举个例子,如果新加入的物品是一本刚出版的《HBase: The Definitive Guide》,没有任何用户对它进行过评分或购买,假设这个时候有一个用户对《Hadoop in Action》有了很高的评分,那么我们就可以把《HBase: The Definitive Guide》推荐给这个用户,因为这两本书用着共同的属性和特点:计算机、分布式、大数据 ...

那么如何利用 Mahout 帮忙解决新用户和新物品的冷启动问题呢?一个简单的方法是聚类。对于新用户,我们根据他们的人口统计信息去聚类,把用户划分成一个一个的簇;新物品也是一样的,可以利用物品的属性,如果没有属性,可以对物品的介绍和描述进行分词,抽取出物品的属性和关键词描述,然后根据属性和关键词去聚类,把物品划分成一个一个的簇。Mahout 中对聚类有专门的实现,可以关注我后面的日记和博文。

你的最后一个问题,如何根据好友的喜好进行推荐?说直接点,也就是如何利用社交数据进行推荐?随着 SNS 的流行,这种推荐方法也逐渐被重视,推荐的方法也很简单:从社交网站获取用户的好友列表,然后在目标网站中搜索好友列表中每一个好友喜欢的物品,然后推荐给用户。通常用户的好友列表是来源于外部的 SNS 网站,最普遍的就是通过开放的 API 授权后获取(微博、QQ空间都是这样),而用户的喜好 userId、itemId、preference 存储在目标网站的 MySQL 或者缓存中。需要做的仅只是 查找、过滤、排序 那么简单。

推荐的书籍和资料:《Mahout in Action》、《推荐系统实践》,ReSysChina

Mahout之数据承载的更多相关文章

  1. Mahout--(一)数据承载

    mahout API英文解释:https://builds.apache.org/job/Mahout-Quality/javadoc/ 推荐数据的处理是大规模的,在集群环境下一次要处理的数据可能是数 ...

  2. Mahout之(三)相似性度量

    User CF 和 Item CF 都依赖于相似度的计算,因为只有通过衡量用户之间或物品之间的相似度,才能找到用户的“邻居”,才能完成推荐.上文简单的介绍了相似性的计算,但不完全,下面就对常用的相似度 ...

  3. Apache mahout 源码阅读笔记--DataModel之FileDataModel

    要做推荐,用户行为数据是基础. 用户行为数据有哪些字段呢? mahout的DataModel支持,用户ID,ItemID是必须的,偏好值(用户对当前Item的评分),时间戳 这四个字段 {@code ...

  4. LTE 切换过程中的数据切换

    http://blog.sina.com.cn/s/blog_673b30dd0100j4p4.html LTE中的切换,根据无线承载(Radio Bearer)的QoS要求的不同,可以分为无缝切换( ...

  5. 转】Mahout学习路线图

    原博文出自于: http://blog.fens.me/hadoop-mahout-roadmap/ 感谢! Mahout学习路线图 Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目 ...

  6. Mahout机器学习平台之聚类算法具体剖析(含实例分析)

    第一部分: 学习Mahout必需要知道的资料查找技能: 学会查官方帮助文档: 解压用于安装文件(mahout-distribution-0.6.tar.gz),找到例如以下位置.我将该文件解压到win ...

  7. mahout第一篇-----Mahout学习路线图

    Mahout学习路线图 前言 Mahout是Hadoop家族中与众不同的一个成员,是基于一个Hadoop的机器学习和数据挖掘的分布式计算框架.Mahout是一个跨学科产品,同时也是我认为Hadoop家 ...

  8. Mahout学习路线图

    转自:http://blog.fens.me/hadoop-mahout-roadmap/ Mahout学习路线图 Hadoop家族系列文章,主要介绍Hadoop家族产品,常用的项目包括Hadoop, ...

  9. Mahout kmeans聚类

    Mahout  K-means聚类 一.Kmeans 聚类原理 K-means算法是最为经典的基于划分的聚类方法,是十大经典数据挖掘算法之一.K-means算法的基本思想是:以空间中k个点为中心进行聚 ...

随机推荐

  1. TypeScript 素描-变量声明

    博文读自 TypeScript 官方文档而来,不具有学习性,仅是本人学习时记录以供日后翻阅 ,有学习TypeScript的朋友还请去看更为详细的官方文档 /* 变量声明在之前的js中一直是使用var关 ...

  2. Linux下查看chm文件

    第一种方法.安装xchm,安装命令sudo apt-get install xchm,打开xchm,在终端下输入xchm. 第二种方法.安装kchmviewer,安装命令sudo apt-get in ...

  3. IOS-Hybrid(混合开发)

    http://www.cnblogs.com/oc-bowen/p/5423902.html 1.1.     APP三种开发模式 智能手机之普及不用多说,手机APP渗投到各个行业:电商(淘宝.京东等 ...

  4. Html中<font>标签的使用

    Html中<font>标签的使用 <!doctype html> <html lang="en"> <head> <meta ...

  5. coreseek常见错误原因及解决方法

    coreseek常见错误原因及解决方法 Coreseek 中文全文检索引擎 Coreseek 是一款中文全文检索/搜索软件,以GPLv2许可协议开源发布,基于Sphinx研发并独立发布,专攻中文搜索和 ...

  6. javascript闭包

    关于闭包的介绍,推荐两篇文章: 廖雪峰javascript教程-闭包: http://www.liaoxuefeng.com/wiki/001434446689867b27157e896e74d51a ...

  7. HDU 1859

    #include <iostream> #include <cstdio> #include <algorithm> #include <vector> ...

  8. IIS7.0发布Web服务-0001

    配置错误 不能在此路径中使用此配置节.如果在父级别上锁定了该节,便会出现这种情况.锁定是默认设置的 (overrideModeDefault="Deny"),或者是通过包含 ove ...

  9. docker版wordpress

    拉取wordpress镜像 docker pull wordpress:latest 创建mysql 容器docker run --name wordpress-mysql -e MYSQL_ROOT ...

  10. 修复Linux Mint损坏的依赖

    第一种: sudo apt-get install -f 第二种 sudo aptitude install -f 注: 要是某软件xxx依赖损坏了,可以这样 sudo aptitude instal ...