MapReduce实例-基于内容的推荐(一)
环境:
Hadoop1.x,CentOS6.5,三台虚拟机搭建的模拟分布式环境
数据:下载的amazon产品共同采购网络元数据(需翻墙下载)http://snap.stanford.edu/data/amazon-meta.html
方案目标:
从数据中提取出每个用户买过哪些商品,根据买过的商品以及商品之间的相关性来对用户进行推荐商品
下载的数据如下所示为单位
Id: 1
ASIN: 0827229534
title: Patterns of Preaching: A Sermon Sampler
group: Book
salesrank: 396585
similar: 5 0804215715 156101074X 0687023955 0687074231 082721619X
categories: 2
|Books[283155]|Subjects[1000]|Religion & Spirituality[22]|Christianity[12290]
|Clergy[12360]|Preaching[12368]
|Books[283155]|Subjects[1000]|Religion & Spirituality[22]|Christianity[12290]
|Clergy[12360]|Sermons[12370]
reviews: total: 2 downloaded: 2 avg rating: 5
2000-7-28 cutomer: A2JW67OY8U6HHK rating: 5 votes: 10 helpful: 9
2003-12-14 cutomer: A2VE83MZF98ITY rating: 5 votes: 6 helpful: 5
思路:
整套程序需要分解为两个步骤。1.提取每个用户买过哪些商品。2.根据第一步产生的数据,结合用户的感兴趣度与商品之间的关联生成推荐商品
本篇文章主要做第一步。
这一步骤的主要难点是对自定义输入格式的编写。
1.自定义格式化输入数据
如上所示的数据, 需要自定义输入数据的格式来提取数据。
job.setInputFormatClass(TestAmazonDataFormat.class);
那怎么做自定义输入格式呢?
这里我们需要了解文件在HDFS中的处理方式。我们知道文件在放入HDFS中时会进行分片。因此我们要对数据进行操作的时候,需要获取文件的信息(文件名、path、开始位置、长度、位于哪个节点等)。
传入文件信息:
//获取文件信息
public class TestAmazonDataFormat extends FileInputFormat<Text, Text> { TestAmazonDataReader datareader;
@Override
public RecordReader<Text, Text> createRecordReader(InputSplit inputSplit, TaskAttemptContext attempt)
throws IOException, InterruptedException {
datareader = new TestAmazonDataReader();
datareader.initialize(inputSplit, attempt); //传入文件信息
// TODO Auto-generated method stub
return datareader;
} }
读取文件:
package ren.snail; import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import java.util.regex.Matcher;
import java.util.regex.Pattern; import org.apache.hadoop.fs.FSDataInputStream;
import org.apache.hadoop.fs.FileSystem;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.InputSplit;
import org.apache.hadoop.mapreduce.RecordReader;
import org.apache.hadoop.mapreduce.TaskAttemptContext;
import org.apache.hadoop.mapreduce.lib.input.FileSplit; /**
* @author Srinath Perera (hemapani@apache.org)
*/ public class TestAmazonDataReader extends RecordReader<Text, Text> {
private static Pattern pattern1 = Pattern.compile(
"\\s+([^\\s]+)\\s+cutomer:\\s+([^\\s]+)\\s+rating:\\s+([^\\s]+)\\s+votes:\\s+([^\\s]+)\\s+helpful:\\s+([^\\s]+).*");
private BufferedReader reader;
private int count = 0;
private Text key;
private Text value;
private StringBuffer currentLineData = new StringBuffer();
String line = null; public TestAmazonDataReader() {
} public void initialize(InputSplit inputSplit, TaskAttemptContext attempt) throws IOException, InterruptedException {
// TODO Auto-generated method stub
Path path = ((FileSplit) inputSplit).getPath();
FileSystem fs = FileSystem.get(URI.create(path.toString()), attempt.getConfiguration()); //这里需要注意:由于fs.open的格式为file:///,而path获取的为HDFS的hdfs://XXXXX,因此需要在此进行转换
// FileSystem fs = FileSystem.get(attempt.getConfiguration());
FSDataInputStream fsStream = fs.open(path);
reader = new BufferedReader(new InputStreamReader(fsStream), 1024 * 100);
while ((line = reader.readLine()) != null) {
if (line.startsWith("Id:")) {
break;
}
}
} // define key and value
@Override
public boolean nextKeyValue() throws IOException, InterruptedException {
// TODO Auto-generated method stub
currentLineData = new StringBuffer();
count++;
boolean readingreview = false;
while ((line = reader.readLine()) != null) {
if(line.trim().length() == 0){
value = new Text(currentLineData.toString());
return true;
}
else {
if (readingreview) { Matcher matcher = pattern1.matcher(line);
if(matcher.matches())
{
currentLineData.append("review=").append(matcher.group(2)).append("|")
.append(matcher.group(3)).append("|")
.append(matcher.group(4)).append("|")
.append(matcher.group(5)).append("#");
}
else{
System.out.println("review "+ line + "does not match");
}
} else {
int indexOf = line.indexOf(":");
if(indexOf > 0){
String key = line.substring(0,indexOf).trim();
String value = line.substring(indexOf+1).trim();
if(value == null || value.length() == 0){
continue;
}
if(value.indexOf("#") > 0){
value = value.replaceAll("#", "_");
} if(key.equals("ASIN") || key.equals("Id") || key.equals("title") || key.equals("group") || key.equals("salesrank")){
if(key.equals("ASIN")){
this.key = new Text(value);
}
currentLineData.append(key).append("=").append(value.replaceAll(",", "")).append("#");
}else if(key.equals("similar")){
String[] tokens = value.split("\\s+");
//yes we skip the first one
if(tokens.length >= 2){
currentLineData.append(key).append("=");
for(int i=1;i<tokens.length;i++){
currentLineData.append(tokens[i].trim()).append("|");
}
currentLineData.append("#");
}
}else if( key.equals("reviews")){
readingreview = true;
}
}
}
} }
return false;
} @Override
public Text getCurrentKey() throws IOException, InterruptedException {
return key;
} @Override
public Text getCurrentValue() throws IOException, InterruptedException {
return value;
} @Override
public float getProgress() throws IOException, InterruptedException {
return count;
} @Override
public void close() throws IOException {
reader.close();
}
}
Map和Reduce
代码Map中有对于Amazon元数据的方法,就不给出了。就是对input传入的value数据进行解析
package ren.snail; import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.List;
import java.util.Set; import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.hdfs.tools.GetConf;
import org.apache.hadoop.io.IntWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapred.JobConf;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Mapper;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.input.FileInputFormat;
import org.apache.hadoop.mapreduce.lib.output.FileOutputFormat;
import org.apache.hadoop.util.GenericOptionsParser;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner; import ren.snail.AmazonCustomer.ItemData; /**
* Find number of owner and replies received by each thread
* @author Srinath Perera (hemapani@apache.org)
*/
public class Main extends Configured implements Tool {
public static SimpleDateFormat dateFormatter = new SimpleDateFormat("EEEE dd MMM yyyy hh:mm:ss z"); public static class AMapper extends Mapper<Object, Text, Text, Text> { public void map(Object key, Text value, Context context) throws IOException, InterruptedException {
//System.out.println(key + "="+ value);
try {
List<AmazonCustomer> customerList = AmazonCustomer.parseAItemLine(value.toString());
for(AmazonCustomer customer: customerList){
context.write(new Text(customer.customerID), new Text(customer.toString()));
//System.out.println(customer.customerID + "=" + customer.toString());
}
} catch (Exception e) {
e.printStackTrace();
System.out.println("Error:" +e.getMessage());
}
}
} public static class AReducer extends Reducer<Text, Text, IntWritable, Text> { public void reduce(Text key, Iterable<Text> values, Context context) throws IOException, InterruptedException {
AmazonCustomer customer = new AmazonCustomer();
customer.customerID = key.toString(); for(Text value: values){
Set<ItemData> itemsBrought = new AmazonCustomer(value.toString()).itemsBrought;
for(ItemData itemData: itemsBrought){
customer.itemsBrought.add(itemData);
}
}
// if(customer.itemsBrought.size() > 5){
context.write(new IntWritable(customer.itemsBrought.size()), new Text(customer.toString()));
// }
}
} public static void main(String[] args) throws Exception {
int result = ToolRunner.run(new Configuration(), new Main(), args);
System.exit(result); } @Override
public int run(String[] arg0) throws Exception {
// TODO Auto-generated method stub Configuration configuration = getConf();
Job job = new Job(configuration, "MostFrequentUserFinder");
job.setJarByClass(Main.class);
job.setMapperClass(AMapper.class);
job.setMapOutputKeyClass(Text.class);
job.setMapOutputValueClass(Text.class);
job.setOutputKeyClass(IntWritable.class);
job.setOutputValueClass(Text.class);
// Uncomment this to
// job.setCombinerClass(IntSumReducer.class);
job.setReducerClass(AReducer.class);
job.setInputFormatClass(TestAmazonDataFormat.class);
FileInputFormat.addInputPath(job, new Path(arg0[0]));
FileOutputFormat.setOutputPath(job, new Path(arg0[1]));
System.exit(job.waitForCompletion(true) ? 0 : 1);
return 0;
}
}
最终的输出如下:
customerID=A11NCO6YTE4BTJ,review=ASIN=0738700797#title=Candlemas: Feast of Flames#salesrank=168596#group=Book#rating=5#similar=0738700827|1567184960|1567182836|0738700525|0738700940|,
MapReduce实例-基于内容的推荐(一)的更多相关文章
- Recommender Systems基于内容的推荐
基于内容的推荐的基本推荐思路是:用户喜欢幻想小说,这本书是幻想小说,则用户有可能喜欢这本小说 两方面要求:(1)知道用户的喜好:(2)知道物品的属性 基于内容的推荐相比协同过滤方法(个人观点):协同过 ...
- 新闻推荐系统:基于内容的推荐算法(Recommender System:Content-based Recommendation)
https://blog.csdn.net/qq_32690999/article/details/77434381 因为开发了一个新闻推荐系统的模块,在推荐算法这一块涉及到了基于内容的推荐算法(Co ...
- elasticsearch使用More like this实现基于内容的推荐
基于内容的推荐通常是给定一篇文档信息,然后给用户推荐与该文档相识的文档.Lucene的api中有实现查询文章相似度的接口,叫MoreLikeThis.Elasticsearch封装了该接口,通过Ela ...
- 推荐系统第5周--- 基于内容的推荐,隐语义模型LFM
基于内容的推荐
- ElasticSearch java API-使用More like this实现基于内容的推荐
ElasticSearch java API-使用More like this实现基于内容的推荐 基于内容的推荐通常是给定一篇文档信息,然后给用户推荐与该文档相识的文档.Lucene的api中有实现查 ...
- 【T-BABY 夜谈大数据】基于内容的推荐算法
这个系列主要也是自己最近在研究大数据方向,所以边研究.开发也边整理相关的资料.网上的资料经常是碎片式的,如果要完整的看完可能需要同时看好几篇文章,所以我希望有兴趣的人能够更轻松和快速地学习相关的知识. ...
- C# 基于内容电影推荐项目(一)
从今天起,我将制作一个电影推荐项目,在此写下博客,记录每天的成果. 其实,从我发布 C# 爬取猫眼电影数据 这篇博客后, 我就已经开始制作电影推荐项目了,今天写下这篇博客,也是因为项目进度已经完成50 ...
- 基于内容的推荐 java实现
这是本人在cousera上学习机器学习的笔记,不能保证其正确性,慎重參考 看完这一课后Content Based Recommendations 后自己用java实现了一下 1.下图是待处理的数据,代 ...
- Recommending music on Spotify with deep learning 采用深度学习算法为Spotify做基于内容的音乐推荐
本文参考http://blog.csdn.net/zdy0_2004/article/details/43896015译文以及原文file:///F:/%E6%9C%BA%E5%99%A8%E5%AD ...
随机推荐
- Nancy 学习-自宿主 继续跨平台
Nancy简介 Nancy是一个轻量级的独立的框架,下面是官网的一些介绍: Nancy 是一个轻量级用于构建基于 HTTP 的 Web 服务,基于 .NET 和 Mono 平台,框架的目标是保持尽可能 ...
- WebView输入框提示
做基于WebView应用时,页面上有一个输入框,当输入的文字过多时,超过输入框的行数时,输入框能够滚动,这时间问题来了,输入的提示箭头会移动到输入框外,如何解决这个问题呢,查找chromium源码如下 ...
- iOS 阶段学习第十天笔记(结构体)
iOS学习(C语言)知识点整理 一.数据结构 1)概念:数据结构是指计算机程序中所操作的对象——数据以及数据元素之间的相互关系和运算. 2)结构体必须有struct 关键字修饰. 实例代码: stru ...
- 炉石传说 C# 开发笔记(6月底小结)
炉石传说的开发,已经有30个工作日了. 关于法术的定义方法,有过一次重大的变更:法术效果是整个炉石的核心,正是因为丰富的法术效果,才造就了炉石的可玩性. 原来构思的时候,对于法术效果没有充分的理解,所 ...
- C#微信公众平台账号开发,从零到整,步骤详细。
想到微信的火热,想到其他公司开发手游,如雷电,酷跑类的,都不是很火,但是弱智的“打飞机”和“天天酷跑”却是那么火热.于是乎,想做个微信营销的软件.首先想到的是手机连电脑wifi,用抓包工具抓微信的包, ...
- Java基础复习笔记系列 九 网络编程
Java基础复习笔记系列之 网络编程 学习资料参考: 1.http://www.icoolxue.com/ 2. 1.网络编程的基础概念. TCP/IP协议:Socket编程:IP地址. 中国和美国之 ...
- Web Service代理类生成工具
本文原文连接:http://www.cnblogs.com/dengxinglin/p/3334158.html 之前一篇文章写 Web Service服务代理类生成及编译 , 通过命令行的方式可以直 ...
- Atom + activate-power-mode震屏插件Windows7下安装
Atom是Github推出的一个文本编辑器,搜索一下大概是给Web前端用的,最近比较火的是他的一个插件activate-power-mode,可以实现打字屏振效果. 用来装装逼还是挺适合的,本来想试试 ...
- Java实现注册时发送激活邮件+激活
最近从项目分离出来的注册邮箱激活功能,整理一下,方便下次使用 1.RegisterController.java package com.app.web.controller; import java ...
- fakeLoader页面加载前loading演示8种效果
提高用户体验的插件fakeLoader页面加载前loading演示8种效果 在线预览 下载地址 示例代码 <div id="main"> <div class=& ...