Originally posted by James Arendt:
I want to create my own collection type that allows querying for an object based on:
a) it's type
b) the template provided (aka fields).
I'd also like to be able get obtain a match even if not all the fields are specified (aka. a field is null
Let's forget about type for the moment. Let's also just focus on the algorithm expressed in terms of Collection classes. Since you need to be able to search on any number of fields, you may initially index each field separately. For each possible value of the field, you have a set of objects which have that value.
Enter a HashMap which maps a value to a Set of objects. For each non-null field in your template, you would be doing something like this:
Each field would have its own fieldValueMap. This calls for a further Map which maps the name of the field to the fieldValueMap.
So far, so good. There is a fair number which will complicate things however.
First, if you want to be able to search for a range of values in a field rather than a fixed value only, you would need to use a TreeMap instead of a HashMap.
Second, you will probably find that for some fields indexing doesn't work. They only have a few values and you will end up with impossibly large and inefficient Sets for that field. These fields would better be subject to a linear search. You could enhance the code so that it will do a linear search where the fieldValueMap is null.
Third, once you've gone through a couple of fields, your resultSet is likely to be so small that a simple linear search through the remaining set is more efficient than going through the fieldValueMap for all the remaining fields. In fact, for optimum performance you would process the template fields in an order that allows you to cut down the resultSet as quickly as possible and finish off with a linear search.
If the above sounds like database indexing and query optimisation, that is because that's essentially what you're trying to build: an in-memory database. I would advise you to take a long hard look at products like the (free)
HypersonicSQL.
Fourth, types. If you don't want to compare between types, it's simple -- instead of mapping the field name to a fieldValueMap, you map typeName.fieldName to a fieldValueMap.
This can even be made to work when comparing different but compatible types. Say you have a class A with field a, and subclasses B and C. Say you are adding an object of type B. You can use reflection to determine that field B.a is in fact inherited from A, and map it using "A.a" rather than "B.a". That way, if you are searching with a template of type A, you will find not only objects of type A but also matching objects of types B and C.
Hope I didn't discourage you!
- Peter