I\'m looking for the most basic solution to create multiple indexes on a Java Collection.
Required functionality:
You have a lot of really constrictive requirements are appear to be very particular to your needs. Most of the things you are saying aren't viable are because a lot so of people have the same exact needs which basically defines a basic database engine. That is why they are "large" libraries. You say "no database" but at its core every indexing system is a "database" of terms and documents. I would argue that a Collection is a "database". I would say take a look at Space4J.
I would say if you don't find what you are looking for, start a project on GitHub and get on with coding it yourself and sharing the results.
lets look at project http://code.google.com/p/multiindexcontainer/wiki/MainPage This is generalized way how to use maps for JavaBean getters and perform lookups over indexed values. I think this is what you are looking for. Lets give it a try.
Google Collections LinkedListMultimap
About your first requirement
I think There is neither a library nor a Helper that supports it.
Here is how i have done by using LinkedListMultimap
Multimap<Integer, String> multimap = LinkedListMultimap.create();
// Three duplicates entries
multimap.put(1, "A");
multimap.put(2, "B");
multimap.put(1, "A");
multimap.put(4, "C");
multimap.put(1, "A");
System.out.println(multimap.size()); // outputs 5
To get your first requirement, a Helper can play a good job
public static <K, V> void removeAllIndexEntriesAssociatedWith(Multimap<K, V> multimap, V value) {
Collection<Map.Entry<K, V>> eCollection = multimap.entries();
for (Map.Entry<K, V> entry : eCollection)
if(entry.getValue().equals(value))
eCollection.remove(entry);
}
...
removeAllIndexEntriesAssociatedWith(multimap, "A");
System.out.println(multimap.size()); // outputs 2
Google collections is
Your main goal seems to be that you'll remove the object from all indexes when you remove it from one.
The simplest approach will be to add another layer of indirection: you store your actual object in a Map<Long,Value>
, and use a bidirectional map (which you'll find in Jakarta Commons and probably Google Code) for your indexes as Map<Key,Long>
. When you remove an entry from a particular index, you'll take the Long
value from that index and use it to remove the corresponding entries from the main map and the other indexes.
One alternative to the BIDIMap is to define your "index" maps as Map<Key,WeakReference<Long>>
; however, this will require you to implement a ReferenceQueue
for cleanup.
Another alternative is to create a key object that can take an arbitrary tuple, define its equals()
method to match on any element in the tuple, and use that with a TreeMap
. You can't use a HashMap
, because you won't be able to compute a hashcode based on just one element of the tuple.
public class MultiKey
implements Comparable<Object>
{
private Comparable<?>[] _keys;
private Comparable _matchKey;
private int _matchPosition;
/**
* This constructor is for inserting values into the map.
*/
public MultiKey(Comparable<?>... keys)
{
// yes, this is making the object dependent on externally-changable
// data; if you're paranoid, copy the array
_keys = keys;
}
/**
* This constructor is for map probes.
*/
public MultiKey(Comparable key, int position)
{
_matchKey = key;
_matchPosition = position;
}
@Override
public boolean equals(Object obj)
{
// verify that obj != null and is castable to MultiKey
if (_keys != null)
{
// check every element
}
else
{
// check single element
}
}
public int compareTo(Object o)
{
// follow same pattern as equals()
}
}
Use Prefuse Tables. They support as many indices as you want, are fast (indices are TreeMaps), and have nice filtering options (boolean filters? no problem!). No database required, tested with large data-sets in many information visualization applications.
In their raw form, they are not as convenient as standard containers (you need to deal with rows and columns), but you can surely write a small wrapper around that. Plus, they plug nicely into UI components such as Swing's JTables.
Basically a solution based on multiple hash maps would be possible, but in this case all of them have to be keped up-to-date manually. A very simple integrated solution can be found here: http://insidecoffe.blogspot.de/2013/04/indexable-hashmap-implementation.html