javasensei.db.managments.RankingManager.java Source code

Java tutorial

Introduction

Here is the source code for javasensei.db.managments.RankingManager.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package javasensei.db.managments;

import com.mongodb.BasicDBObjectBuilder;
import com.mongodb.DBCollection;
import com.mongodb.DBCursor;
import com.mongodb.DBObject;
import com.mongodb.QueryBuilder;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Timer;
import java.util.TimerTask;
import java.util.logging.Level;
import java.util.logging.Logger;
import javasensei.db.Connection;
import javasensei.estudiante.ModeloEstudiante;
import javasensei.exceptions.JavaException;
import org.apache.mahout.cf.taste.common.NoSuchUserException;
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.GenericPreference;
import org.apache.mahout.cf.taste.impl.model.GenericUserPreferenceArray;
import org.apache.mahout.cf.taste.impl.model.file.FileDataModel;
import org.apache.mahout.cf.taste.impl.neighborhood.NearestNUserNeighborhood;
import org.apache.mahout.cf.taste.impl.neighborhood.ThresholdUserNeighborhood;
import org.apache.mahout.cf.taste.impl.recommender.AbstractRecommender;
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.Preference;
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.similarity.UserSimilarity;

/**
 *
 * @author Rock
 */
public class RankingManager {

    private DBCollection ejercicios = Connection.getCollection().get(CollectionsDB.EJERCICIOS);
    private DBCollection rankingEjercicios = Connection.getCollection().get(CollectionsDB.RANKING_EJERCICIOS);

    private DBCollection recursos = Connection.getCollection().get(CollectionsDB.RECURSOS);
    private DBCollection rankingRecursos = Connection.getCollection().get(CollectionsDB.RANKING_RECURSOS);;

    private ModeloEstudiante estudiante;

    protected static GenericUserBasedRecommender recommenderEjercicios;
    //protected static RandomRecommender randomRecommender; //No funciona el recommender no se porque FGH
    protected static GenericUserBasedRecommender recommenderRecursos;

    protected static boolean updateModelExcercises = true;
    protected static boolean updateModelResources = true;

    private static Timer timer = new Timer();

    static {
        timer.scheduleAtFixedRate(new TimerTask() {

            @Override
            public void run() {
                updateModelExcercises = true;
                updateModelResources = true;
            }
        }, 0, 1800000);
    }

    public RankingManager(ModeloEstudiante estudiante) {
        this(estudiante, true, true);
    }

    public RankingManager(ModeloEstudiante estudiante, boolean updateExercises, boolean updateResources) {
        this.estudiante = estudiante;
        if (recommenderEjercicios == null && updateExercises) {
            updateDataModelEjercicios();
        }
        if (recommenderRecursos == null && updateResources) {
            updateDataModelRecursos();
        }
    }

    public String getRecommenderResources(int cantidad, boolean random) {
        return getRecommenders(rankingRecursos, recommenderRecursos, cantidad, random);
    }

    private int getIdLeccion(int idEjercicio) {
        return new Double(
                ejercicios
                        .findOne(QueryBuilder.start("id").is(idEjercicio).get(),
                                QueryBuilder.start("_id").is(0).put("idLeccion").is(1).get())
                        .get("idLeccion").toString()).intValue();
    }

    public String getRecommenderResources(int cantidad, int idEjercicio) {
        String result = "[]";

        try {
            int idLeccionPrincipal = getIdLeccion(idEjercicio);

            List<DBObject> listaRecursos = recursos
                    .find(QueryBuilder.start("id").in(getRecommendersItemsIDAsArray(recommenderRecursos, cantidad))
                            .put("idLeccion").is(idLeccionPrincipal).get())
                    .toArray();

            listaRecursos.replaceAll((DBObject object) -> {
                object.put("ranking",
                        rankingRecursos.findOne(
                                QueryBuilder.start("idRecurso").is(object.get("id")).put("idAlumno")
                                        .is(estudiante.getId()).get(),
                                QueryBuilder.start("_id").is(0).put("ranking").is(1).get()).get("ranking"));

                return object;
            });

            result = listaRecursos.toString();
        } catch (TasteException ex) {
            Logger.getLogger(RankingManager.class.getName()).log(Level.SEVERE, null, ex);
        }

        return result;
    }

    /**
     * Metodo que obtiene recomendaciones de los ejercicios
     *
     * @param cantidad Cantidad de recomendaciones (No necesariamente devuelva
     * la cantidad pedida)
     * @param random Verdadero si necesita que genere un item aleatoriamente en
     * caso de no encontrar alguna recomendacion
     * @return JSON de los ejercicios
     */
    public String getRecommendersExercises(int cantidad, boolean random) {
        return getRecommenders(rankingEjercicios, recommenderEjercicios, cantidad, random);
    }

    protected Integer[] getRecommendersItemsIDAsArray(AbstractRecommender recommender, int cantidad)
            throws TasteException {
        List<Integer> listId = new ArrayList<>();

        for (RecommendedItem item : getRecommendersItems(recommender, cantidad)) {
            listId.add(new Long(item.getItemID()).intValue());
        }

        return listId.toArray(new Integer[listId.size()]);
    }

    protected List<RecommendedItem> getRecommendersItems(AbstractRecommender recommender, int cantidad)
            throws TasteException {
        return recommender.recommend(estudiante.getId(), cantidad);
    }

