Java tutorial
/* * Copyright (c) 2002-2014, Mairie de Paris * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright notice * and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice * and the following disclaimer in the documentation and/or other materials * provided with the distribution. * * 3. Neither the name of 'Mairie de Paris' nor 'Lutece' nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * * License 1.0 */ package fr.paris.lutece.plugins.recommendation.service; import fr.paris.lutece.portal.service.database.AppConnectionService; import fr.paris.lutece.portal.service.util.AppLogService; import fr.paris.lutece.portal.service.util.AppPropertiesService; import fr.paris.lutece.util.pool.PoolManager; import org.apache.mahout.cf.taste.common.TasteException; import org.apache.mahout.cf.taste.impl.model.jdbc.MySQLJDBCDataModel; import org.apache.mahout.cf.taste.impl.neighborhood.ThresholdUserNeighborhood; 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.neighborhood.UserNeighborhood; import org.apache.mahout.cf.taste.recommender.RecommendedItem; import org.apache.mahout.cf.taste.recommender.UserBasedRecommender; import org.apache.mahout.cf.taste.similarity.UserSimilarity; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.sql.DataSource; /** * RecommendationService */ public final class RecommendationService { private static final String PROPERTY_LIST = "recommendation.recommendersList"; private static final String PREFIX = "recommendation.recommender."; private static final String PROPERTY_DATASOURCE = ".dataSource"; private static final String PROPERTY_PREF_TABLE = ".preferenceTable"; private static final String PROPERTY_USER_ID_COL = ".userIDColumn"; private static final String PROPERTY_ITEM_ID_COL = ".itemIDColumn"; private static final String PROPERTY_PREF_COL = ".preferenceColumn"; private static final List<RecommendedItem> LIST_NO_RECOMMENDATION = new ArrayList<RecommendedItem>(); private static Map<String, UserBasedRecommender> _mapRecommenders; private static RecommendationService _singleton; /** Private constructor */ private RecommendationService() { } /** * Provides the unique instance * @return the unique instance */ public static synchronized RecommendationService instance() { if (_singleton == null) { _singleton = new RecommendationService(); init(); } return _singleton; } /** * Initialize the service */ private static void init() { _mapRecommenders = new HashMap<String, UserBasedRecommender>(); String strList = AppPropertiesService.getProperty(PROPERTY_LIST); String[] recommenders = strList.split(","); for (String strRecommender : recommenders) { UserBasedRecommender recommender = initRecommender(strRecommender.trim()); _mapRecommenders.put(strRecommender, recommender); AppLogService.info("New Mahout Recommender registered '" + strRecommender + "'"); } } /** * Provides a list of recommended items for a given user based on a recommender * @param strRecommender The recommender name * @param lUserID The User's ID * @param nCount The number of recommendation whished * @return The list of recommended items */ public List<RecommendedItem> getRecommendations(String strRecommender, long lUserID, int nCount) { UserBasedRecommender recommender = _mapRecommenders.get(strRecommender); if (recommender != null) { try { return recommender.recommend(lUserID, nCount); } catch (TasteException ex) { AppLogService.error("Error getting recommendation : " + ex.getMessage(), ex); } } return LIST_NO_RECOMMENDATION; } /** * Initialize a recommender * @param strName The recommender name * @return The recommender */ private static UserBasedRecommender initRecommender(String strName) { try { AppLogService.info("Initialize Mahout JDBC DataModel for Recommender '" + strName + "'"); String strKeyPrefix = PREFIX + strName; String strDataSource = AppPropertiesService.getProperty(strKeyPrefix + PROPERTY_DATASOURCE); AppLogService.info("- DataSource = " + strDataSource); String strPrefTable = AppPropertiesService.getProperty(strKeyPrefix + PROPERTY_PREF_TABLE); AppLogService.info("- Table = " + strPrefTable); String strUserIdColumn = AppPropertiesService.getProperty(strKeyPrefix + PROPERTY_USER_ID_COL); AppLogService.info("- User ID Column = " + strUserIdColumn); String strItemIdColumn = AppPropertiesService.getProperty(strKeyPrefix + PROPERTY_ITEM_ID_COL); AppLogService.info("- Item ID Column = " + strItemIdColumn); String strPrefColumn = AppPropertiesService.getProperty(strKeyPrefix + PROPERTY_PREF_COL); AppLogService.info("- Pref Column = " + strPrefColumn); PoolManager pm = AppConnectionService.getPoolManager(); DataSource dataSource = pm.getDataSource(strDataSource); DataModel model = new MySQLJDBCDataModel(dataSource, strPrefTable, strUserIdColumn, strItemIdColumn, strPrefColumn, null); UserSimilarity similarity = new PearsonCorrelationSimilarity(model); UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.1, similarity, model); return new GenericUserBasedRecommender(model, neighborhood, similarity); } catch (TasteException ex) { AppLogService.error("Error loading recommender : " + ex.getMessage(), ex); } return null; } }