Best way to store this in mapdb?

2.5k Views Asked by At

so I'm trying to do something with MapDB and I've run into a wall. I'll try describing it best I can:

I have four pieces of data, we'll say it goes like this:

1) String action; //the name of the action itself
2) String categoryOfAction; //the category of the action
3) Integer personWhoPerformedAction; //the person that did the action
4) Long timeOfOccurrence; //the time the action was done

The same action can be performed multiple times in this database, by different people and at different times, as well as in different categories. I want to have three separate maps, each that organize data into something like this:

String[] actionOccurances = map1.get(action); //returns every occurrence of that action (possibly in an array), including who did that occurrence, time the occurrence occurred, and the category of that occurrence

Long latestOccurance = map2.get(action); //returns the latest occurrence of that action

String[] actionsPerformedByPerson = map3.get(personWhoPerformedAction); //returns every action that this person has done, including the category of that action, the time they performed that action, and the name of the action itself

So, I want to do this as efficiently as possible. I know that I could just do something like this:

DB thedb = DBMaker.newTempFileDB().make();

NavigableSet<Object[]> map1 = thedb.createTreeSet("actionOccurences").comparator(Fun.COMPARABLE_ARRAY_COMPARATOR).make();

HTreeMap<String, Long> map2 = thedb.getHashMap("lastOccurrence");

NavigableSet<Object[]> map3 = thedb.createTreeSet("actionsPerformedByPerson").comparator(Fun.COMPARABLE_ARRAY_COMPARATOR).make();

But I feel like that's wrong. There must be a much more efficient way where I don't have to store the same data multiple times, yeah?

I've played quite a bit with the Bind class and it's functions (secondaryValues, mapInverse, etc. etc.) but I can't seem to find a way to map this set of data out how I want it to be.

Any help? Thanks.

1

There are 1 best solutions below

0
On

Ah! After awhile of working on this, I found a solution. I basically assign a unique ID to every record and then use MapDB's secondaryKey binding. It goes like this:

static class Record implements Serializable
{
    final String action;
    final String categoryOfAction;
    final String personWhoPerformedAction;
    final Long timeOfOccurrence;

    public record(String actn, String cat, String person, Long time)
    {
        action = actn;
        categoryOfAction = cat;
        personWhoPerformedAction = person;
        timeOfOccurence = time;
    }

}

static void main(String[] args)
{
    DB thedb = DBMaker.newTempFileDB().make();

    //primaryMap maps each record to a unique ID
    BTreeMap<Integer,Record> primaryMap = thedb.createTreeMap("pri")
                                        .keySerializer(BTreeKeySerializer.INTEGER)
                                        .makeOrGet();;

    //this map holds the unique ID of every record in primaryMap with a common action
    NavigableSet<Object[]> map_commonAction = thedb.createTreeSet("com_a")
                                        .comparator(Fun.COMPARABLE_ARRAY_COMPARATOR)
                                        .makeOrGet();

    //this map holds the unique ID of every record in primaryMap with a common person
    NavigableSet<Object[]> map_commonPerson = thedb.createTreeSet("com_p")
                                        .comparator(Fun.COMPARABLE_ARRAY_COMPARATOR)
                                        .makeOrGet();

    //binding map_commonAction to primaryMap so it is updated with primary
    Bind.secondaryKey(primaryMap, map_commonAction, new Fun.Function2<String, Integer, Record>() {
        @Override
        public String run(Integer recordID, Record r) {
            return r.action;
        }
    });

    //binding map_commonPerson to primaryMap so it is updated with primary
    Bind.secondaryKey(primaryMap, map_commonPerson, new Fun.Function2<String, Integer, Record>() {
        @Override
        public String run(Integer recordID, Record r) {
            return r.personWhoPerformedAction;
        }
    });


    primaryMap.put(1, new Record("a", "abc", "person1", 123434L));
    primaryMap.put(2, new Record("a", "abc", "person2", 322443L));
    primaryMap.put(3, new Record("b", "def", "person2", 124243L));
    primaryMap.put(4, new Record("b", "abc", "person1", 983243L));
    primaryMap.put(5, new Record("c", "def", "person2", 999993L));


    //this is how we attain all records with some action
    for (Object[] k : Fun.filter(map_commonAction, "someAction"))
    {
        Record obtainedRecord = primary.get(k[1]);

    }

    //this is how we attain all records with some person
    for (Object[] k : Fun.filter(map_commonPerson, "somePerson"))
    {
        Record obtainedRecord = primary.get(k[1]);

    }

}

However, still chime in if you think you can improve this solution. Thanks!