Mahout预先计算的项目项目相似性 - 慢推荐

时间:2013-09-03 08:53:17

标签: mahout recommendation-engine mahout-recommender

我在Mahout中遇到与预先设定的项目项相似性的性能问题。

我有400万用户,项目数量大致相同,用户项目偏好约为1亿。我想基于文档的TF-IDF向量的余弦相似性来进行基于内容的推荐。 由于计算速度很慢,我预先计算了前50个最相似文档的成对相似性,如下所示:

  1. 我使用seq2sparse生成TF-IDF向量。
  2. 我使用mahout rowId生成mahout矩阵
  3. 我使用mahout rowSimilarity -i INPUT/matrix -o OUTPUT -r 4587604 --similarityClassname SIMILARITY_COSINE -m 50 -ess来制作前50个最相似的文档
  4. 我使用hadoop预先计算所有这些。对于400万件产品,产量仅为2.5GB。

    然后我使用Collection<GenericItemSimilarity.ItemItemSimilarity> corrMatrix = ...将Reducer生成的文件内容加载到docIndex以解码文档的ID。它们已经是整数,但是rowId已经从1开始解码它们,所以我必须把它取回来。

    对于推荐,我使用以下代码:

    ItemSimilarity similarity = new GenericItemSimilarity(correlationMatrix);
    
    CandidateItemsStrategy candidateItemsStrategy = new SamplingCandidateItemsStrategy(1, 1, 1, model.getNumUsers(),  model.getNumItems());
    MostSimilarItemsCandidateItemsStrategy mostSimilarItemsCandidateItemsStrategy = new SamplingCandidateItemsStrategy(1, 1, 1, model.getNumUsers(),  model.getNumItems());
    
    Recommender recommender = new GenericItemBasedRecommender(model, similarity, candidateItemsStrategy, mostSimilarItemsCandidateItemsStrategy);
    

    我正在尝试使用有限的数据模型(1.6M项目),但我在内存中加载了所有项目项目成对相似性。我设法使用40GB加载主内存中的所有内容。

    当我想为一个用户做推荐时

    Recommender cachingRecommender = new CachingRecommender(recommender);
    List<RecommendedItem> recommendations = cachingRecommender.recommend(userID, howMany);
    

    推荐过程所用的时间为554.938583083秒,此外它没有产生任何推荐。现在我真的很关心推荐的表现。我使用了CandidateItemsStrategyMostSimilarItemsCandidateItemsStrategy的数字,但我的表现没有任何改善。

    是不是预先计算了所有想要加速推荐过程的想法? 有人可以帮助我,告诉我我做错了什么,我做错了什么。 另外,为什么在主存储器中加载parwise相似性会以指数方式爆炸?在Collection<GenericItemSimilarity.ItemItemSimilarity> mahout矩阵中的40GB主内存中加载了2.5GB的文件。我知道文件是使用IntWritableVectorWritable hashMap键值序列化的,并且键必须为ItemItemSimilarity矩阵中的每个向量值重复,但这有点太多了,你不觉得吗?

    提前谢谢。

1 个答案:

答案 0 :(得分:1)

我已经纠正了使用Collection计算推荐值所需的时间。显然,我已将long startTime = System.nanoTime();放在我的代码顶部,而不是List<RecommendedItem> recommendations = cachingRecommender.recommend(userID, howMany);之前。这计算了将数据集和预先计算的项目项相似性加载到主存储器中所需的时间。

然而,我站在记忆消耗的背后。我使用自定义ItemSimilarity并加载预先计算的相似度的HashMap<Long, HashMap<Long, Double>来改进它。我使用了宝库来减少空间需求。

这是一个详细代码。自定义ItemSimilarity:

public class TextItemSimilarity implements ItemSimilarity{

    private TLongObjectHashMap<TLongDoubleHashMap> correlationMatrix;

    public WikiTextItemSimilarity(TLongObjectHashMap<TLongDoubleHashMap> correlationMatrix){
        this.correlationMatrix = correlationMatrix;
    }

    @Override
    public void refresh(Collection<Refreshable> alreadyRefreshed) {
    }

    @Override
    public double itemSimilarity(long itemID1, long itemID2) throws TasteException {
        TLongDoubleHashMap similarToItemId1 = correlationMatrix.get(itemID1);   
        if(similarToItemId1 != null && !similarToItemId1.isEmpty() &&  similarToItemId1.contains(itemID2)){
            return similarToItemId1.get(itemID2);
        }   
        return 0;
    }
    @Override
    public double[] itemSimilarities(long itemID1, long[] itemID2s) throws TasteException {
        double[] result = new double[itemID2s.length];
        for (int i = 0; i < itemID2s.length; i++) {
            result[i] = itemSimilarity(itemID1, itemID2s[i]);
        }
        return result;
    }
    @Override
    public long[] allSimilarItemIDs(long itemID) throws TasteException {
        return correlationMatrix.get(itemID).keys();
    }
}

使用Collection<GenericItemSimilarity.ItemItemSimilarity>的总内存消耗和我的数据集为30GB,使用TLongObjectHashMap<TLongDoubleHashMap>和自定义TextItemSimilarity时,空间要求为17GB。 使用Collection<GenericItemSimilarity.ItemItemSimilarity>时间性能为0.05秒,使用TLongObjectHashMap<TLongDoubleHashMap>时间性能为0.07秒。另外,我相信使用CandidateItemsStrategyMostSimilarItemsCandidateItemsStrategy

可以在效果方面发挥重要作用

我想如果你想节省一些空间使用特洛伊HashMap,如果你想要更好的性能,你可以使用Collection<GenericItemSimilarity.ItemItemSimilarity>