0

I follow this topic and use MemoryIDMigrator to get a long ID for my products : Mahout : To read a custom input file

But I can't initialize IDMigrator like this because the parent constructor need to come first :

public MemoryIDMigrator memoryIDMigrator;

public CustomFileDataModel(File dataFile) throws IOException {

    this.memoryIDMigrator = new MemoryIDMigrator();
    super(dataFile);
}

@Override
protected long readItemIDFromString(String stringID) {

    long result = this.memoryIDMigrator.toLongID(stringID);
    this.memoryIDMigrator.storeMapping(result, stringID);
    return result;
}

How could I give this parameter to get back my String ID ? I need something like this :

    List<RecommendedItem> recommendations = recommender.recommend(2, 5);
    for (RecommendedItem recommendation : recommendations) {
        System.out.println(memoryIDMigrator.toStringID(recommendation.getItemID());
    }
  • Actually this is a problem with Mahout. It uses numeric ids internally for just about everything. It is expected that you will provide your own translation from Mahout ID to your id and the other way around. I suggest something like a BiMap, which is a 2 directional hashmap. You can initialize it with a set of (YourId, MahoutId) pairs then map from either to the other. In the Scala version of Mahout (Mahout Samsara) there is a BiDictionary class that can be used for this. – pferrel Apr 04 '20 at 16:36

1 Answers1

0

I just found a solution ! In my opinion it's not the best way to do it but it works.

When my override function try to read an item, I prevent the creation of a new map if it had already been created :

public class CustomFileDataModel extends FileDataModel {

    public MemoryIDMigrator memoryIDMigrator;
    private boolean loaded;

    public CustomFileDataModel(File dataFile) throws IOException {
        super(dataFile);
    }

    @Override
    protected long readItemIDFromString(String stringID) {
        if (!this.loaded) {
            this.memoryIDMigrator = new MemoryIDMigrator();
            this.loaded = true;
        }
        long result = this.memoryIDMigrator.toLongID(stringID);
        this.memoryIDMigrator.storeMapping(result, stringID);
        return result;
    }
}

Similarly, if you want to use a custom user ID, you can override the readUserIDFromString() function.

And then to recover my string ID, I proceed like this :

public static void main( String[] args ) throws IOException, TasteException {

    CustomFileDataModel model = new CustomFileDataModel(new File("path/to/data.csv"));

    UserSimilarity similarity = new PearsonCorrelationSimilarity(model);

    UserNeighborhood neighborhood = new ThresholdUserNeighborhood(0.1, similarity, model);

    UserBasedRecommender recommender = new GenericUserBasedRecommender(model, neighborhood, similarity);

    List<RecommendedItem> recommendations = recommender.recommend(2, 5);
    for (RecommendedItem recommendation : recommendations) {
        System.out.println(model.memoryIDMigrator.toStringID(recommendation.getItemID()));
    }
}