Skip to content

Commit a61a59d

Browse files
uglideggivo
andauthored
Add support for SVS-VAMANA vector indexing (#4222)
* Add support for SVS-VAMANA vector indexing * Update VectorAlgo to be Raw-able mitigating '-' in SVS-VAMANA --------- Co-authored-by: Ivo Gaydazhiev <[email protected]> * anotate test with @SinceRedisVersion("8.1.240") * add missing import --------- Co-authored-by: Ivo Gaydazhiev <[email protected]>
1 parent 3be29f5 commit a61a59d

File tree

5 files changed

+383
-7
lines changed

5 files changed

+383
-7
lines changed

src/main/java/redis/clients/jedis/search/Schema.java

Lines changed: 78 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55
import java.util.Map;
66

77
import redis.clients.jedis.CommandArguments;
8+
import redis.clients.jedis.args.Rawable;
89
import redis.clients.jedis.params.IParams;
10+
import redis.clients.jedis.util.SafeEncoder;
911

1012
/**
1113
* Schema abstracts the schema definition when creating an index. Documents can contain fields not
@@ -138,6 +140,21 @@ public Schema addHNSWVectorField(String name, Map<String, Object> attributes) {
138140
return this;
139141
}
140142

143+
/**
144+
* Add a Vamana vector field to the schema using the SVS-VAMANA algorithm.
145+
* This method provides a convenient way to add SVS-VAMANA vector fields.
146+
*
147+
* @param name the field's name
148+
* @param attributes the SVS-Vamana algorithm configuration attributes
149+
* @return the schema object
150+
*/
151+
public Schema addSvsVamanaVectorField(String name, Map<String, Object> attributes) {
152+
// Use the existing VectorField with SVS_VAMANA algorithm
153+
Map<String, Object> vamanaAttributes = new java.util.HashMap<>(attributes);
154+
fields.add(new VectorField(name, VectorField.VectorAlgo.SVS_VAMANA, vamanaAttributes));
155+
return this;
156+
}
157+
141158
public Schema addField(Field field) {
142159
fields.add(field);
143160
return this;
@@ -348,9 +365,65 @@ public String toString() {
348365

349366
public static class VectorField extends Field {
350367

351-
public enum VectorAlgo {
352-
FLAT,
353-
HNSW
368+
369+
/**
370+
* Enumeration of supported vector indexing algorithms in Redis.
371+
* Each algorithm has different performance characteristics and use cases.
372+
*/
373+
public enum VectorAlgo implements Rawable {
374+
375+
/**
376+
* FLAT algorithm provides exact vector search with perfect accuracy.
377+
* Best suited for smaller datasets (&lt; 1M vectors) where search accuracy
378+
* is more important than search latency.
379+
*/
380+
FLAT("FLAT"),
381+
382+
/**
383+
* HNSW (Hierarchical Navigable Small World) algorithm provides approximate
384+
* vector search with configurable accuracy-performance trade-offs.
385+
* Best suited for larger datasets (&gt; 1M vectors) where search performance
386+
* and scalability are more important than perfect accuracy.
387+
*/
388+
HNSW("HNSW"),
389+
390+
/**
391+
* SVS_VAMANA algorithm provides high-performance approximate vector search
392+
* optimized for specific use cases with advanced compression and optimization features.
393+
*
394+
* <p>Characteristics:
395+
* <ul>
396+
* <li>High-performance approximate search</li>
397+
* <li>Support for vector compression (LVQ, LeanVec)</li>
398+
* <li>Configurable graph construction and search parameters</li>
399+
* <li>Optimized for Intel platforms with fallback support</li>
400+
* </ul>
401+
*
402+
* <p>Note: This algorithm may have specific requirements and limitations.
403+
* Consult the Redis documentation for detailed usage guidelines.
404+
*/
405+
SVS_VAMANA("SVS-VAMANA");
406+
407+
private final byte[] raw;
408+
409+
/**
410+
* Creates a VectorAlgorithm enum value.
411+
*
412+
* @param redisParamName the Redis parameter name for this algorithm
413+
*/
414+
VectorAlgo(String redisParamName) {
415+
raw = SafeEncoder.encode(redisParamName);
416+
}
417+
418+
/**
419+
* Returns the raw byte representation of the algorithm name for Redis commands.
420+
*
421+
* @return the raw bytes of the algorithm name
422+
*/
423+
@Override
424+
public byte[] getRaw() {
425+
return raw;
426+
}
354427
}
355428

356429
private final VectorAlgo algorithm;
@@ -364,7 +437,9 @@ public VectorField(String name, VectorAlgo algorithm, Map<String, Object> attrib
364437

365438
@Override
366439
public void addTypeArgs(CommandArguments args) {
440+
367441
args.add(algorithm);
442+
368443
args.add(attributes.size() << 1);
369444
for (Map.Entry<String, Object> entry : attributes.entrySet()) {
370445
args.add(entry.getKey());

src/main/java/redis/clients/jedis/search/schemafields/VectorField.java

Lines changed: 179 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,77 @@
66
import java.util.LinkedHashMap;
77
import java.util.Map;
88
import redis.clients.jedis.CommandArguments;
9+
import redis.clients.jedis.args.Rawable;
910
import redis.clients.jedis.search.FieldName;
11+
import redis.clients.jedis.util.SafeEncoder;
1012

13+
/**
14+
* Represents a vector field in a Redis search index schema for performing semantic vector searches.
15+
* Vector fields enable high-performance similarity searches over vector embeddings using various
16+
* algorithms and distance metrics.
17+
*
18+
* @see <a href="https://redis.io/docs/latest/develop/ai/search-and-query/vectors/">Redis Vector Search Documentation</a>
19+
*/
1120
public class VectorField extends SchemaField {
1221

13-
public enum VectorAlgorithm {
14-
FLAT,
15-
HNSW
22+
/**
23+
* Enumeration of supported vector indexing algorithms in Redis.
24+
* Each algorithm has different performance characteristics and use cases.
25+
*/
26+
public enum VectorAlgorithm implements Rawable {
27+
28+
/**
29+
* FLAT algorithm provides exact vector search with perfect accuracy.
30+
* Best suited for smaller datasets (&lt; 1M vectors) where search accuracy
31+
* is more important than search latency.
32+
*/
33+
FLAT("FLAT"),
34+
35+
/**
36+
* HNSW (Hierarchical Navigable Small World) algorithm provides approximate
37+
* vector search with configurable accuracy-performance trade-offs.
38+
* Best suited for larger datasets (&gt; 1M vectors) where search performance
39+
* and scalability are more important than perfect accuracy.
40+
*/
41+
HNSW("HNSW"),
42+
43+
/**
44+
* SVS_VAMANA algorithm provides high-performance approximate vector search
45+
* optimized for specific use cases with advanced compression and optimization features.
46+
*
47+
* <p>Characteristics:
48+
* <ul>
49+
* <li>High-performance approximate search</li>
50+
* <li>Support for vector compression (LVQ, LeanVec)</li>
51+
* <li>Configurable graph construction and search parameters</li>
52+
* <li>Optimized for Intel platforms with fallback support</li>
53+
* </ul>
54+
*
55+
* <p>Note: This algorithm may have specific requirements and limitations.
56+
* Consult the Redis documentation for detailed usage guidelines.
57+
*/
58+
SVS_VAMANA("SVS-VAMANA");
59+
60+
private final byte[] raw;
61+
62+
/**
63+
* Creates a VectorAlgorithm enum value.
64+
*
65+
* @param redisParamName the Redis parameter name for this algorithm
66+
*/
67+
VectorAlgorithm(String redisParamName) {
68+
raw = SafeEncoder.encode(redisParamName);
69+
}
70+
71+
/**
72+
* Returns the raw byte representation of the algorithm name for Redis commands.
73+
*
74+
* @return the raw bytes of the algorithm name
75+
*/
76+
@Override
77+
public byte[] getRaw() {
78+
return raw;
79+
}
1680
}
1781

1882
private final VectorAlgorithm algorithm;
@@ -21,29 +85,70 @@ public enum VectorAlgorithm {
2185
private boolean indexMissing;
2286
// private boolean noIndex; // throws Field `NOINDEX` does not have a type
2387

88+
/**
89+
* Creates a new VectorField with the specified field name, algorithm, and attributes.
90+
*
91+
* @param fieldName the name of the vector field in the index
92+
* @param algorithm the vector indexing algorithm to use
93+
* @param attributes the algorithm-specific configuration attributes
94+
* @throws IllegalArgumentException if required attributes are missing or invalid
95+
*/
2496
public VectorField(String fieldName, VectorAlgorithm algorithm, Map<String, Object> attributes) {
2597
super(fieldName);
2698
this.algorithm = algorithm;
2799
this.attributes = attributes;
28100
}
29101

102+
/**
103+
* Creates a new VectorField with the specified field name, algorithm, and attributes.
104+
*
105+
* @param fieldName the field name object containing the field name and optional alias
106+
* @param algorithm the vector indexing algorithm to use
107+
* @param attributes the algorithm-specific configuration attributes
108+
* @throws IllegalArgumentException if required attributes are missing or invalid
109+
* @see #VectorField(String, VectorAlgorithm, Map) for detailed attribute documentation
110+
*/
30111
public VectorField(FieldName fieldName, VectorAlgorithm algorithm, Map<String, Object> attributes) {
31112
super(fieldName);
32113
this.algorithm = algorithm;
33114
this.attributes = attributes;
34115
}
35116

117+
/**
118+
* Sets an alias for this field that can be used in queries instead of the field name.
119+
* This is useful when the field name contains special characters or when you want
120+
* to use a shorter name in queries.
121+
*
122+
* @param attribute the alias name to use for this field in queries
123+
* @return this VectorField instance for method chaining
124+
*/
36125
@Override
37126
public VectorField as(String attribute) {
38127
super.as(attribute);
39128
return this;
40129
}
41130

131+
/**
132+
* Configures the field to handle missing values during indexing.
133+
* When enabled, documents that don't contain this vector field will still be indexed,
134+
* but won't participate in vector searches.
135+
*
136+
* <p>This is useful when not all documents in your dataset contain vector embeddings,
137+
* but you still want to index them for other types of searches.
138+
*
139+
* @return this VectorField instance for method chaining
140+
*/
42141
public VectorField indexMissing() {
43142
this.indexMissing = true;
44143
return this;
45144
}
46145

146+
/**
147+
* Adds the vector field parameters to the Redis command arguments.
148+
* This method is used internally when creating the search index.
149+
*
150+
* @param args the command arguments to add parameters to
151+
*/
47152
@Override
48153
public void addParams(CommandArguments args) {
49154
args.addParams(fieldName);
@@ -58,51 +163,122 @@ public void addParams(CommandArguments args) {
58163
}
59164
}
60165

166+
/**
167+
* Creates a new Builder instance for constructing VectorField objects using the builder pattern.
168+
* The builder pattern provides a fluent interface for setting field properties and is especially
169+
* useful when dealing with complex vector field configurations.
170+
*
171+
* @return a new Builder instance
172+
*/
61173
public static Builder builder() {
62174
return new Builder();
63175
}
64176

177+
/**
178+
* Builder class for constructing VectorField instances using the builder pattern.
179+
* Provides a fluent interface for setting vector field properties and attributes.
180+
*
181+
* <p>Example usage:
182+
* <pre>{@code
183+
* VectorField field = VectorField.builder()
184+
* .fieldName("product_embedding")
185+
* .algorithm(VectorAlgorithm.HNSW)
186+
* .addAttribute("TYPE", "FLOAT32")
187+
* .addAttribute("DIM", 768)
188+
* .addAttribute("DISTANCE_METRIC", "COSINE")
189+
* .addAttribute("M", 32)
190+
* .addAttribute("EF_CONSTRUCTION", 200)
191+
* .build();
192+
* }</pre>
193+
*/
65194
public static class Builder {
66195

67196
private FieldName fieldName;
68197
private VectorAlgorithm algorithm;
69198
private Map<String, Object> attributes;
70199

200+
/**
201+
* Private constructor to enforce use of the static builder() method.
202+
*/
71203
private Builder() {
72204
}
73205

206+
/**
207+
* Builds and returns a new VectorField instance with the configured properties.
208+
*
209+
* @return a new VectorField instance
210+
* @throws IllegalArgumentException if required parameters (fieldName, algorithm, or attributes) are not set
211+
*/
74212
public VectorField build() {
75213
if (fieldName == null || algorithm == null || attributes == null || attributes.isEmpty()) {
76214
throw new IllegalArgumentException("All required VectorField parameters are not set.");
77215
}
78216
return new VectorField(fieldName, algorithm, attributes);
79217
}
80218

219+
/**
220+
* Sets the field name for the vector field.
221+
*
222+
* @param fieldName the name of the vector field in the index
223+
* @return this Builder instance for method chaining
224+
*/
81225
public Builder fieldName(String fieldName) {
82226
this.fieldName = FieldName.of(fieldName);
83227
return this;
84228
}
85229

230+
/**
231+
* Sets the field name using a FieldName object.
232+
*
233+
* @param fieldName the FieldName object containing the field name and optional alias
234+
* @return this Builder instance for method chaining
235+
*/
86236
public Builder fieldName(FieldName fieldName) {
87237
this.fieldName = fieldName;
88238
return this;
89239
}
90240

241+
/**
242+
* Sets an alias for the field that can be used in queries.
243+
*
244+
* @param attribute the alias name to use for this field in queries
245+
* @return this Builder instance for method chaining
246+
*/
91247
public Builder as(String attribute) {
92248
this.fieldName.as(attribute);
93249
return this;
94250
}
95251

252+
/**
253+
* Sets the vector indexing algorithm to use.
254+
*
255+
* @param algorithm the vector algorithm (FLAT, HNSW, or SVS_VAMANA)
256+
* @return this Builder instance for method chaining
257+
*/
96258
public Builder algorithm(VectorAlgorithm algorithm) {
97259
this.algorithm = algorithm;
98260
return this;
99261
}
100262

263+
/**
264+
* Sets all vector field attributes at once, replacing any previously set attributes.
265+
*
266+
* @param attributes a map of attribute names to values
267+
* @return this Builder instance for method chaining
268+
*/
101269
public Builder attributes(Map<String, Object> attributes) {
102270
this.attributes = attributes;
103271
return this;
104272
}
105273

274+
/**
275+
* Adds a single attribute to the vector field configuration.
276+
* If this is the first attribute added, initializes the attributes map.
277+
*
278+
* @param name the attribute name
279+
* @param value the attribute value
280+
* @return this Builder instance for method chaining
281+
*/
106282
public Builder addAttribute(String name, Object value) {
107283
if (this.attributes == null) {
108284
this.attributes = new LinkedHashMap<>();

0 commit comments

Comments
 (0)