    protected String getRecommenders(DBCollection collection, AbstractRecommender recommender, int cantidad,
            boolean random) {
        String result = "{}";

        List<RecommendedItem> recommenders = new ArrayList<>();
        try {
            List<Long> array = new ArrayList();

            try {
                recommenders = getRecommendersItems(recommender, cantidad);//recommenderEjercicios.recommend(estudiante.getId(), cantidad); //5 Recomendaciones
            } catch (Exception ex) {
                System.out.println("El usuario no existe aun en el modelo de datos: " + estudiante.getId());
            }
            //Se agrega un item aleatorio...
            if (random && recommenders.size() < 1) { //RandomRecommender no funciona....

                double number = collection.count();

                DBObject object = collection.find().limit(1).skip((int) Math.floor(Math.random() * number)).next();

                array.add(Math.round(Double.parseDouble(object.get("idEjercicio").toString())));
            }

            //Las recomendaciones se transforman en json array
            for (RecommendedItem item : recommenders) {
                array.add(item.getItemID());
            }

            //Se crea un json array con los id obtenidos de los ejercicios
            result = ejercicios.find(QueryBuilder.start("id").in(array).get()).toArray().toString();
        } catch (Exception ex) {
            JavaException.printMessage(ex, System.out);
        }

        return result;
    }

    public FastByIDMap buildDataModel(DBCollection rankings, String fieldNameUserId, String fieldNameItemId,
            String fieldNameValue) {
        //Obtenemos todos los ranking actuales y los almacenamos en el archivo csv
        DBCursor cursor = rankings.find();
        FastByIDMap<PreferenceArray> userData = new FastByIDMap<>();

        if (cursor.count() > 0) {

            List<Preference> preferences = new ArrayList<>();
            Long idLastUser = null;

            while (cursor.hasNext()) {
                DBObject object = cursor.next();
                Long idItem = new Double(object.get(fieldNameItemId).toString()).longValue();
                Long idCurrentUser = new Double(object.get(fieldNameUserId).toString()).longValue();
                Float value = new Float(object.get(fieldNameValue).toString());

                if (idLastUser == null || !idCurrentUser.equals(idLastUser)) {
                    if (preferences.size() > 0) {
                        userData.put(idLastUser, new GenericUserPreferenceArray(preferences));
                        preferences.clear();
                    }
                    idLastUser = idCurrentUser;
                }

                preferences.add(new GenericPreference(idLastUser, idItem, value));

                if (!cursor.hasNext()) {
                    userData.put(idLastUser, new GenericUserPreferenceArray(preferences));
                }
            }

            System.out.println(userData);
        }

        return userData;
    }

    private void updateDataModelEjercicios() {
        try {
            if (updateModelExcercises) {
                //El archivo es pasado al dataModel
                DataModel dataModel = new GenericDataModel(
                        buildDataModel(rankingEjercicios, "idAlumno", "idEjercicio", "ranking"));
                //Creamos la correlacion de pearson
                PearsonCorrelationSimilarity correlation = new PearsonCorrelationSimilarity(dataModel);
                UserNeighborhood neigh = new NearestNUserNeighborhood(5, correlation, dataModel);
                recommenderEjercicios = new GenericUserBasedRecommender(dataModel, neigh, correlation);
                //randomRecommender = new RandomRecommender(dataModel);

                updateModelExcercises = false;
            }
        } catch (Exception ex) {
            Logger.getLogger(RankingManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void updateDataModelRecursos() {
        try {
            if (updateModelResources) {
                //El archivo es pasado al dataModel
                DataModel dataModel = new GenericDataModel(
                        buildDataModel(rankingRecursos, "idAlumno", "idRecurso", "ranking"));
                //Creamos la correlacion de pearson
                UserSimilarity correlation = new PearsonCorrelationSimilarity(dataModel);
                UserNeighborhood neigh = new NearestNUserNeighborhood(5, correlation, dataModel); //new ThresholdUserNeighborhood(0.1, correlation, dataModel);
                recommenderRecursos = new GenericUserBasedRecommender(dataModel, neigh, correlation);

                //csv.deleteOnExit();
                updateModelResources = false;
            }
        } catch (Exception ex) {
            Logger.getLogger(RankingManager.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public boolean colocarRankingDefault() {
        boolean result = false;

        try {
            QueryBuilder query = QueryBuilder.start("id").notIn(rankingEjercicios.distinct("idEjercicio",
                    QueryBuilder.start("idAlumno").is(estudiante.getId()).get()));

            //Obtenemos los id de ejercicios que no estan rankeados por el alumno
            //Se colocara un valor 2 de default para dicho ranking, de acuerdo a la escala de LIKERT
            List<DBObject> objects = ejercicios.find(query.get()).toArray();

            if (!objects.isEmpty()) {
                List<DBObject> listObjects = new ArrayList<>();

                for (DBObject object : objects) {
                    listObjects.add(BasicDBObjectBuilder.start().add("idEjercicio", object.get("id"))
                            .add("idAlumno", estudiante.getId()).add("ranking", 2) //2 De acuerdo a la escala
                            .get());
                }

                rankingEjercicios.insert(listObjects);

                updateDataModelEjercicios();
            }

            //Mismo proceso para ranking de recursos
            QueryBuilder queryRecursos = QueryBuilder.start("id").notIn(rankingRecursos.distinct("idRecurso",
                    QueryBuilder.start("idAlumno").is(estudiante.getId()).get()));

            List<DBObject> idRecursos = recursos.find(queryRecursos.get()).toArray();

            if (!idRecursos.isEmpty()) {
                List<DBObject> listRankingRecursosSave = new ArrayList<>();

                for (DBObject object : idRecursos) {
                    listRankingRecursosSave.add(BasicDBObjectBuilder.start().add("idRecurso", object.get("id"))
                            .add("idAlumno", estudiante.getId()).add("ranking", 2) //2 De acuerdo a la escala
                            .get());
                }

                rankingRecursos.insert(listRankingRecursosSave);

                updateDataModelRecursos();
            }

            result = true;

        } catch (Exception ex) {
            System.err.println(ex);
        }

        return result;
    }
}