起点R3基于Mahout实现的推荐引擎

R3商业智能 发布于 2011/04/13 07:54
阅读 4K+
收藏 8

解读下一代网络:算力网络正从理想照进现实!>>>

1、用户行为日志
     起点R3电子商务搜索引擎演示系统中记录的用户行为数据主要包括四大类
 搜索历史
搜索历史的记录主要包括用户信息、时间、地址、检索的关键词,检索关键词拼音及缩写,用户年纪等,其中,记录的时间包括检索发生时的小时、当天是周几、当天的日期信息;地址信息包括了省市区县信息。
 点击历史
点击历史记录了当前点击记录的用户信息、时间、地址、检索词、点击记录的序号、点击记录的ID,其中,记录的时间包括检索发生时的小时、当天是周几、当天的日期信息;记录了该产品是在搜索结果中点击的还是推荐结果中点击的;地址信息包括了省市区县信息。
 购买历史
购买历史分类已付款和未付款,并记录的有付款时间和订单时间。统计还记录了用户信息、时间、地址、检索词、点击记录的序号、购买记录的ID,并且统计了在查看了该记录多少次以后购买的,也记录了该产品是在搜索结果中点击的还是推荐结果中点击的,其中,记录的时间包括检索发生时的小时、当天是周几、当天的日期信息;地址信息包括了省市区县信息。
 浏览数据历史
浏览数据是用户在查看产品信息的浏览记录,一次点击查看的页面会记录多条浏览数据,该记录是采样数据,采集的频率是10秒一次,记录了用户信息、时间、地址、检索词、产品ID、当前鼠标浏览位置、当前页面焦点位置、当前页面滚动次数、距离上一次滚动时间等信息。
2、推荐引擎
 起点R3电子商务搜索智能推荐引擎是基于以上历史记录的数据分析与挖掘。主要推荐类型分为四种:
 直接推荐
     直接推荐是最简单的一种推荐方式,比如,根据用户的检索词向推荐用户与该检索词高度相关的产品信息,推荐列表的排序方式可以是按照销售量排序、浏览量或其他方式排序。
 交叉推荐
    交叉推荐是稍复杂一些的一种推荐方式,比如:购买该商品的用户还购买了那些商品、浏览该商品的用户还浏览了那些商品,推荐列表的排序方式可以是按照销售量排序、浏览量或其他方式排序。
 区域性和时间段推荐
    区域性推荐是在以上两种推荐的基础之上扩展的一种推荐,比如,上海地区的购买了该商品的用户还购买了那些商品;上海地区在周六日购买了该商品的用户还购买了那些商品;上海地区的用户在下午5点-8点间购买了该商品的用户还购买了那些商品。
 商品属性相关推荐
    商品属性相关推荐是针对用户购买记录或浏览记录进行分析以后的一种推荐方式,是一种简单计算,比如,对用户购买或浏览记录进行Facet统计以后得出该用户主要注意力在B罩杯的内衣,那么对用户推荐的列表中只包含B罩杯的商品;另一类:比如用户浏览的内衣70%以上都是性感类型的,推荐引擎在对该用户进行推荐的时候,则只推荐性感类型的内衣、内裤。
起点R3还可以根据用户的购买行为来分析用户的社会化属性,比如区分喜好性感类型的用户群和喜好文静型的用户群,并可以针对不同的用户群计算不同的推荐列表用于发送邮件列表。
3、用户访问数据分析
    用户访问数据分析主要是对用户操作历史记录的数据进行数据挖掘和分析,主要包括四类:
 社会化属性
    社会化属性分析主要包括分析用户类型、用户的使用偏好、用户的购买习惯、消费习惯、消费能力以及评论或商品的销售数据对用户的影响等数据的分析。
 区域性分析
    区域性分析是对地区数据进行分析,以确定该地区的用户购买习惯、消费能力、消费习惯、以及用户年龄分布等。
 时间周期特性分析
    时间周期分布主要是和以上两类综合统计,比如用于计算周六周日以及特殊节假日的推荐列表等。
 商品和商品组合分析
    该分析主要是统计商品的购买特点,比如,通常用户浏览了多少次以后会购买该商品,那些商品会在短期内(2小时)同时购买,以及商品和地区区域、时间周期的组合分析等。
