Additional Indexes

Note: The API described in this document is not an official contract and may change without preserving a backward compatibility. Such changes will be announced in advance on MDR mailing lists.
Content:
1. Overview
2. Definition of Additional Indexes
3. Multivalues Matching
4. Usage - Current Status

1. Overview

Additional indexes are support for fast and convenient searching objects in repository that match some specified attribute and association values. For example if the user works with an instance of a metamodel defining class 'Person' that contains attribute 'Age', an additional index can be build for the attribute allowing the user to query for all instances of Person having Age attribute of value, e.g., 30. Indexes can be combined - defined on several attributes and association ends.

2. Definition of Additional Indexes

Additional indexes are defined on the metamodel level using tags. Every time a model is to be instantiated, mdr looks for these tags and builds all needed additional indexes. Once a model is instantiated, no more indexes can be added or removed. An additional index is defined using a tag as follows:

Here is a definition of the index described in Overview (expressed using XMI):

<Model:Tag xmi.id = 'tag_1' name = 'not_important' annotation = '' tagId = 'org.netbeans.attributeIndex' values = 'ByAge'>
    <Model:Tag.elements>
        <Model:Attribute xmi.idref = 'Attribute_Age_ref'/>
    </Model:Tag.elements>
</Model:Tag>

If we have class C and association A with ends E1 and E2, where one of the ends is of type C (e.g. E1), it is possible to build index of instances of C for E1. Let us consider that our metamodel contains (except class Person) class 'Address' and association 'LivesAt' linking instances of Person (first end) and Address (second end). To build an index allowing to find all instances of Person linked to an instance of Address, we need the following tag:

<Model:Tag xmi.id = 'tag_2' name = '' annotation = '' tagId = 'org.netbeans.attributeIndex' values = 'ByAddress'>
    <Model:Tag.elements>
        <Model:Attribute xmi.idref = 'LivesAt_EndPerson_ref'/>
    </Model:Tag.elements>
</Model:Tag>

Moreover, we can define index on several attributes and association ends. If the type of used elements (attributes and assoc. ends) is not the same in all cases, it is required to attach the tag to a class that is a subtype of all the types (let us call it base class). Instances of this class and of all its subclasses are stored in the index. If the class is not specified the only type determined by elements the tag is attached to is taken as the base class.

Here is an example of multiple index definition:

<Model:Tag xmi.id = 'tag_3' name = '' annotation = '' tagId = 'org.netbeans.attributeIndex' values = 'ByAgeAndAddress'>
    <Model:Tag.elements>
        <Model:Attribute xmi.idref = 'Attribue_Age_ref'/>
        <Model:Attribute xmi.idref = 'LivesAt_EndPerson_ref'/>
        <Model:Class xmi.idref = 'Class_Person_ref'/>
    </Model:Tag.elements>
</Model:Tag>

The tag defines index supporting queries on instances of Person matching a pair of values - age and address. Note that attaching to Person class was not required in this case since both defining elements are of the same type (Person).

Note that the definition of base class can be used to filter instances in results of queries according to the class hierarchy. Let us suppose class 'Friend' is a subclass of Person. If we attach (e.g.) the third tag to Friend instead of Person, the index will store instances of Friend only and queries will return these instances only as well (even if there are some another matching instances of Person).

3. Multivalues Matching

If an indexed attribute or association end is multivalued an object matches to a query if the attribute's (resp. assoc. end's) value, which is a collection, has the same elements as the related collection specified in the query. Moreover, if the attribute (resp. assoc. end) is ordered, an object matches if both values, which are lists, contain the same elements in the same order.

4. Usage - Current Status

For now, additional indexes support is mdr internal thing only. There are not any related find/query methods in mdr api yet (however they are planned to be added). Despite the internal character additional indexes can be used, but it requires to access the mdr storagemodel layer (if you are interested in mdr architecture, see Architecture page).

First of all, we need to obtain an instance of MdrStorage related to the package extent we work with. It is done as follows:

import org.netbeans.handlers.*;
import org.netbeans.storagemodel.*;

MdrStorage storage = ((BaseObjectHandler) extent)._getDelegate().getMdrStorage ();

MdrStorage has method 

    queryAdditionalIndex(String extentMofId, String indexName, Map values) 

returning Collection of instances of org.netbeans.storagemodel.StorableObject. Each StorableObject can be translated to RefObject using org.netbeans.handlers.BaseObjectHandler.getHanler(StorableBaseObject storable) static method. The parameters of the method are as follows:

If an additional index is based on one element (attribute or assoc. end), method 

    getObjectsFromAdditionalIndex(String extentMofId, String indexName, Object value)

can be used as well. Here is the only value passed directly, a map is not required.

Test for additional indexes can serve as an example:
    http://mdr.netbeans.org/source/browse/mdr/test/unit/src/org/netbeans/mdr/test/AdditionalIndexTest.java .
The used metamodel containing tags that define indexes is
    http://mdr.netbeans.org/source/browse/mdr/test/unit/src/org/netbeans/mdr/test/data/IndexedModel.xml .