Indices in Morphium

published : 2020-11-27 changed: 2020-11-27

category: Computer --> programming --> MongoDB --> morphium

tags:


Morphium and Indices

Defining Indices

First of all, you usually do not need to care about Indices in Mongodb, just define it in your entity code:

@Entity
public class MyEntity {
    @Id
    private MorphiumId id;
    @Index
    private String myIndexedString;
    @Index(decrement = true)
    private Integer aNumber;
}

There are more options for defining indices, please consult the morphium documentation for details.

Index creation

As already mentioned, Morphium usually takes care of creation of indices following a simple rule:

  • when writing, check if the collection already exists, if not, create indexes
  • do nothing if collection is already there

The reason being, that if you have big collections, it might cause problems to create new indices when writing - it might affect the system. But if the collection does not exist, this is quite a small operation.

But there's a catch: this check costs time, every write morphium checks, if the collection exists.

You can change this behaviour by switching automatic index creation off in MorphiumConfig config.setAutoIndexAndCappedCreationOnWrite(false).

Starting with morphium V4.2.3, you can also have morphium check those indices only on startup. morphiumConfig.setIndexCappedCheck(IndexCappedCheck.WARN_ON_STARTUP)

This will issue a warning in log, if an index for an entity is missing. There are more options, you can choose from:

  • NO_CHECK: do not check, if indices match
  • WARN_ON_STARTUP: check indices for all Entities on startup/connect. This will slow down startup depending on your code.
  • CREATE_ON_WRITE_NEW_COL: create missing indices, when writing to a new collection (Default behaviour)
  • CREATE_ON_STARTUP: check for indices only once when starting up / connecting to mongo.

Hint: There is no option to warn on write, this would slow down mongodb access significantly!

Warnings for missing indices look like this: Collection 'person' for entity 'de.caluga.test.mongo.suite.TextIndexTest$Person' does not exist.

Capped collections

Morphium does combine handles the capped status of collection together with indices. That means, if the collection does not exists, but @Capped-Annotation is used, the collection is created capped. This is done together with the indices, so if you check those, capped information is also checked. Depending on settings, the collection might also be automatically converted to a capped collection!

programmatically creating indices

The easiest way to create indices is, to call the method ensureIndicesFor(ENTITYCLASS). This will create all indices, that are defined in code for this entity (using the @Index annotation). If you also want to ensure, the corresponding collection is capped, if defined accordingly, call morphium.ensureCapped(ENTITYCLASS).

Both methods will not create indices or capped collections, if no index is defined in code. But it will call ensureIndex on mongodb.

Hint: when an index is created for a non existend collection, there will be an empty collection in mongodb.

But you can also create indices more manually:

  public <T> void ensureIndex(Class<T> cls, String collection, Map<String, Object> index, Map<String, Object> options, AsyncOperationCallback<T> callback);

the Index map contains the Document that describes the index (similar as directly in mongodb) and the options are the corresponding options for this index. e.g.

 morphium.ensureIndex(UncachedObject.class, "uncached_object",Utils.getMap("counter",1),Utils.getMap("unique","true"),null);

get Information about missing indices

In order to get just the information on missing indices for a specific Entity (or all of them), you can get this information starting with MongoDB V4.2.3:

Map<Class<?>, List<Map<String, Object>>> missing = morphium.checkIndices();

returns a Map with the entity class as key and a list of missing Index definitions as value. you can use this map to manually create an index:

Map<Class<?>, List<Map<String, Object>>> missing = morphium.checkIndices();
morphium.ensureIndex(EntObject.class,missing.get(EntObject.class).get(0))

ATTENTION:

  • the checkIndices() also adds missing capped information to the result map!
  • checkIndices() runs through the whole classpath, which can take some milliseconds, if you want to reduce the load, you can use checkIndices(filter), and filter classes according to your needs: checkIndices(classInfo -> !classInfo.getPackageName().startsWith("de.caluga.morphium"));

conclusion

The performance of Databases strongly depends on proper creation of indices. With morphium you can define them all in code, which reduces the need to know, how to create indices in Mongodb manually for java engineers and hence improves performance.

created Stephan Bösebeck (stephan)