Skip to content

Secondary Indexes

Secondary indexes are used to enable lookup operations based on native Valkey structures. Values are written to the according indexes on every save and are removed when objects are deleted or expire.

Given the sample Person entity shown earlier, we can create an index for firstname by annotating the property with @Indexed, as shown in the following example:

Example 1. Annotation driven indexing

@ValkeyHash("people")
public class Person {
@Id String id;
@Indexed String firstname;
String lastname;
Address address;
}

Indexes are built up for actual property values. Saving two Persons (for example, “rand” and “aviendha”) results in setting up indexes similar to the following:

SADD people:firstname:rand e2c7dcee-b8cd-4424-883e-736ce564363e
SADD people:firstname:aviendha a9d4b3a0-50d3-4538-a2fc-f7fc2581ee56

It is also possible to have indexes on nested elements. Assume Address has a city property that is annotated with @Indexed. In that case, once person.address.city is not null, we have Sets for each city, as shown in the following example:

SADD people:address.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e

Furthermore, the programmatic setup lets you define indexes on map keys and list properties, as shown in the following example:

@ValkeyHash("people")
public class Person {
// ... other properties omitted
Map<String, String> attributes; // (1)
Map<String, Person> relatives; // (2)
List<Address> addresses; // (3)
}
1. `SADD people:attributes.map-key:map-value e2c7dcee-b8cd-4424-883e-736ce564363e`
2. `SADD people:relatives.map-key.firstname:tam e2c7dcee-b8cd-4424-883e-736ce564363e`
3. `SADD people:addresses.city:tear e2c7dcee-b8cd-4424-883e-736ce564363e`

As with keyspaces, you can configure indexes without needing to annotate the actual domain type, as shown in the following example:

Example 2. Index Setup with @EnableValkeyRepositories

@Configuration
@EnableValkeyRepositories(indexConfiguration = MyIndexConfiguration.class)
public class ApplicationConfig {
//... ValkeyConnectionFactory and ValkeyTemplate Bean definitions omitted
public static class MyIndexConfiguration extends IndexConfiguration {
@Override
protected Iterable<IndexDefinition> initialConfiguration() {
return Collections.singleton(new SimpleIndexDefinition("people", "firstname"));
}
}
}

Again, as with keyspaces, you can programmatically configure indexes, as shown in the following example:

Example 3. Programmatic Index setup

@Configuration
@EnableValkeyRepositories
public class ApplicationConfig {
//... ValkeyConnectionFactory and ValkeyTemplate Bean definitions omitted
@Bean
public ValkeyMappingContext keyValueMappingContext() {
return new ValkeyMappingContext(
new MappingConfiguration(
new KeyspaceConfiguration(), new MyIndexConfiguration()));
}
public static class MyIndexConfiguration extends IndexConfiguration {
@Override
protected Iterable<IndexDefinition> initialConfiguration() {
return Collections.singleton(new SimpleIndexDefinition("people", "firstname"));
}
}
}

Assume the Address type contains a location property of type Point that holds the geo coordinates of the particular address. By annotating the property with @GeoIndexed, Spring Data Valkey adds those values by using Valkey GEO commands, as shown in the following example:

@ValkeyHash("people")
public class Person {
Address address;
// ... other properties omitted
}
public class Address {
@GeoIndexed Point location;
// ... other properties omitted
}
public interface PersonRepository extends CrudRepository<Person, String> {
List<Person> findByAddressLocationNear(Point point, Distance distance); // (1)
List<Person> findByAddressLocationWithin(Circle circle); // (2)
}
Person rand = new Person("rand", "al'thor");
rand.setAddress(new Address(new Point(13.361389D, 38.115556D)));
repository.save(rand); // (3)
repository.findByAddressLocationNear(new Point(15D, 37D), new Distance(200, Metrics.KILOMETERS)); // (4)
1. Query method declaration on a nested property, using `Point` and `Distance`.
2. Query method declaration on a nested property, using `Circle` to search within.
3. `GEOADD people:address:location 13.361389 38.115556 e2c7dcee-b8cd-4424-883e-736ce564363e`
4. `GEORADIUS people:address:location 15.0 37.0 200.0 km`

In the preceding example the, longitude and latitude values are stored by using GEOADD that use the object’s id as the member’s name. The finder methods allow usage of Circle or Point, Distance combinations for querying those values.