[Java programming language only]

Using a composite index

The composite HashIndex improves query performance and avoids expensive map scanning. The feature also provides a convenient way for the HashIndex API to find cached objects when search criteria involve many attributes.

Improved performance

A composite HashIndex provides a fast and convenient way to search for cached objects with multiple attributes in match-searching criteria. The composite index supports full attribute-match searches, but does not support range searches.

Note: Composite indexes do not support the BETWEEN operator in the ObjectGrid query language because BETWEEN would require range support. The greater than (>) and less than (<) conditionals also do not work because they require range indexes.

A composite index can improve performance of queries if the appropriate composite index is available for the WHERE condition. This means that the composite index has exactly the same attributes as involved in the WHERE condition with full attributes matched.

A query might have many attributes involved in a condition as in the following example.

SELECT a FROM Address a WHERE a.city='Rochester' AND a.state='MN' AND a.zipcode='55901'

Composite index can improve query performance by avoiding scanning map or joining multiple single-attribute index results. In the example, if a composite index is defined with attributes (city,state,zipcode), the query engine can use the composite index to find the entry with city='Rochester', state='MN', and zipcode='55901'. Without composite index and attribute index on city, state, and zipcode attributes, the query engine must scan the map or join multiple single-attribute searches, which usually have expensive overhead. Also, querying for the composite index supports a full-matched pattern only.

Configuring a composite index

You can configure composite indexing in three ways: programmatically, using XML, and with entity annotations only for entity maps.
[Version 8.6.0.2 and later]Restriction: MapIndex.EMPTY_VALUE is not supported with composite global indexes.
  • Programmatic configuration

    The following example creates the a composite index.

    	  HashIndex mapIndex = new HashIndex();
        mapIndex.setName("Address.CityStateZip");
        mapIndex.setAttributeName(("city,state,zipcode"));
        mapIndex.setRangeIndex(false);
        BackingMap bm = objectGrid.defineMap("mymap");
        bm.addMapIndexPlugin(mapIndex);

    Note that configuring a composite index is the same as configuring a regular index with XML except for the attributeName property value. In a composite index case, the value of attributeName is a comma-delimited list of attributes. For example, the value class Address has 3 attributes: city, state, and zipcode. A composite index can be defined with the attributeName property value as "city,state,zipcode" indicating that city, state, and zipcode are included in the composite index.

    Composite HashIndexes do not support range lookups and therefore cannot have the RangeIndex property set to true.

  • Using XML

    To configure a composite index with XML, include the following configuration in the backingMapPluginCollections element in the ObjectGrid descriptor XML file.

    Composite index - XML configuration approach
    <bean id="MapIndexPlugin"  className="com.ibm.websphere.objectgrid.plugins.index.HashIndex">
    <property name="Name" type="java.lang.String" value="Address.CityStateZip"/>
    <property name="AttributeName" type="java.lang.String" value="city,state,zipcode"/>
    </bean>
  • With entity annotations

    In the entity map case, annotation approach can be used to define a composite index. You can define a list of CompositeIndex within CompositeIndexes annotation on the entity class level. The CompositeIndex has a name and attributeNames property. Each CompositeIndex is associated with a HashIndex instance applied to the backing map that is associated with the entity. The HashIndex is configured as a non-range index.

    @Entity
    @CompositeIndexes({
        @CompositeIndex(name="CityStateZip", attributeNames="city,state,zipcode"), 
        @CompositeIndex(name="lastnameBirthday", attributeNames="lastname,birthday")
     })
    public class Address {
        @Id int id;
        String street;
        String city;
        String state;
        String zipcode;
        String lastname;
        Date birthday;
    }

    The name property for each composite index must be unique within the entity and BackingMap. If the name is not specified, a generated name is used. The attributeNames property is used to populate the HashIndex attributeName with the comma-delimited list of attributes. The attribute names coincide with the persistent field names when the entities are configured to use field-access, or the property name as defined for the JavaBeans naming conventions for property-access entities. For example: If the attribute name is "street", the property getter method is named getStreet.