4、用户行为对搜索结果的影响
    用户行为对搜索结果的影响主要体现在排序和推荐列表中,在对搜索结果的排序中,购买量是一个排序参数,可以直接使用商品购买数量对搜索结果排序。此外,可用的排序参数还包括商品购买浏览量、商品点击量、商品浏览时长等指标。用户行为对推荐列表的影响就更为直接了,交叉推荐、区域性和时间段推荐以及商品属性相关推荐都是以用户购买数据和浏览数据为基础进行的。

加载中
0
华宰
华宰

文章应该介绍如何基于Mahout实现推荐的,而不是讲这些开发人员不太关心的内容。

所以看起来像广告帖,踩~

0
R3商业智能
R3商业智能

引用来自#2楼“华宰”的帖子

文章应该介绍如何基于Mahout实现推荐的,而不是讲这些开发人员不太关心的内容。

所以看起来像广告帖,踩~

 慢慢来,昨天晚上整理一个晚上,全部内容,都会发出来的

0
R3商业智能
R3商业智能

获取推荐内容的主要代码

package org.rivu.plugin.recommender;

import java.util.Collection;
import java.util.List;

import org.apache.mahout.cf.taste.common.Refreshable;
import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.CachingRecommender;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.AveragingPreferenceInferrer;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.IDRescorer;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;

public class RivuRecommenderPlugin implements Recommender {
	private final Recommender recommender;
	public RivuRecommenderPlugin(DataModel dataModel) throws TasteException{
		UserSimilarity userSimilarity = new PearsonCorrelationSimilarity(dataModel);          
		userSimilarity.setPreferenceInferrer(new AveragingPreferenceInferrer(dataModel));        
		UserNeighborhood neighborhood = new NearestNUserNeighborhood(3, userSimilarity, dataModel);        
		recommender = new CachingRecommender(           
				new GenericUserBasedRecommender(dataModel, neighborhood, userSimilarity));
	}
	@Override
	public void refresh(Collection<Refreshable> alreadyRefreshed) {
		recommender.refresh(alreadyRefreshed);
	}

	@Override
	public float estimatePreference(long userID, long itemID) throws TasteException {
		 return recommender.estimatePreference(userID, itemID);
	}

	@Override
	public DataModel getDataModel() {
		return recommender.getDataModel();
	}

	@Override
	public List<RecommendedItem> recommend(long userID, int howMany)
			throws TasteException {
		return recommender.recommend(userID, howMany);
	}

	@Override
	public List<RecommendedItem> recommend(long userID, int howMany, IDRescorer rescorer)
			throws TasteException {
		return recommender.recommend(userID, howMany, rescorer);
	}

	@Override
	public void removePreference(long userID, long itemID) throws TasteException {
		 recommender.removePreference(userID, itemID);
	}

	@Override
	public void setPreference(long userID, long itemID, float value)
			throws TasteException {
		recommender.setPreference(userID, itemID, value);
	}

}

重要的是DataModel dataModel , 从Solr获取数据,问题在于GenericUserPreferenceArray使用的内存大概为30个字节,在JVM里即使为Mahout分配1G内存用于计算推荐内容,最大可以承受数据量大约为350万条左右,这个数据量远远满足不了要求,有点规模的电子商务网站积累的日志数据量都比这个要大,所以,可以将GenericUserPreferenceArray的每条记录内存占用缩减到5到6字节,其中,UserID使用三个字节,商品使用两个字节,分值使用1个字节,前提是,注册用户量小于256*65536 ,商品数量少于 65536 ;如果超出这个数字,则商品数据可以使用3个字节,即256*65536,大部分的电子商务网站商品数量应该在这个规模以下。占用5个字节,1G内存大约可以计算2000万条记录,有一些增加,如果用Linux,内存分配到2.6G,全部用来计算推荐内容并且缓存,可以处理的数据量大概为6千万条左右,不采用分布式的情况下,估计6000万也是个上限了

