/* * Sifarish: Recommendation Engine * Author: Pranab Ghosh * * Licensed under the Apache License, Version 2.0 (the "License"); you * may not use this file except in compliance with the License. You may * obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or * implied. See the License for the specific language governing * permissions and limitations under the License. */ package org.sifarish.common; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.util.ToolRunner; import org.chombo.mr.Transformer; import org.chombo.transformer.AttributeTransformer; /** * Per user item novelty. Novelty has an inverse relationship with user's engagement * with an item. Input: userID, itemID, rating, rating distr * @author pranab * */ public class IndividualNovelty extends Transformer { @Override public int run(String[] args) throws Exception { return start("Individual novelty MR", IndividualNovelty.class, IndividualNovelty.NoveltyMapper.class, args); } /** * @author pranab * */ public static class NoveltyMapper extends Transformer.TransformerMapper { /* (non-Javadoc) * @see org.chombo.mr.Transformer.TransformerMapper#setup(org.apache.hadoop.mapreduce.Mapper.Context) */ protected void setup(Context context) throws IOException, InterruptedException { super.setup(context); Configuration config = context.getConfiguration(); String strategy = config.get("inn.novelty.gen.strategy", "selfInformation"); int maxRating = config.getInt("inn.rating.scale", 100); if (strategy.equals("selfInformation")) { //based on rating distribution int engaementDistrScale = config.getInt("inn.engaement.distr.scale", 1000); registerTransformers(2, new Transformer.NullTransformer()); registerTransformers(3, new IndividualNovelty.SelfInformation(engaementDistrScale, maxRating)); } else if (strategy.equals("nonLinearInverse")) { //based on rating double param = config.getFloat("inn.quadratic.param", (float) 0.8); registerTransformers(2, new IndividualNovelty.NonLinearInverse(maxRating, param)); registerTransformers(3, new Transformer.NullTransformer()); } } } /** * @author pranab * */ public static class SelfInformation extends AttributeTransformer { private double maxNovelty; private int maxRating; public SelfInformation(int engaementDistrScale, int maxRating) { maxNovelty = log2(engaementDistrScale); this.maxRating = maxRating; } private double log2(int val) { return Math.log(val) / Math.log(2); } @Override public String[] tranform(String value) { //from rating distr to novelty int rating = Integer.parseInt(value); rating = rating == 0 ? 1 : rating; Integer novelty = (int)((1.0 - log2(rating) / maxNovelty) * maxRating); String[] transformed = new String[1]; transformed[0] = novelty.toString(); return transformed; } } /** * Second degree polynomial * @author pranab * */ public static class NonLinearInverse extends AttributeTransformer { private int maxRating; private double k0, k1, k2; private int maxRatingInData; public NonLinearInverse(int maxRating, double param) { this.maxRating = maxRating; k0 = maxRating; k1 = -3 + 2 * param; k2 = 2 * (1 - param) / maxRating; } public NonLinearInverse(int maxRating, double param, int maxRatingInData) { this(maxRating, param); this.maxRatingInData = maxRatingInData; } @Override public String[] tranform(String value) { //from rating to novelty int rating = Integer.parseInt(value); //scale it if (maxRatingInData > 0) { rating = (rating * maxRating) / maxRatingInData; } Integer novelty = null; if (rating == 0) { novelty = maxRating; } else if (rating == maxRating){ novelty = 0; } else { novelty = (int)(k2 * rating * rating + k1 * rating + k0); } String[] transformed = new String[1]; transformed[0] = novelty.toString(); return transformed; } } /** * @param args * @throws Exception */ public static void main(String[] args) throws Exception { int exitCode = ToolRunner.run(new IndividualNovelty(), args); System.exit(exitCode); } }