1

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

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

  1. 我曾经seq2sparse生成 TF-IDF 向量。
  2. 我曾经mahout rowId制作过驯象师矩阵
  3. 我使用 mahoutrowSimilarity -i INPUT/matrix -o OUTPUT -r 4587604 --similarityClassname SIMILARITY_COSINE -m 50 -ess生成了前 50 个最相似的文档

我使用 hadoop 预先计算所有这些。对于 400 万个项目,输出仅为 2.5GB。

然后我将reducers生成的文件的内容加载到Collection<GenericItemSimilarity.ItemItemSimilarity> corrMatrix = ...使用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);

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

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

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

推荐过程的经过时间是554.938583083秒,而且它没有产生任何推荐。现在我真的很担心推荐的表现。我玩过 和 的数字CandidateItemsStrategyMostSimilarItemsCandidateItemsStrategy但性能没有任何改进。

预计算所有东西的想法难道不是为了加快推荐过程吗?有人可以帮助我并告诉我我做错了什么以及我做错了什么。另外,为什么在主内存中加载 parwise 相似性会呈指数级增长?Collection<GenericItemSimilarity.ItemItemSimilarity>在mahout 矩阵的 40GB 主内存中加载了 2.5GB 的文件?我知道文件是使用IntWritable, VectorWritablehashMap 键值序列化的,并且对于ItemItemSimilarity矩阵中的每个向量值都必须重复该键,但这有点太多了,你不觉得吗?

先感谢您。

4

1 回答 1

2

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

但是我支持内存消耗。我通过使用自定义ItemSimilarity和加载HashMap<Long, HashMap<Long, Double>预先计算的相似性对其进行了改进。我使用了 trove 库来减少空间需求。

这是一个详细的代码。自定义 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。时间性能是使用 0.05 秒Collection<GenericItemSimilarity.ItemItemSimilarity>,使用 0.07 秒TLongObjectHashMap<TLongDoubleHashMap>。我也相信在表演中扮演的重要角色是使用CandidateItemsStrategyMostSimilarItemsCandidateItemsStrategy

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

于 2013-09-06T13:46:47.897 回答