Skip to content

Valkey Repositories Anatomy

Valkey as a store itself offers a very narrow low-level API leaving higher level functions, such as secondary indexes and query operations, up to the user.

This section provides a more detailed view of commands issued by the repository abstraction for a better understanding of potential performance implications.

Consider the following entity class as the starting point for all operations:

Example 1. Example entity

@ValkeyHash("people")
public class Person {
@Id String id;
@Indexed String firstname;
String lastname;
Address hometown;
}
public class Address {
@GeoIndexed Point location;
}
repository.save(new Person("rand", "al'thor"));
HMSET "people:19315449-cda2-4f5c-b696-9cb8018fa1f9" "_class" "Person" "id" "19315449-cda2-4f5c-b696-9cb8018fa1f9" "firstname" "rand" "lastname" "al'thor" // (1)
SADD "people" "19315449-cda2-4f5c-b696-9cb8018fa1f9" // (2)
SADD "people:firstname:rand" "19315449-cda2-4f5c-b696-9cb8018fa1f9" // (3)
SADD "people:19315449-cda2-4f5c-b696-9cb8018fa1f9:idx" "people:firstname:rand" // (4)
1. Save the flattened entry as hash.
2. Add the key of the hash written in (1) to the helper index of entities in the same keyspace.
3. Add the key of the hash written in (2) to the secondary index of firstnames with the properties value.
4. Add the index of (3) to the set of helper structures for entry to keep track of indexes to clean on delete/update.
repository.save(new Person("e82908cf-e7d3-47c2-9eec-b4e0967ad0c9", "Dragon Reborn", "al'thor"));
DEL "people:e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" // (1)
HMSET "people:e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" "_class" "Person" "id" "e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" "firstname" "Dragon Reborn" "lastname" "al'thor" // (2)
SADD "people" "e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" // (3)
SMEMBERS "people:e82908cf-e7d3-47c2-9eec-b4e0967ad0c9:idx" // (4)
TYPE "people:firstname:rand" // (5)
SREM "people:firstname:rand" "e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" // (6)
DEL "people:e82908cf-e7d3-47c2-9eec-b4e0967ad0c9:idx" // (7)
SADD "people:firstname:Dragon Reborn" "e82908cf-e7d3-47c2-9eec-b4e0967ad0c9" // (8)
SADD "people:e82908cf-e7d3-47c2-9eec-b4e0967ad0c9:idx" "people:firstname:Dragon Reborn" // (9)
1. Remove the existing hash to avoid leftovers of hash keys potentially no longer present.
2. Save the flattened entry as hash.
3. Add the key of the hash written in (1) to the helper index of entities in the same keyspace.
4. Get existing index structures that might need to be updated.
5. Check if the index exists and what type it is (text, geo, …).
6. Remove a potentially existing key from the index.
7. Remove the helper holding index information.
8. Add the key of the hash added in (2) to the secondary index of firstnames with the properties value.
9. Add the index of (6) to the set of helper structures for entry to keep track of indexes to clean on delete/update.

Geo indexes follow the same rules as normal text based ones but use geo structure to store values. Saving an entity that uses a Geo-indexed property results in the following commands:

GEOADD "people:hometown:location" "13.361389" "38.115556" "76900e94-b057-44bc-abcf-8126d51a621b" // (1)
SADD "people:76900e94-b057-44bc-abcf-8126d51a621b:idx" "people:hometown:location" // (2)
1. Add the key of the saved entry to the the geo index.
2. Keep track of the index structure.
repository.findByFirstname("egwene");
SINTER "people:firstname:egwene" // (1)
HGETALL "people:d70091b5-0b9a-4c0a-9551-519e61bc9ef3" // (2)
HGETALL ...
1. Fetch keys contained in the secondary index.
2. Fetch each key returned by (1) individually.
repository.findByHometownLocationNear(new Point(15, 37), new Distance(200, KILOMETERS));
GEORADIUS "people:hometown:location" "15.0" "37.0" "200.0" "km" // (1)
HGETALL "people:76900e94-b057-44bc-abcf-8126d51a621b" // (2)
HGETALL ...
1. Fetch keys contained in the secondary index.
2. Fetch each key returned by (1) individually.