de.lemo.dms.processing.questions.QFrequentPathsApriori.java Source code

Java tutorial

Introduction

Here is the source code for de.lemo.dms.processing.questions.QFrequentPathsApriori.java

Source

/**
 * File ./src/main/java/de/lemo/dms/processing/questions/QFrequentPathsApriori.java
 * Lemo-Data-Management-Server for learning analytics.
 * Copyright (C) 2015
 * Leonard Kappe, Andreas Pursian, Sebastian Schwarzrock, Boris Wenzlaff
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
**/

/**
 * File ./main/java/de/lemo/dms/processing/questions/QFrequentPathsApriori.java
 * Date 2013-01-24
 * Project Lemo Learning Analytics
 */

package de.lemo.dms.processing.questions;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.ws.rs.FormParam;
import javax.ws.rs.POST;
import javax.ws.rs.Path;

import org.hibernate.Criteria;
import org.hibernate.Session;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import de.lemo.dms.core.config.ServerConfiguration;
import de.lemo.dms.db.IDBHandler;
import de.lemo.dms.db.mapping.abstractions.ILearningObject;
import de.lemo.dms.db.mapping.abstractions.ILog;
import de.lemo.dms.processing.FrequentPath;
import de.lemo.dms.processing.MetaParam;
import de.lemo.dms.processing.Question;
import de.lemo.dms.processing.StudentHelper;
import de.lemo.dms.processing.resulttype.ResultListUserPathGraph;
import de.lemo.dms.processing.resulttype.UserPathLink;
import de.lemo.dms.processing.resulttype.UserPathNode;
import de.lemo.dms.processing.resulttype.UserPathObject;

/**
 * Reads the path data from the database and using a algorithm to find frequent paths
 * 
 * @author Sebastian Schwarzrock
 */
@Path("frequentPathsApriori")
public class QFrequentPathsApriori extends Question {

    private Map<Integer, ILog> idToLogM = new HashMap<Integer, ILog>();
    private Map<Integer, List<Long>> requests = new HashMap<Integer, List<Long>>();
    private Map<Integer, Integer> idToInternalId = new HashMap<Integer, Integer>();
    private Map<Integer, Integer> internalIdToId = new HashMap<Integer, Integer>();
    private ArrayList<Integer> objInd = new ArrayList<Integer>();
    private int userCount = 0;

