Tip
|
For more details on secondary indexes please visit Aerospike Secondary Index official documentation. |
Out of the box spring-data-aerospike
supports creating secondary indexes in Aerospike.
There are two ways to accomplish this task:
-
Using
AerospikeTemplate
createIndex
method; -
Using
@Indexed
annotation placed over the field in your entity.
Let’s dive into more details.
In this example we will create an index at startup of the application manually.
AerospikeIndexConfiguration.java
package com.example.demo.persistence.index;
import com.aerospike.client.query.IndexType;
import com.example.demo.persistence.simplecrud.MovieDocument;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.aerospike.exceptions.IndexAlreadyExistsException;
import org.springframework.data.aerospike.core.AerospikeTemplate;
@Slf4j
@Configuration
public class AerospikeIndexConfiguration {
private static final String INDEX_NAME = "movie-rating-index";
@Bean
@ConditionalOnProperty(
value = "aerospike." + INDEX_NAME + ".create-on-startup",
havingValue = "true",
matchIfMissing = true)
public boolean createAerospikeIndex(AerospikeTemplate aerospikeTemplate) {
try {
aerospikeTemplate.createIndex(MovieDocument.class, INDEX_NAME, "rating", IndexType.NUMERIC);
log.info("Index {} was successfully created", INDEX_NAME);
} catch (IndexAlreadyExistsException e) {
log.info("Index {} already exists, skipped creating", INDEX_NAME);
}
return true;
}
}
Place @Indexed
annotation over the field in your entity and specify required types of the index.
This will make spring-data-aerospike
to auto-create specfied secondary index in Aerospike on startup of your application.
Note
|
|
IndexedDocument.java
package com.example.demo.persistence.index;
import lombok.Value;
import org.springframework.data.aerospike.annotation.Indexed;
import org.springframework.data.aerospike.mapping.Document;
import org.springframework.data.annotation.Id;
import java.util.List;
import static com.aerospike.client.query.IndexCollectionType.DEFAULT;
import static com.aerospike.client.query.IndexCollectionType.LIST;
import static com.aerospike.client.query.IndexType.NUMERIC;
import static com.aerospike.client.query.IndexType.STRING;
@Value
@Document
public class IndexedDocument {
@Id
String key;
@Indexed(type = STRING, collectionType = DEFAULT)
String author;
@Indexed(type = NUMERIC, collectionType = DEFAULT)
int likes;
@Indexed(type = NUMERIC, collectionType = LIST)
List<Integer> options;
}
Verify indexes were created using the following tests:
IndexTests.java
package com.example.demo;
import com.aerospike.client.AerospikeClient;
import com.aerospike.client.Info;
import com.aerospike.client.cluster.Node;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;
public class IndexTests extends DemoApplicationTests {
@Value("${embedded.aerospike.namespace}")
String namespace;
@Autowired
AerospikeClient client;
@Test
void verifyCustomIndexCreated() {
List<String> existingIndexes = getIndexes(client, namespace);
assertThat(existingIndexes).contains("movie-rating-index");
}
@Test
void verifyAnnotationBasedIndexesCreated() {
List<String> existingIndexes = getIndexes(client, namespace);
assertThat(existingIndexes)
.contains(
"IndexedDocument_author_string_default",
"IndexedDocument_likes_numeric_default",
"IndexedDocument_options_numeric_list");
}
// DO NOT USE THIS CODE IN PRODUCTION
private static List<String> getIndexes(AerospikeClient client, String namespace) {
Node node = client.getNodes()[0];
String response = Info.request(node, "sindex/" + namespace);
return Arrays.stream(response.split(";"))
.map(info -> {
Map<String, String> keyValue = Arrays.stream(info.split(":"))
.map(part -> {
String[] kvParts = part.split("=");
return Map.entry(kvParts[0], kvParts[1]);
})
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
return keyValue.get("indexname");
})
.collect(Collectors.toList());
}
}
Tip
|
If you are not familiar on how to setup embedded Aerospike server for your tests please consult Getting started Testing section. |