Preference+PreferenceArray+DataModel

news/2023/9/27 7:10:37

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

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


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


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

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

这样一来的话,new Object()就占用了8个字节,那怕它是个空对象


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

byte/boolean 1bytes

char/short 2bytes

int/float 4byte

double/long 8bytes


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

reference 4bytes


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


占 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,用于表示喜好数据的集合



我们看到,GenericUserPreferenceArray包含了一个userId,一个itemId的数组long[],一个用户的喜好评分数据float[]。而不是一个Preference对象的集合。下面我们做个比较,分别创建一个PreferenceArray和Preference数组



在size为5,但只包含一条喜好数据的情况下:


PreferenceArray需要20Bytes(userId 8bytes + preference 4bytes + itemId8bytes),


而Preference[]需要48字节(基本8bytes + 一个Preference对象28bytes + 4个空的引用4×3 12Bytes)。如果在有多条喜好数据的情况下,PreferenceArray中将只有一个itemId,这样它所占用的8Bytes微乎其微。所以PreferenceArray用它特殊的实现节省了4倍内存。


用《Mahout in action》一书中的原话“mahout has alreadly reinvented an 'array of Javaobjects'”——"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类似于一个缓存区,它有一个“maximumsize”的概念,当我们添加一个新元素的时候,如果超过了这个size,那些使用不频繁的元素就会被移除。

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


========================================================================================================


DataModel

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

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


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



转载于:https://www.cnblogs.com/baoendemao/p/3804750.html


https://dhexx.cn/news/show-18581.html

相关文章

android 向js传递参数,《成为大前端》系列 4.4 Native与JS通信-参数传递和结果返回(Android)...

JS 传递参数到 Native前面完成了 JS 调用 Native&#xff0c;接下来继续 JS 如何传递参数到 Native传递原始类型数据先看 JS 端的代码&#xff1a;function onClickButton(){window.androidBridge.callNative("Hello");}复制代码Native 端&#xff1a;inner class Br…

2013第四届 蓝桥杯c/c++B组预赛 解题报告(还在更新中。。。。。)

大半部分题目都是自己做的&#xff0c;可能还有存在错误的地方&#xff0c;还望各位指正。 有不会的题目&#xff0c;还请大牛们留下解题思路&#xff0c;谢谢了。 第一题&#xff1a;高斯日记 大数学家高斯有个好习惯&#xff1a;无论如何都要记日记。他的日记有个与众不同的地…

android读取多行文件,Android 读取txt,按行读取的实例讲解

Android 读取txt,按行读取的实例讲解发布时间&#xff1a;2020-09-12 12:43:31来源&#xff1a;脚本之家阅读&#xff1a;103作者&#xff1a;Damionew一个TXT 文件 对其进行读取&#xff0c;并且每行都单个存储读取public class MainActivity extends AppCompatActivity {priv…

Java简单游戏开发之碰撞检测

前言 不久之前在论坛上有人发贴&#xff0c;使用java编写的超级马里奥如何实现碰撞检测&#xff0c;笔者自己以前 也做过Tank大战。里面同样涉及到碰撞检测&#xff0c;翻翻U盘里的东西还在&#xff0c;什么时候也给共享出来。 这篇文章就简单游戏中的碰撞检测做一个简单的总结…

通用用户权限管理系统组件V3.9功能改进说明 - 操作权限项定义简化

在通用权限管理系统组件V3.9中对操作权限项定义进行了一次大胆的简化&#xff0c;现在定义模块菜单的同时可以定义操作权限项目&#xff0c;这样不用菜单与操作权限分离了&#xff0c;可以集中展示&#xff0c;实用效果更加友善。 下面是定义菜单或者操作权限项目的参考页面 设…

html 10 margin 重叠

留意&#xff0c;父子元素&#xff0c;margin重叠影响的是margin-top上的。取两者中的最大值&#xff0c;水平和bottom不受影响&#xff0c; 重叠的时候子元素的margin-top消失 父元素如果加了padding属性&#xff0c;不会重叠。子元素如果有float&#xff0c;父子不重叠 CSS 外…

PHP cURL模块

简介&#xff1a; cURL是利用URL语法在命令行方式下工作的文件传输工具&#xff0c;目前苹果机器已经内置了cURL。cURL是一个综合性的传输工具&#xff0c;对HTTP、FTP等协议提供了广泛的支持&#xff0c;它甚至可以实现迅雷、快车等下载工具的所有功能。PHP中也提供了对cURL语…

day20(下)_IO流5(递归穷举与删除,Properties,PrintStream,PrintWriter,SequenceInputStream)

1.对目录和文件递归穷举 /* 列出指定目录下的文件或者文件夹,包含子目录中的内容 也就是列出目录下所有的内容 例如:new File(d:\\);在d盘下还有一个abc目录而abc下还有文件和目录,而用list()方法只能获取到d盘下的文件和目录 */ package filedemo; import java.util.Arrays; i…

android javacv 录像,使用JavaCV(ffmpeg)录制视频

使用JavaCV(ffmpeg)录制视频JavaCV是对各种常用计算机视觉库的封装后的一组jar包&#xff0c;其中封装了ffmpeg、OpenCV、libdc1394、OpenKinect、videoInput和ARToolKitPlus等计算机视觉编程人员常用库的接口&#xff0c;可以通过其中的utility类方便的在包括Android在内的Jav…

协方差矩阵和相关矩阵

1、协方差矩阵 协方差是衡量两个随机变量&#xff08;同一样本&#xff0c;不同分量&#xff09;的相关程度。&#xff08;方差描述的是一维变量&#xff09;随机变量 之间的协方差可以表示为根据已知的样本值可以得到协方差的估计值如下&#xff08;列向量相关&#xff09;&am…