Jean-Francois Leveque

Preview release processing

......@@ -37,8 +37,7 @@ public class CosineRecommender implements Recommender {
ItemRecommender irec;
@Override
public void Recommender(String filePath) {
public CosineRecommender(String filePath) {
config = new LenskitConfiguration();
config.bind(ItemScorer.class).to(ItemItemScorer.class);
......
......@@ -33,8 +33,7 @@ public class FunkSVDRecommender implements Recommender {
ItemRecommender irec;
@Override
public void Recommender(String filePath) {
public FunkSVDRecommender(String filePath) {
config = new LenskitConfiguration();
config.bind(ItemScorer.class).to(FunkSVDItemScorer.class);
......
......@@ -37,8 +37,7 @@ public class PearsonRecommender implements Recommender {
ItemRecommender irec;
@Override
public void Recommender(String filePath) {
public PearsonRecommender(String filePath) {
config = new LenskitConfiguration();
config.bind(ItemScorer.class).to(ItemItemScorer.class);
......
......@@ -10,18 +10,8 @@ import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class ProcessingApplication {
Logger logger = LoggerFactory.getLogger(getClass());
public static void main(String[] args) {
SpringApplication.run(ProcessingApplication.class, args);
}
@Bean
public CommandLineRunner process() {
return (args) -> this.run();
}
public void run() {
}
}
......
package org.legrog.recommendation.process;
import org.grouplens.lenskit.scored.ScoredId;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.List;
import java.util.Set;
public class ProcessingExpert {
Logger logger = LoggerFactory.getLogger(getClass());
Recommender recommender;
int topSize;
public ProcessingExpert(Recommender recommender, int topSize) {
this.recommender = recommender;
this.topSize = topSize;
}
public ProcessingRecommendations getRecommendations(Set<Long> userIds) {
ProcessingRecommendations processingRecommendations = new ProcessingRecommendations();
List<ScoredId> recommendations;
for (Long userId : userIds) {
recommendations = recommender.recommend(userId, topSize);
for (ScoredId recommendation : recommendations) {
processingRecommendations.addRecommentation(new RecommendationElement(userId, recommendation.getId()));
logger.trace("Recommending {} for {}", recommendation.getId(), userId);
}
}
return processingRecommendations;
}
}
package org.legrog.recommendation.process;
import java.util.HashSet;
import java.util.Set;
public class ProcessingRecommendations {
Set<RecommendationElement> recommendations;
public ProcessingRecommendations() {
recommendations = new HashSet<>();
}
public void addRecommentation(RecommendationElement recommendationElement) {
recommendations.add(recommendationElement);
}
public Set<RecommendationElement> getRecommendations() {
return recommendations;
}
}
package org.legrog.recommendation.process;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVPrinter;
import org.apache.commons.csv.CSVRecord;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
import java.io.*;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
@Component
public class ProcessingRunner implements ApplicationRunner {
Logger logger = LoggerFactory.getLogger(getClass());
@Value("${parameters.filename}")
private String parametersFilename;
@Value("${data.dir}")
private String dataDir;
@Value("${collectionSample.filename}")
private String collectionSampleFilename;
@Value("${ratingSample.filename}")
private String ratingSampleFilename;
@Value("${recommandations.filename}")
private String recommandationsFilename;
private String sampleFilename;
private String algorithm;
private Recommender recommender;
private int topSize;
@Override
public void run(ApplicationArguments args) throws Exception {
loadParameters();
logger.trace("Parameters loaded");
Set<Long> userIds = loadUserIdsFromSample();
RecommenderFactory recommenderFactory = new RecommenderFactory();
recommender = recommenderFactory.build(algorithm ,dataDir+sampleFilename);
logger.trace("Recommender built");
ProcessingExpert processingExpert = new ProcessingExpert(recommender, topSize);
ProcessingRecommendations processingRecommendations = processingExpert.getRecommendations(userIds);
logger.trace("Recommendations done");
writeRecommendationsToFile(processingRecommendations);
logger.trace("Recommendations written");
}
private Set<Long> loadUserIdsFromSample() throws ProcessingException {
Set<Long> userIds = new HashSet<>();
Reader in = null;
try {
in = new FileReader(dataDir+sampleFilename);
Iterable<CSVRecord> records = CSVFormat.TDF.withFirstRecordAsHeader().parse(in);
for (CSVRecord record : records) {
userIds.add(Long.parseLong(record.get("userId")));
}
} catch (FileNotFoundException e) {
throw new ProcessingException("sample file not found " + dataDir + sampleFilename, e);
} catch (IOException e) {
throw new ProcessingException("Can't read user ids from sample file " + dataDir + sampleFilename, e);
}
return userIds;
}
private void writeRecommendationsToFile(ProcessingRecommendations processingRecommendations) throws ProcessingException {
try {
CSVPrinter csvPrinter = new CSVPrinter(new FileWriter(new File(dataDir, recommandationsFilename)),
CSVFormat.TDF.withHeader("itemId", "userId"));
// TODO : finish
Set<RecommendationElement> recommendations = processingRecommendations.getRecommendations();
if (recommendations.isEmpty()) {
logger.trace("No recommendations at all");
} else {
logger.trace("{} recommendations", recommendations.size());
}
// forEach incompatible avec IOException
for (RecommendationElement recommendation : recommendations) {
csvPrinter.printRecord(recommendation.getItemId(), recommendation.getUserId());
}
csvPrinter.close();
} catch (IOException e) {
throw new ProcessingException("Can't write recommendations file " + dataDir + recommandationsFilename, e);
}
}
/**
* read properties file from application.properties' parameter.fileName then search for parameters inside
* for ratings, select rating or collection file as the sample file for sample ; using others directly
*
* todo replace this by a command line switch ?
*
* @throws ProcessingException
*/
private void loadParameters() throws ProcessingException {
try (InputStream in = new FileInputStream(new File(dataDir, parametersFilename))) {
Properties properties = new Properties();
properties.load(in);
if (properties.containsKey("ratings")) {
logger.trace("ratings {}", properties.getProperty("ratings"));
if (Boolean.parseBoolean(properties.getProperty("ratings"))) {
sampleFilename = ratingSampleFilename;
} else {
sampleFilename = collectionSampleFilename;
}
} else {
// by default, takes collection
sampleFilename = collectionSampleFilename;
}
if (properties.containsKey("algorithm")) {
algorithm = properties.getProperty("algorithm");
} else {
// default algorithm is Cosine
algorithm = "cosine";
}
if (properties.containsKey("topSize")) {
topSize = Integer.parseInt(properties.getProperty("topSize"));
} else {
// default top size is 10
topSize = 10;
}
} catch (IOException e) {
throw new ProcessingException("Can't read parameters properties file " + parametersFilename, e);
}
}
private class ProcessingException extends Exception {
public ProcessingException() {
super();
}
public ProcessingException(String message) {
super(message);
}
public ProcessingException(String message, Throwable cause) {
super(message, cause);
}
public ProcessingException(Throwable cause) {
super(cause);
}
protected ProcessingException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
}
\ No newline at end of file
package org.legrog.recommendation.process;
public class RecommendationElement {
private Long userId;
private Long itemId;
public RecommendationElement(Long userId, Long itemId) {
this.userId = userId;
this.itemId = itemId;
}
public Long getUserId() {
return userId;
}
public Long getItemId() {
return itemId;
}
}
......@@ -5,7 +5,5 @@ import org.grouplens.lenskit.scored.ScoredId;
import java.util.List;
public interface Recommender {
void Recommender(String filePath);
List<ScoredId> recommend(long user, int n);
}
......
package org.legrog.recommendation.process;
import org.springframework.stereotype.Component;
@Component
public class RecommenderFactory {
public Recommender build(String recommenderName, String filePath) {
Recommender recommender;
if (recommenderName.equals("cosine")) {
recommender = new CosineRecommender(filePath);
} else if (recommenderName.equals("funkSVD")) {
recommender = new FunkSVDRecommender(filePath);
} else if (recommenderName.equals("pearson")) {
recommender = new PearsonRecommender(filePath);
} else {
recommender = new SlopeOneRecommender(filePath);
}
return recommender;
}
}
......@@ -30,8 +30,7 @@ public class SlopeOneRecommender implements Recommender {
ItemRecommender irec;
@Override
public void Recommender(String filePath) {
public SlopeOneRecommender(String filePath) {
config = new LenskitConfiguration();
config.bind(ItemScorer.class).to(SlopeOneItemScorer.class);
......
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<!-- encoders are assigned the type
ch.qos.logback.classic.encoder.PatternLayoutEncoder by default -->
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.legrog" level="DEBUG"/>
<logger name="org.legrog.recommendation.process" level="TRACE"/>
<root level="warn">
<appender-ref ref="STDOUT" />
</root>
</configuration>
\ No newline at end of file