    @POST
    public ResultListUserPathGraph compute(@FormParam(MetaParam.COURSE_IDS) final List<Long> courses,
            @FormParam(MetaParam.USER_IDS) final List<Long> users,
            @FormParam(MetaParam.TYPES) final List<String> types,
            @FormParam(MetaParam.MIN_LENGTH) final Long minLength,
            @FormParam(MetaParam.MAX_LENGTH) final Long maxLength,
            @FormParam(MetaParam.MIN_SUP) final Double minSup,
            @FormParam(MetaParam.START_TIME) final Long startTime,
            @FormParam(MetaParam.END_TIME) final Long endTime, @FormParam(MetaParam.GENDER) final List<Long> gender,
            @FormParam(MetaParam.LEARNING_OBJ_IDS) final List<Long> learningObjects) {

        validateTimestamps(startTime, endTime);
        final ArrayList<UserPathNode> nodes = Lists.newArrayList();
        final ArrayList<UserPathLink> links = Lists.newArrayList();
        logger.info(startTime + " " + endTime);

        if (logger.isDebugEnabled()) {
            if ((courses != null) && (courses.size() > 0)) {
                StringBuffer buffer = new StringBuffer();
                buffer.append("Parameter list: Courses: " + courses.get(0));
                for (int i = 1; i < courses.size(); i++) {
                    buffer.append(", " + courses.get(i));
                }
                logger.debug(buffer.toString());
            }
            if ((users != null) && (users.size() > 0)) {
                StringBuffer buffer = new StringBuffer();
                buffer.append("Parameter list: Users: " + users.get(0));
                for (int i = 1; i < users.size(); i++) {
                    buffer.append(", " + users.get(i));
                }
                logger.debug(buffer.toString());
            }
            if ((types != null) && (types.size() > 0)) {
                StringBuffer buffer = new StringBuffer();
                buffer.append("Parameter list: Types: : " + types.get(0));
                for (int i = 1; i < types.size(); i++) {
                    buffer.append(", " + types.get(i));
                }
                logger.debug(buffer.toString());
            }
            if ((minLength != null) && (maxLength != null) && (minLength < maxLength)) {
                logger.debug("Parameter list: Minimum path length: : " + minLength);
                logger.debug("Parameter list: Maximum path length: : " + maxLength);
            }
            logger.debug("Parameter list: Minimum Support: : " + minSup);
            logger.debug("Parameter list: Start time: : " + startTime);
            logger.debug("Parameter list: End time: : " + endTime);
        }

        final IDBHandler dbHandler = ServerConfiguration.getInstance().getMiningDbHandler();

        final Session session = dbHandler.getMiningSession();
        List<List<Integer>> list = generateList(courses, users, types, minLength, maxLength, startTime, endTime,
                session, gender, learningObjects);

        List<List<List<Integer>>> patterns = FrequentPath.apriori(list, minSup.doubleValue());
        final LinkedHashMap<String, UserPathObject> pathObjects = Maps.newLinkedHashMap();
        Long pathId = 0L;

        for (int i = patterns.size() - 1; i >= 0; i--) {
            logger.info("Found " + patterns.get(i).size() + " paths of length " + patterns.get(i).get(0).size());
            for (int j = 0; j < patterns.get(i).size(); j++) {

                String predecessor = null;
                Long absSup = (long) (minSup * userCount) + 1;
                pathId++;
                for (int k = 0; k < patterns.get(i).get(j).size(); k++) {
                    final String posId = String.valueOf(pathObjects.size());
                    int obj = patterns.get(i).get(j).get(k);
                    final ILog ilo = this.idToLogM.get(objInd.get(obj));

                    if (predecessor != null) {
                        pathObjects.put(posId,
                                new UserPathObject(posId, ilo.getLearning().getTitle(), absSup,
                                        ilo.getClass().getSimpleName(), 0d, ilo.getPrefix(), pathId,
                                        Long.valueOf(this.requests.get(obj).size()),
                                        Long.valueOf(new HashSet<Long>(this.requests.get(obj)).size())));

                        // Increment or create predecessor edge
                        pathObjects.get(predecessor).addEdgeOrIncrement(posId);
                    } else {
                        pathObjects.put(posId,
                                new UserPathObject(posId, ilo.getLearning().getTitle(), absSup,
                                        ilo.getClass().getSimpleName(), 0d, ilo.getPrefix(), pathId,
                                        Long.valueOf(this.requests.get(obj).size()),
                                        Long.valueOf(new HashSet<Long>(this.requests.get(obj)).size())));
                    }
                    predecessor = posId;
                }
            }
        }
        for (final UserPathObject pathEntry : pathObjects.values()) {

            final UserPathObject path = pathEntry;
            path.setWeight(path.getWeight());
            path.setPathId(pathEntry.getPathId());
            nodes.add(new UserPathNode(path, true));
            final String sourcePos = path.getId();

            for (final Entry<String, Integer> linkEntry : pathEntry.getEdges().entrySet()) {
                final UserPathLink link = new UserPathLink();
                link.setSource(sourcePos);
                link.setPathId(path.getPathId());
                link.setTarget(linkEntry.getKey());
                link.setValue(String.valueOf(linkEntry.getValue()));
                links.add(link);
            }
        }

        this.requests.clear();
        this.idToLogM.clear();
        this.internalIdToId.clear();
        this.idToInternalId.clear();

        logger.info("Found " + pathId + " paths.");
        session.close();
        return new ResultListUserPathGraph(nodes, links);
    }