Performing composite index lookups

After a composite index is configured, an application can use the findAll(Object) method of the MapIndex interface to perform lookups.

Session sess = objectgrid.getSession();
ObjectMap map = sess.getMap("MAP_NAME");
MapIndex codeIndex = (MapIndex) map.getIndex("INDEX_NAME");
Object[] compositeValue = new Object[]{ MapIndex.EMPTY_VALUE,
			"MN", "55901"};
Iterator iter = mapIndex.findAll(compositeValue);
// Close the session (optional in Version 7.1.1 and later) for improved performance
sess.close();   

The MapIndex.EMPTY_VALUE is assigned to the compositeValue[ 0 ] which indicates that the city attribute is excluded from evaluation. Only objects with state attribute equal to "MN" and zipcode attribute equal to "55901" are included in the result.

The following queries benefit from the previous composite index configuration:

SELECT a FROM Address a WHERE a.city='Rochester' AND a.state='MN' AND a.zipcode='55901'

SELECT a FROM Address a WHERE a.state='MN' AND a.zipcode='55901'

The query engine finds the appropriate composite index and use it to improve query performance in full attribute-match cases.

In some scenarios, the application might need to define multiple composite indexes with overlapped attributes in order to satisfy all queries with full attributes matched. A disadvantage of increasing the number of indexes is the possible performance overhead on map operations.

Configuring a global composite index

A global composite index is a type of global index used to index multiple attributes of a cached object which is in the form of a composite index. You can configure a global composite index in two ways, either programmatically or using XML.

  • Programmatic configuration

    The following example creates the a composite index.

    	  HashIndex mapIndex = new HashIndex();
        mapIndex.setName("Address.CityStateZip");
        mapIndex.setAttributeName(("city,state,zipcode"));
        mapIndex.setRangeIndex(false);
        mapIndex.setGlobalIndexEnabled(true);
        BackingMap bm = objectGrid.defineMap("mymap");
        bm.addMapIndexPlugin(mapIndex);
  • Using XML

    To configure a global composite index with XML, include the following configuration in the backingMapPluginCollections element in the ObjectGrid descriptor XML file.

    Global composite index - XML configuration approach
    <bean id="MapIndexPlugin"  className="com.ibm.websphere.objectgrid.plugins.index.HashIndex">
    <property name="Name" type="java.lang.String" value="Address.CityStateZip"/>
    <property name="AttributeName" type="java.lang.String" value="city,state,zipcode"/>
    <property name="GlobalIndexEnabled" type="boolean" value="true" description="required"/>
    </bean>

Performing global composite index lookups

After a global composite index is configured, an application can use the findAll(Object) method of the MapIndex interface to perform lookups.

Session sess = objectgrid.getSession();
ObjectMap map = sess.getMap("MAP_NAME");
globalIndex = (MapGlobalIndex)map.getIndex("IndexName");
Object values = new Object[]{ "Rochester", "MN" , "55901" } ;
//  OR :
//  Object[] values =  new Object[] { new Object[] { "Rochester", "MN" , "55901"  } };
Set keys = mapIndex.findKeys (values);
sess.close();   

The following queries benefit from the previous composite index configuration:

SELECT a FROM Address a WHERE a.city='Rochester' AND a.state='MN' AND a.zipcode='55901'

The query engine finds the appropriate composite index and use it to improve query performance in full attribute-match cases.

In some scenarios, the application might need to define multiple composite indexes with overlapped attributes in order to satisfy all queries with full attributes matched. A disadvantage of increasing the number of indexes is the possible performance overhead on map operations.

Migration and interoperability

The only constraint for the use of a composite index is that an application cannot configure it in a distributed environment with heterogeneous containers. Old and new container servers cannot be mixed, since older container servers do not recognize a composite index configuration. The composite index is just like the existing regular attribute index, except that the former allows indexing over multiple attributes. When using only the regular attribute index, a mixed-container environment is still viable.