Skip to content

Commit

Permalink
@indexed enhancements (#113)
Browse files Browse the repository at this point in the history
* Move @indexed annotation to high-level annotation package

* @indexed: support index collection type
  • Loading branch information
Aloren authored Nov 23, 2020
1 parent 1c0df5c commit be58f5f
Show file tree
Hide file tree
Showing 25 changed files with 357 additions and 134 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@
*/


package org.springframework.data.aerospike.index;
package org.springframework.data.aerospike.annotation;

import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;

import java.lang.annotation.ElementType;
Expand All @@ -25,7 +26,11 @@
import java.lang.annotation.Target;

/**
* Mark a field to be indexed using Aerospike's indexing feature.
* Marks a field to be indexed using Aerospike's secondary index.
* This will make spring-data-aerospike create index on application's startup.
* <p>
* For more details on Secondary index feature please refer to
* <a href="https://www.aerospike.com/docs/architecture/secondary-index.html">Aerospike Secondary index</a>.
*
* @author Taras Danylchuk
*/
Expand All @@ -34,12 +39,17 @@
public @interface Indexed {

/**
* If not set, name will be automatically generated with pattern {setName}_{fieldName}.
* If not set, name will be automatically generated with pattern {setName}_{fieldName}_lowercase{type}_lowercase{collectionType}.
*/
String name() default "";

/**
* Underlying data type of index.
* Underlying data type of secondary index.
*/
IndexType type();

/**
* Secondary index collection type.
*/
IndexCollectionType collectionType() default IndexCollectionType.DEFAULT;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@
*/
package org.springframework.data.aerospike.core;

import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.springframework.data.aerospike.IndexAlreadyExistsException;
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;

import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Value;
import com.aerospike.client.policy.WritePolicy;
import com.aerospike.client.query.Filter;
import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import org.springframework.data.aerospike.IndexAlreadyExistsException;
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.domain.Sort;
import org.springframework.data.mapping.context.MappingContext;

import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

/**
* Aerospike specific data access operations.
Expand Down Expand Up @@ -163,14 +163,16 @@ public interface AerospikeOperations {

/**
* Creates index by specified name in Aerospike.
* @param entityClass
* @param indexName
* @param binName
* @param indexType
*/
<T> void createIndex(Class<T> entityClass, String indexName, String binName,
IndexType indexType);

/**
* Creates index by specified name in Aerospike.
*/
<T> void createIndex(Class<T> entityClass, String indexName, String binName,
IndexType indexType, IndexCollectionType indexCollectionType);

/**
* Deletes index by specified name from Aerospike.
* @param entityClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.aerospike.client.policy.RecordExistsAction;
import com.aerospike.client.policy.WritePolicy;
import com.aerospike.client.query.Filter;
import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import com.aerospike.client.query.KeyRecord;
import com.aerospike.client.query.ResultSet;
Expand Down Expand Up @@ -99,13 +100,21 @@ public AerospikeTemplate(AerospikeClient client,
@Override
public <T> void createIndex(Class<T> entityClass, String indexName,
String binName, IndexType indexType) {
createIndex(entityClass, indexName, binName, indexType, IndexCollectionType.DEFAULT);
}

public <T> void createIndex(Class<T> entityClass, String indexName,
String binName, IndexType indexType, IndexCollectionType indexCollectionType) {
Assert.notNull(entityClass, "Type must not be null!");
Assert.notNull(indexName, "Index name must not be null!");
Assert.notNull(binName, "Bin name must not be null!");
Assert.notNull(indexType, "Index type must not be null!");
Assert.notNull(indexCollectionType, "Index collection type must not be null!");

try {
String setName = getSetName(entityClass);
IndexTask task = client.createIndex(null, this.namespace,
setName, indexName, binName, indexType);
setName, indexName, binName, indexType, indexCollectionType);
if (task != null) {
task.waitTillComplete();
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.springframework.data.aerospike.core;

import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import org.springframework.data.aerospike.repository.query.Query;
import org.springframework.data.domain.Sort;
Expand Down Expand Up @@ -62,14 +63,16 @@ public interface ReactiveAerospikeOperations {

/**
* Creates index by specified name in Aerospike.
* @param entityClass
* @param indexName
* @param binName
* @param indexType
*/
<T> Mono<Void> createIndex(Class<T> entityClass, String indexName,
String binName, IndexType indexType);

/**
* Creates index by specified name in Aerospike.
*/
<T> Mono<Void> createIndex(Class<T> entityClass, String indexName, String binName,
IndexType indexType, IndexCollectionType indexCollectionType);

/**
* Deletes index by specified name from Aerospike.
* @param entityClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,21 @@ public <T> Mono<Boolean> delete(T objectToDelete) {
@Override
public <T> Mono<Void> createIndex(Class<T> entityClass, String indexName,
String binName, IndexType indexType) {
return createIndex(entityClass, indexName, binName, indexType, IndexCollectionType.DEFAULT);
}

@Override
public <T> Mono<Void> createIndex(Class<T> entityClass, String indexName,
String binName, IndexType indexType, IndexCollectionType indexCollectionType) {
Assert.notNull(entityClass, "Type must not be null!");
Assert.notNull(indexName, "Index name must not be null!");
Assert.notNull(binName, "Bin name must not be null!");
Assert.notNull(indexType, "Index type must not be null!");
Assert.notNull(indexCollectionType, "Index collection type must not be null!");

String setName = getSetName(entityClass);
return reactorClient.createIndex(null, this.namespace,
setName, indexName, binName, indexType, IndexCollectionType.DEFAULT)
setName, indexName, binName, indexType, indexCollectionType)
.then(reactorIndexRefresher.refreshIndexes())
.onErrorMap(this::translateError);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.data.aerospike.index;

import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;
import lombok.Builder;
import lombok.NonNull;
Expand All @@ -34,5 +35,7 @@ public class AerospikeIndexDefinition {
@NonNull
IndexType type;
@NonNull
IndexCollectionType collectionType;
@NonNull
Class<?> entityClass;
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

package org.springframework.data.aerospike.index;

import org.springframework.data.aerospike.annotation.Indexed;
import org.springframework.data.aerospike.mapping.AerospikePersistentProperty;
import org.springframework.data.aerospike.mapping.BasicAerospikePersistentEntity;
import org.springframework.util.StringUtils;
Expand All @@ -41,13 +42,20 @@ private AerospikeIndexDefinition convertToIndex(BasicAerospikePersistentEntity<?
AerospikePersistentProperty property) {
Indexed annotation = property.getRequiredAnnotation(Indexed.class);
String indexName = StringUtils.isEmpty(annotation.name())
? String.join("_", persistentEntity.getSetName(), property.getFieldName())
? getIndexName(persistentEntity, property, annotation)
: annotation.name();
return AerospikeIndexDefinition.builder()
.entityClass(persistentEntity.getType())
.fieldName(property.getFieldName())
.name(indexName)
.type(annotation.type())
.collectionType(annotation.collectionType())
.build();
}

private String getIndexName(BasicAerospikePersistentEntity<?> entity,
AerospikePersistentProperty property, Indexed annotation) {
return String.join("_",
entity.getSetName(), property.getFieldName(), annotation.type().name().toLowerCase(), annotation.collectionType().name().toLowerCase());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ protected void installIndexes(Set<AerospikeIndexDefinition> indexes) {
indexes.forEach(this::installIndex);
}

private void installIndex(AerospikeIndexDefinition indexDefinition) {
log.debug("Installing aerospike index: {}...", indexDefinition);
private void installIndex(AerospikeIndexDefinition index) {
log.debug("Installing aerospike index: {}...", index);
try {
template.createIndex(indexDefinition.getEntityClass(), indexDefinition.getName(),
indexDefinition.getFieldName(), indexDefinition.getType());
log.info("Installed aerospike index: {} successfully.", indexDefinition);
template.createIndex(index.getEntityClass(), index.getName(),
index.getFieldName(), index.getType(), index.getCollectionType());
log.info("Installed aerospike index: {} successfully.", index);
} catch (IndexAlreadyExistsException e) {
log.info("Skipping index [{}] creation. Index with the same name already exists. {}", indexDefinition, e.getMessage());
log.info("Skipping index [{}] creation. Index with the same name already exists. {}", index, e.getMessage());
} catch (Exception e) {
throw new IllegalStateException("Failed to install aerospike index: " + indexDefinition, e);
throw new IllegalStateException("Failed to install aerospike index: " + index, e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,12 @@ protected void installIndexes(Set<AerospikeIndexDefinition> indexes) {
.block();
}

private Mono<Void> installIndex(AerospikeIndexDefinition definition) {
log.debug("Installing aerospike index: {}...", definition);
return template.createIndex(definition.getEntityClass(), definition.getName(), definition.getFieldName(), definition.getType())
.doOnSuccess(__ -> log.info("Installed aerospike index: {} successfully.", definition))
.onErrorResume(IndexAlreadyExistsException.class, e -> onIndexAlreadyExists(e, definition))
.doOnError(throwable -> log.error("Failed to install aerospike index: " + definition, throwable));
private Mono<Void> installIndex(AerospikeIndexDefinition index) {
log.debug("Installing aerospike index: {}...", index);
return template.createIndex(index.getEntityClass(), index.getName(), index.getFieldName(), index.getType(), index.getCollectionType())
.doOnSuccess(__ -> log.info("Installed aerospike index: {} successfully.", index))
.onErrorResume(IndexAlreadyExistsException.class, e -> onIndexAlreadyExists(e, index))
.doOnError(throwable -> log.error("Failed to install aerospike index: " + index, throwable));
}

private Mono<? extends Void> onIndexAlreadyExists(Throwable throwable, AerospikeIndexDefinition indexDefinition) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,14 @@ public Index parse(String infoString) {
String bin = getRequiredBin(values);
IndexType indexType = getIndexTypeInternal(values);
IndexCollectionType collectionType = getIndexCollectionTypeInternal(values);
return new Index(values, name, namespace, set, bin, indexType, collectionType);
return Index.builder()
.name(name)
.namespace(namespace)
.set(set)
.bin(bin)
.indexType(indexType)
.indexCollectionType(collectionType)
.build();
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@

import com.aerospike.client.query.IndexCollectionType;
import com.aerospike.client.query.IndexType;

import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import lombok.Builder;
import lombok.RequiredArgsConstructor;
import lombok.Value;

/**
* This class represents a Secondary Index
Expand All @@ -31,41 +29,18 @@
* @author Peter Milne
* @author Anastasiia Smirnova
*/
@Value
@Builder
@RequiredArgsConstructor
public class Index {

private final Map<String, String> values;
private final String name;
private final String namespace;
private final String set;
private final String bin;
private final IndexType indexType;
private final IndexCollectionType indexCollectionType;

public Index(Map<String, String> values, String name,
String namespace, String set, String bin,
IndexType indexType, IndexCollectionType indexCollectionType) {
this.values = values;
this.name = name;
this.namespace = namespace;
this.set = set;
this.bin = bin;
this.indexType = indexType;
this.indexCollectionType = indexCollectionType;
}

public List<NameValuePair> getValues() {
return this.values.entrySet().stream()
.map(entry -> new NameValuePair(entry.getKey(), entry.getValue()))
.collect(Collectors.collectingAndThen(
Collectors.toList(),
Collections::unmodifiableList));
}

@Override
public String toString() {
return this.getName();
}

public String getName() {
return this.name;
}
Expand Down
Loading

0 comments on commit be58f5f

Please sign in to comment.