blob: 688eccb60fc1e96efde1a7280f10696f5f8c72e8 [file] [log] [blame]
Many datastores do not support secondary indexing or require you to build your own. In cases like this, you will need to implement a `PropertyIndexer`.
NOTE: If the underlying datastore supports secondary indexes then it is ok to just return a `null` `PropertyIndexer` and let the datastore handle the indexing.
For example the `ConcurrentHashMap` implementation creates secondary indices by populating another `Map` containing the indices:
[source,groovy]
----
void index(value, primaryKey) {
def index = getIndexName(value)
def indexed = indices[index]
if (indexed == null) {
indexed = []
indices[index] = indexed
}
if (!indexed.contains(primaryKey)) {
indexed << primaryKey
}
}
----
The implementation for Redis is very similar and stores the primary key in a Redis set:
[,java]
----
public void index(final Object value, final Long primaryKey) {
if (value == null) {
return;
}
final String primaryIndex = createRedisKey(value);
redisTemplate.sadd(primaryIndex, primaryKey);
}
----
An index name is typically built from the entity name, property name and property value. The primary key of the entity is stored in this index for later querying. In fact there is a `query` method that needs to be implemented on `PropertyIndexer`. The `ConcurrentHashMap` implementation looks like this:
[source,groovy]
----
List query(value, int offset, int max) {
def index = getIndexName(value)
def indexed = indices[index]
if (!indexed) {
return Collections.emptyList()
}
return indexed[offset..max]
}
----
Depending on the characteristics of the underlying database you may want to do the indexing asynchronously or you may want to index into a search library such as Lucene. For datastores that are eventually consistent for example it makes sense to do all indexing asynchronously.
Finally, when an object is deleted it will need to removed from the indices. This can be done with the `deindex` method:
[source,groovy]
----
void deindex(value, primaryKey) {
def index = getIndexName(value)
def indexed = indices[index]
if (indexed) {
indexed.remove(primaryKey)
}
}
----