yunitongle
yunitongle
请问博主,怎么将GenericUserPreferenceArray的每条记录内存占用缩减到6字节呀?(其中,UserID使用三个字节,商品使用三个字节,分值使用1个字节)求指点!
0
R3商业智能
R3商业智能

测试代码如下:

package org.rivu.test;

import java.util.List;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.GenericUserBasedRecommender;
import org.apache.mahout.cf.taste.impl.similarity.PearsonCorrelationSimilarity;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.neighborhood.UserNeighborhood;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.apache.mahout.cf.taste.recommender.Recommender;
import org.apache.mahout.cf.taste.similarity.UserSimilarity;
import org.rivu.plugin.recommender.RivuLogDataModel;
import org.rivu.plugin.recommender.RivuRecommenderPlugin;

public class MahoutTest {
	public static void main(String[] args) throws TasteException {
		FastByIDMap<PreferenceArray> preferences = new FastByIDMap<PreferenceArray>();
		PreferenceArray prefsForUser1 = new GenericUserPreferenceArray(10);
		prefsForUser1.setItemID(0, 101);
		prefsForUser1.setValue(0, 5.0f);
		prefsForUser1.setItemID(1, 102);
		prefsForUser1.setValue(1, 3.0f);
		prefsForUser1.setItemID(2, 103);
		prefsForUser1.setValue(2, 2.5f);
		preferences.put(1l, prefsForUser1);// 在这里添加数据
		PreferenceArray prefsForUser2 = new GenericUserPreferenceArray(4);
		prefsForUser2.setUserID(0, 2);
		prefsForUser2.setItemID(0, 101);
		prefsForUser2.setValue(0, 2.0f);
		prefsForUser2.setItemID(1, 102);
		prefsForUser2.setValue(1, 2.5f);
		prefsForUser2.setItemID(2, 103);
		prefsForUser2.setValue(2, 5.0f);
		prefsForUser2.setItemID(3, 104);
		prefsForUser2.setValue(3, 2.0f);
		preferences.put(2l, prefsForUser2);
		PreferenceArray prefsForUser3 = new GenericUserPreferenceArray(4);
		prefsForUser3.setUserID(0, 3);
		prefsForUser3.setItemID(0, 101);
		prefsForUser3.setValue(0, 2.5f);
		prefsForUser3.setItemID(1, 104);
		prefsForUser3.setValue(1, 4.0f);
		prefsForUser3.setItemID(2, 105);
		prefsForUser3.setValue(2, 4.5f);
		prefsForUser3.setItemID(3, 107);
		prefsForUser3.setValue(3, 5.0f);
		preferences.put(3l, prefsForUser3);
		PreferenceArray prefsForUser4 = new GenericUserPreferenceArray(4);
		prefsForUser4.setUserID(0, 4);
		prefsForUser4.setItemID(0, 101);
		prefsForUser4.setValue(0, 5.0f);
		prefsForUser4.setItemID(1, 103);
		prefsForUser4.setValue(1, 3.0f);
		prefsForUser4.setItemID(2, 104);
		prefsForUser4.setValue(2, 4.5f);
		prefsForUser4.setItemID(3, 106);
		prefsForUser4.setValue(3, 4.0f);
		preferences.put(4l, prefsForUser4);
		PreferenceArray prefsForUser5 = new GenericUserPreferenceArray(6);
		prefsForUser5.setUserID(0, 5);
		prefsForUser5.setItemID(0, 101);
		prefsForUser5.setValue(0, 4.0f);
		prefsForUser5.setItemID(1, 102);
		prefsForUser5.setValue(1, 3.0f);
		prefsForUser5.setItemID(2, 103);
		prefsForUser5.setValue(2, 2.0f);
		prefsForUser5.setItemID(3, 104);
		prefsForUser5.setValue(3, 4.0f);
		prefsForUser5.setItemID(4, 105);
		prefsForUser5.setValue(4, 3.5f);
		prefsForUser5.setItemID(5, 106);
		prefsForUser5.setValue(5, 4.0f);
		preferences.put(5l, prefsForUser5);

		DataModel model = new GenericDataModel(preferences);// DataModel的建立

		RivuRecommenderPlugin recommenderPlugin = new RivuRecommenderPlugin(model);
		List<RecommendedItem> dataList = recommenderPlugin.recommend(1, 10);
		for (RecommendedItem item : dataList) {
			System.out.println("item.getId():" + item.getItemID() + " value:"
					+ item.getValue());
		}
	}
}