    /**
     * Generates the necessary list containing the sequences (user paths) for the algorithm
     * 
     * @param courses
     *            Course-Ids
     * @param users
     *            User-Ids
     * @param starttime
     *            Start time
     * @param endtime
     *            End time
     * @return The path to the generated file
     */
    @SuppressWarnings("unchecked")
    public List<List<Integer>> generateList(final List<Long> courses, List<Long> users, final List<String> types,
            final Long minLength, final Long maxLength, final Long starttime, final Long endtime, Session session,
            List<Long> gender, List<Long> learningObjects) {

        final List<List<Integer>> result = new ArrayList<List<Integer>>();
        final boolean hasBorders = (minLength != null) && (maxLength != null) && (maxLength > 0)
                && (minLength < maxLength);
        final boolean hasTypes = (types != null) && (types.size() > 0);
        Map<Long, ILearningObject> objects = new HashMap<Long, ILearningObject>();

        Criteria criteria;
        if (users == null || users.size() == 0) {
            users = new ArrayList<Long>(StudentHelper.getCourseStudentsAliasKeys(courses, gender).values());
        } else {
            Map<Long, Long> userMap = StudentHelper.getCourseStudentsAliasKeys(courses, gender);
            List<Long> tmp = new ArrayList<Long>();
            for (int i = 0; i < users.size(); i++) {
                tmp.add(userMap.get(users.get(i)));
            }
            users = tmp;
        }

        criteria = session.createCriteria(ILog.class, "log");
        if (courses.size() > 0) {
            criteria.add(Restrictions.in("log.course.id", courses));
        }
        if (users.size() > 0) {
            criteria.add(Restrictions.in("log.user.id", users));
        }
        if (!learningObjects.isEmpty()) {
            criteria.add(Restrictions.in("log.learning.id", learningObjects));
        }
        criteria.add(Restrictions.between("log.timestamp", starttime, endtime));
        criteria.addOrder(Property.forName("log.timestamp").asc());

        final ArrayList<ILog> list = (ArrayList<ILog>) criteria.list();
        Map<Long, List<Integer>> userPaths = new HashMap<Long, List<Integer>>();

        logger.debug("Found " + list.size() + " logs.");
        long id = -1;
        List<Integer> path = new ArrayList<Integer>();
        for (ILog log : list) {
            Integer pos = ((Long) log.getLearning().getId()).intValue();

            if (!hasTypes || types.contains(log.getLearning().getLOType())) {
                if (!objInd.contains(pos)) {
                    objInd.add(pos);
                }
                if (idToLogM.get(pos) == null) {
                    idToLogM.put(pos, log);
                }
                if (this.requests.get(objInd.indexOf(pos)) == null) {
                    final ArrayList<Long> us = new ArrayList<Long>();
                    us.add(log.getUser().getId());
                    this.requests.put(objInd.indexOf(pos), us);
                } else {
                    this.requests.get(objInd.indexOf(pos)).add(log.getUser().getId());
                }

                if (userPaths.get(log.getUser().getId()) == null) {
                    List<Integer> l = new ArrayList<Integer>();
                    l.add(objInd.indexOf(pos));
                    userPaths.put(log.getUser().getId(), l);
                } else {
                    userPaths.get(log.getUser().getId()).add(objInd.indexOf(pos));
                }
            }
            /*if(!hasTypes || types.contains(log.getLearning().getLOType()))
            {
               if(objects.get(log.getLearning()) == null)
                  objects.put(log.getLearning().getId(), log.getLearning());
               if(id != log.getUser().getId())
               {
                  id = log.getUser().getId();
                  if(!hasBorders || (path.size() < maxLength && path.size() > minLength))
                  {
              List<Integer> userPath = new ArrayList<Integer>();
              for(int i = 0; i < path.size(); i++)
              {
                 userPath.add(path.get(i).intValue());   
              }
              if(userPath.size() > 0)
                 result.add(userPath);
                  }
                  path = new ArrayList<Integer>();
               }
               if(!objInd.contains(pos))
               {
                  objInd.add(pos);
               }
               if(idToLogM.get(pos) == null )
               {
                  idToLogM.put(pos, log);
               }
               if (this.requests.get(objInd.indexOf(pos)) == null)
               {
                  final ArrayList<Long> us = new ArrayList<Long>();
                  us.add(log.getUser().getId());
                  this.requests.put(objInd.indexOf(pos), us);
               } else {
                  this.requests.get(objInd.indexOf(pos)).add(
                 log.getUser().getId());
               }
               path.add(objInd.indexOf(pos));
            }
                  */
        }

        for (List<Integer> uhis : userPaths.values()) {
            result.add(uhis);
        }

        userCount = result.size();
        logger.debug("Found " + result.size() + " user paths.");
        return result;
    }
}