Skip to content

Latest commit

 

History

History
171 lines (129 loc) · 5.43 KB

creating-secondary-index.adoc

File metadata and controls

171 lines (129 loc) · 5.43 KB

Creating secondary index

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:

  1. Using AerospikeTemplate createIndex method;

  2. Using @Indexed annotation placed over the field in your entity.

Let’s dive into more details.

Creating index via AerospikeTemplate

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;
    }
}

Creating index via @Indexed annotation

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

@Indexed annotation is not supported for the fields annotated with @Id, @Expiration or @Version annotations.

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;
}

Testing

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.