3 推荐数据的呈现

这章主要讲述:

。Mahout如何展现推荐器的数据

。DataModel 的实现及其用法 

。没有评分数据

Recommendations的质量主要是由数据的数量和质量决定的。“无用输出,无用输入” 在这里是最真实的。同样,推荐器算法都是集中数据,运行的性能主要受数据的数量和展现的影响。这一章

介绍Mahout的一些关键class,和访问推荐器相关的数据。


3.1 呈现偏好数据

一个推荐引擎的输入数据是评分数据:它喜欢什么以及喜欢的程度。所以,Mahout recommenders的输入数据是一组简单的“userID”,“itemID”,和“评分数据”元组,当然,这是一个大的集合。评分数据有时候会被省略。


3.1.1 Preference对象

Preference是一个最基础的概念,它表现一个单一的userID,itemID和一个评分值。这个对象表现为一个用户对一个条目的打分。Preference是一个接口,通常使用的实现类为GenericPreference。例如:创建一条记录,user(123),对item(456)的打分是3.0: new GenericPreference(123, 456, 3.0f)。

一组Preferences如何表现?如果你给出了一个合理的答案,如Collection<Preference> 或者 Preference[],大部分情况下,在Mahout APIs中不是这样实现的。Collections和arrays对处理海量Preference对象是无效的。如果你在Java中从未研究过上面的对象,你可能会感到困惑!

单个的GenericPreference包含20个字节的有用数据:一个8字节的user ID(Java long),8字节的item ID(long),4字节的分值(float)。这个对象的存在使GenericPreference包含的字节有惊人的增长:28个字节!这个变化依赖的是JVM的实现;这个数字是从苹果Mac OS X 10.6的64位Java 6 VM 得到的。由于上面的对象和其他线性问题,对这个对象来说,28个字节中包括8字节的参考值,另外20个字节的空格,在对象自身的表现内。由于上面的现象,因此一个GenericPreference对象已经比它需要多消耗了140%的存储。

为什么这么做?在recommender算法中,都需要所有评分数据的集合,这些评分数据是与一个用户或一个项目联系在一起的。在这样一个集合里,user ID或者item ID与所有好像多余的Preference对象将会是配套的。

3.1.2 PreferenceArray和实现

进入PreferenceArray,这个接口的实现表现为一个具有类似与数组的API的分值的集合。例如,GenericUserPreferenceArray表现为一个用户的所有打分.它在内部包括一个单一的user ID,一系列的item IDs,一系列的评分值。在一个用户的所有打分中,需要占用12个字节的内存(一个8字节的item ID和一个4字节的评分值)。把它与需要一个完整的Preference项目的大约48个字节相比较。这个4字节内存,包括对齐这个特殊的实现,
但它也提供了小的性能提升,更小的对象必须被垃圾回收器分配和检查。比较图3.1 and 3.2去理解这些保存是如何完成的。

3 推荐数据的呈现_第1张图片

图3.1


图3.1效率较低的评分值的表现,利用一系列的Preference对象。灰色的区域代表上面的对象。白色的区域是数据,它包括引用对象。


3 推荐数据的呈现_第2张图片

图3.2 


图3.2利用GenericUserPreferenceArray更有效的表现

下面的代码表现一个PreferenceArray的典型的构造和使用
列表3.1在一个PreferenceArray中设置评分值  

PreferenceArray user1Prefs = new GenericUserPreferenceArray(2); 
user1Prefs.setUserID(0, 1L); // 为所有打分设置user ID  
user1Prefs.setItemID(0, 101L); 
user1Prefs.setValue(0, 2.0f); // User 1当前为item 101的打分2.0 
user1Prefs.setItemID(1, 102L); 
user1Prefs.setValue(1, 3.0f); // User 1为item 102的打分3.0  
Preference pref = user1Prefs.get(1); // Item 102的一个Preference 



同样这里存在一个称为GenericItemPreferenceArray的实现,它内部的所有分值,与item关联而不是与user关联。它的目的和用法都是完全类似的。


3.1.3  加速集合


非常高兴的是,Mahout已经重新创造了“java数组对象”。这只是万里长征的第一步。我们提及到规模是重要的吗?可能,你已经被说服,我们将会面对处理巨大数量的数据,和不寻常响应。

这个reduced的内存需求,由PreferenceArray和它的实现,带来的复杂性是值得的。削减内存需求的百分之七十五不只是节约一对M字节。在一个合理的规模上,它节约了10分之一G内存。这可能是在你现存的硬盘上是否装配之间的不同。这是是否必须投资大量的RAM和可能的一个新的64-bit系统之间的不同。那是一个小的,但真正节能的技术,非常重要。

3.1.4 FastByIDMap 和 FastIDSet 
当你听到Mahout 推荐器大量的使用如map和set的典型的数据结构时将不会感到奇怪,但是不要使用如TreeSet和HashMap的普通的Java实现。相反,遍历这个实现和API你将会找到FastByIDMap和FastIDSet。它们是像Map和set一样的程序,但是是被明确的详细说明,并只提供Mahout recommenders需要的程序。它们减少内存占用而不是在性能上显著的增加。 

这里没有一个像java中的Collections。但是,它们在一个大范围的环境内,为有效的目的而精心设计。它们不能对未来的使用做出更多的假设。Mahout的需要对可得到的用法有更加特殊,更强的假设。主要不同是:

。如同HashMap,FastByIDMap 是 hash-based。它使用线性探索而不是分离链接来处理hash collisions。这避免了一个额外的Map.Entry对象的每个入口的需要;如我们所讨论的,Objects占用了令人惊奇的内存数量。

。Keys和members在Mahout recommenders中总是长的基元,而在objects中则不是。使用长的keys节约内存并提高性能。

。Set的实现不是使用下面的一个Map来实现的。

。FastByIDMap可以像一个cache一样起作用,因为它有一个“maximum size”的概念;超过这个尺寸,当增加了新的entries时,infrequently-used entries将会被删除。

存储的不同是有意义的:与HashSet 的84个字节相比,FastIDSet平均每个member需要大约14个字节。与HashMap 的每个入口的84个字节再次比较,FastByIDMap每个入口占用28个字节。这显示当一个人对用法做了更强的假设时,有意义的改善是可能的:主要在内存需求上。考虑到为recommender系统提供的讨论中的数据量,这些习惯的实现不仅仅证明了它自己。所以,这些类用在哪里?



你可能感兴趣的:(java,数据结构,HashMap,user,Collections,Arrays)