【问题标题】:Mahout Recomendaton engine recommending products and with its Quantity to customerMahout Recomendaton 引擎向客户推荐产品及其数量
【发布时间】:2014-09-01 07:58:30
【问题描述】:

我正在研究 mahout 推荐引擎用例。我预先计算了推荐并存储在数据库中。现在我计划向 .net 提供味觉休息服务。我的客户和产品有限。这是分销商级别的推荐用例。我的问题是,如果有新的分销商进来,我将如何向他提出建议。以及如何我向每个经销商建议推荐产品的数量。你们能给我一些指导吗。我会面临性能问题吗..?

【问题讨论】:

    标签: mahout recommendation-engine mahout-recommender


    【解决方案1】:

    一种方法是,当新用户到来时,从头开始为所有用户或仅为该用户预先计算推荐。您应该知道该用户也可能会更改其他用户的推荐。您是否经常需要进行预计算。

    但是,如果您的用户和项目数量有限,另一种方法是让在线推荐器实时计算推荐。如果您使用FileDataModel,有一种方法可以定期从新用户那里获取数据(参见书Mahout in Action)。如果你在内存数据模型中使用更快,你可以重写方法:setPreference(long userID, long itemID, float value)removePreference(long userID, long itemID),每当新用户来喜欢或删除一些项目时,你应该在你的数据模型上调用这些方法。

    编辑:基本上你可以得到GenericDataModel,并将它添加到方法setPreferenceremovePreference。这将是您的较低级别的数据模型。您可以通过在 reload() 方法中设置您的数据模型,然后使用 ReloadFromJDBCDataModel 包装它,如下所示:

    数据模型 newDelegateInMemory = 委托.hasPreferenceValues() ?新的 MutableDataModel(delegate.exportWithPrefs()) : 新的 MutableBooleanPrefDataModel(delegate.exportWithIDsOnly());

    被覆盖的方法:

    @Override
    public void setPreference(long userID, long itemID, float value) {
    
        userIDs.add(userID);
        itemIDs.add(itemID);
    
        setMinPreference(Math.min(getMinPreference(), value));
        setMaxPreference(Math.max(getMaxPreference(), value));
    
        Preference p = new GenericPreference(userID, itemID, value);
    
        // User preferences
        GenericUserPreferenceArray newUPref;
        int existingPosition = -1;
        if (preferenceFromUsers.containsKey(userID)) {
            PreferenceArray oldPref = preferenceFromUsers.get(userID);
            newUPref = new GenericUserPreferenceArray(oldPref.length() + 1);
            for (int i = 0; i < oldPref.length(); i++) {
                //If the item does not exist in the liked user items, add it!
                if(oldPref.get(i).getItemID()!=itemID){
                    newUPref.set(i, oldPref.get(i));
                }else{
                    //Otherwise remember the position
                    existingPosition = i;
                }
            }
            if(existingPosition>-1){
                //And change the preference value
                oldPref.set(existingPosition, p);
            }else{
                newUPref.set(oldPref.length(), p);
            }
        } else {
            newUPref = new GenericUserPreferenceArray(1);
            newUPref.set(0, p);
        }
        if(existingPosition == -1){
            preferenceFromUsers.put(userID, newUPref);
        }
    
        // Item preferences
        GenericItemPreferenceArray newIPref;
        existingPosition = -1;
        if (preferenceForItems.containsKey(itemID)) {
            PreferenceArray oldPref = preferenceForItems.get(itemID);
            newIPref = new GenericItemPreferenceArray(oldPref.length() + 1);
            for (int i = 0; i < oldPref.length(); i++) {
                if(oldPref.get(i).getUserID()!=userID){
                    newIPref.set(i, oldPref.get(i));
                }else{
                    existingPosition = i;
                }
            }
            if(existingPosition>-1){
                oldPref.set(existingPosition, p);
            }else{
                newIPref.set(oldPref.length(), p);
            }
        } else {
            newIPref = new GenericItemPreferenceArray(1);
            newIPref.set(0, p);
        }
        if(existingPosition == -1){
            preferenceForItems.put(itemID, newIPref);
        }   
    }
    
    @Override
    public void removePreference(long userID, long itemID) {
        // User preferences
        if (preferenceFromUsers.containsKey(userID)) {
            List<Preference> newPu = new ArrayList<Preference>();
            for (Preference p : preferenceFromUsers.get(userID)) {
                if(p.getItemID()!=itemID){
                    newPu.add(p);
                }       
            }
            preferenceFromUsers.remove(userID);
            preferenceFromUsers.put(userID, new GenericUserPreferenceArray(newPu)); 
        }
        if(preferenceFromUsers.get(userID).length()==0){
            preferenceFromUsers.remove(userID);
            userIDs.remove(userID); 
        }
        if (preferenceForItems.containsKey(itemID)) {
            List<Preference> newPi = new ArrayList<Preference>();
            for (Preference p : preferenceForItems.get(itemID)) {
                if(p.getUserID() != userID){
                    newPi.add(p);
                }   
            }
            preferenceForItems.remove(itemID);
            preferenceForItems.put(itemID, new GenericItemPreferenceArray(newPi));
        }   
        if(preferenceForItems.get(itemID).length()==0){
            //Not sure if this is needed, but it works without removing the item
            //preferenceForItems.remove(itemID);
            //itemIDs.remove(itemID);
        }
    }
    

    【讨论】:

    • 感谢 Dragan,目前我正在尝试使用 Rest 开发实时推荐引擎。我打算使用 Memory 数据模型。请您分享您实现的一个供我参考。
    【解决方案2】:

    如果您所说的“新经销商”是指您没有他们的数据,也没有历史数据。那么您就无法使用 Mahout 的推荐器进行推荐。

    一旦他们选择了其他项目,您就可以推荐其他项目。使用 Mahout 的“itemsimilarity”驱动程序计算目录中所有物品的相似项。然后,如果他们选择了一些东西,你可以推荐类似的东西。

    来自 itemsimilarity 驱动程序的项目可以作为列值存储在您的数据库中,其中包含每个项目的相似项目的 ID。然后,您可以使用搜索引擎对该列进行索引,并使用用户的第一顺序作为查询。这将返回实时个性化推荐,是 Mahout 人建议的最新方法。

    请参阅领先的 Mahout 数据科学家之一 Ted Dunning 对如何执行此操作的说明。 http://www.mapr.com/practical-machine-learning

    【讨论】:

    • 感谢您的建议。我明白您的意思。我的另一个疑问是我正在尝试使用 Java、Web 服务实现。我没有使用搜索引擎 (solr)。我需要使用 REST 将推荐引擎暴露给 .Net 跨平台。我的技术是 Mysql、Java Web 服务、Mahout。我是在朝着正确的方向前进,还是我错过了任何事情。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多