结果如下:

11-04-13 08:33:26 INFO  - Processed 5 users
item.getId():104 value:5.0
item.getId():106 value:4.0

List<RecommendedItem> dataList = recommenderPlugin.recommend(1, 10);
获取用户1的10条推荐信息,计算结果返回了 104和106两个商品

0
jingshishengxu
jingshishengxu

Mahout 不错,不知道性能怎样

0
R3商业智能
R3商业智能

引用来自#8楼“jingshishengxu”的帖子

Mahout 不错,不知道性能怎样

 数据量大了得依赖Hadoop,负载倒是有其他非实时策略来解决

0
R3商业智能
R3商业智能

另一个测试,10万数据量,评分和商品都随机生成

package org.rivu.test;

import java.util.List;
import java.util.Random;

import org.apache.mahout.cf.taste.common.TasteException;
import org.apache.mahout.cf.taste.impl.common.FastByIDMap;
import org.apache.mahout.cf.taste.impl.model.GenericDataModel;
import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
import org.apache.mahout.cf.taste.model.DataModel;
import org.apache.mahout.cf.taste.model.PreferenceArray;
import org.apache.mahout.cf.taste.recommender.RecommendedItem;
import org.rivu.plugin.recommender.RivuRecommenderPlugin;

public class MahoutTest {
	public static void main(String[] args) throws TasteException {
		FastByIDMap<PreferenceArray> preferences = new FastByIDMap<PreferenceArray>();
		PreferenceArray prefsForUser = null ;
		Random r = new Random();
		for(long i=0 ; i<100000; i++){
			int num = r.nextInt(10)+1 ;
			prefsForUser = new GenericUserPreferenceArray(num);
			if(i>0){
				prefsForUser.setUserID(0, i);
			}
			for(int index = 0 ; index<num;index++){
				prefsForUser.setItemID(index, r.nextInt(100));    //商品编号
				prefsForUser.setValue(index, r.nextInt(5));
			}
			preferences.put(i, prefsForUser) ;
			
		}

		DataModel model = new GenericDataModel(preferences);// DataModel的建立

		RivuRecommenderPlugin recommenderPlugin = new RivuRecommenderPlugin(model);
		List<RecommendedItem> dataList = recommenderPlugin.recommend(1, 10);
		for (RecommendedItem item : dataList) {
			System.out.println("item.getId():" + item.getItemID() + " value:"
					+ item.getValue());
		}
	}
}

推荐结果如下:

item.getId():17 value:4.0
item.getId():97 value:3.494683
item.getId():78 value:3.0
item.getId():94 value:2.9303246
item.getId():13 value:2.6116757
item.getId():52 value:2.6002476
item.getId():53 value:2.5918114
item.getId():36 value:2.5029159
item.getId():95 value:2.4825807
item.getId():27 value:2.475848

给用户1推荐的商品中最值得推荐的是 编号为17的商品,评分为4分

0
R3商业智能
R3商业智能

1G内存,820万数据的内存占用

yunitongle
yunitongle
图挂了!
返回顶部
顶部