Skip to content

Commit b42cae6

Browse files
committed
Correct VLINKS return types #3404
VLINKS returns one collection per HNSW graph level. Preserve those levels for plain and WITHSCORES responses across all command APIs and decode both RESP2 arrays and RESP3 maps.
1 parent 2a98186 commit b42cae6

17 files changed

Lines changed: 274 additions & 57 deletions

src/main/java/io/lettuce/core/AbstractRedisAsyncCommands.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@
115115
* @author SeugnSu Kim
116116
* @author Yordan Tsintsov
117117
* @author dae won
118+
* @author hutiefang76
118119
*/
119120
@SuppressWarnings("unchecked")
120121
public abstract class AbstractRedisAsyncCommands<K, V> implements RedisAclAsyncCommands<K, V>, RedisHashAsyncCommands<K, V>,
@@ -2185,12 +2186,12 @@ public RedisFuture<VectorMetadata> vinfo(K key) {
21852186
}
21862187

21872188
@Override
2188-
public RedisFuture<List<V>> vlinks(K key, V element) {
2189+
public RedisFuture<List<List<V>>> vlinks(K key, V element) {
21892190
return dispatch(vectorSetCommandBuilder.vlinks(key, element));
21902191
}
21912192

21922193
@Override
2193-
public RedisFuture<Map<V, Double>> vlinksWithScores(K key, V element) {
2194+
public RedisFuture<List<Map<V, Double>>> vlinksWithScores(K key, V element) {
21942195
return dispatch(vectorSetCommandBuilder.vlinksWithScores(key, element));
21952196
}
21962197

src/main/java/io/lettuce/core/AbstractRedisReactiveCommands.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,7 @@
121121
* @author SeugnSu Kim
122122
* @author Yordan Tsintsov
123123
* @author dae won
124+
* @author hutiefang76
124125
* @since 4.0
125126
*/
126127
public abstract class AbstractRedisReactiveCommands<K, V>
@@ -2277,12 +2278,12 @@ public Mono<VectorMetadata> vinfo(K key) {
22772278
}
22782279

22792280
@Override
2280-
public Flux<V> vlinks(K key, V element) {
2281+
public Flux<List<V>> vlinks(K key, V element) {
22812282
return createDissolvingFlux(() -> vectorSetCommandBuilder.vlinks(key, element));
22822283
}
22832284

22842285
@Override
2285-
public Mono<Map<V, Double>> vlinksWithScores(K key, V element) {
2286+
public Mono<List<Map<V, Double>>> vlinksWithScores(K key, V element) {
22862287
return createMono(() -> vectorSetCommandBuilder.vlinksWithScores(key, element));
22872288
}
22882289

src/main/java/io/lettuce/core/RedisVectorSetCommandBuilder.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
* @param <K> Key type.
3535
* @param <V> Value type.
3636
* @author Tihomir Mateev
37+
* @author hutiefang76
3738
* @since 6.7
3839
*/
3940
public class RedisVectorSetCommandBuilder<K, V> extends BaseRedisCommandBuilder<K, V> {
@@ -251,11 +252,11 @@ public Command<K, V, VectorMetadata> vinfo(K key) {
251252
* @return a new {@link Command} that returns a list of elements that are linked to the specified element
252253
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
253254
*/
254-
public Command<K, V, List<V>> vlinks(K key, V element) {
255+
public Command<K, V, List<List<V>>> vlinks(K key, V element) {
255256
notNullKey(key);
256257
notNullKey(element);
257258
CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).addValue(element);
258-
return createCommand(VLINKS, new ValueListOutput<>(codec), args);
259+
return createCommand(VLINKS, new ValueListListOutput<>(codec), args);
259260
}
260261

261262
/**
@@ -266,11 +267,11 @@ public Command<K, V, List<V>> vlinks(K key, V element) {
266267
* @return a new {@link Command} that returns a list of elements with their similarity scores
267268
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
268269
*/
269-
public Command<K, V, Map<V, Double>> vlinksWithScores(K key, V element) {
270+
public Command<K, V, List<Map<V, Double>>> vlinksWithScores(K key, V element) {
270271
notNullKey(key);
271272
notNullKey(element);
272273
CommandArgs<K, V> args = new CommandArgs<>(codec).addKey(key).addValue(element).add(WITHSCORES);
273-
return createCommand(VLINKS, new ValueDoubleMapOutput<>(codec), args);
274+
return createCommand(VLINKS, new ValueDoubleMapListOutput<>(codec), args);
274275
}
275276

276277
/**

src/main/java/io/lettuce/core/api/async/RedisVectorSetAsyncCommands.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
* @param <K> Key type.
3030
* @param <V> Value type.
3131
* @author Tihomir Mateev
32+
* @author hutiefang76
3233
* @see <a href="https://redis.io/docs/latest/develop/data-types/vector-sets/">Redis Vector Sets</a>
3334
* @since 6.7
3435
* @generated by io.lettuce.apigenerator.CreateAsyncApi
@@ -253,13 +254,12 @@ public interface RedisVectorSetAsyncCommands<K, V> {
253254
*
254255
* @param key the key of the vector set
255256
* @param element the name of the element in the vector set
256-
* @return a list of elements that are linked to the specified element, or an empty list if the key or element does not
257-
* exist
257+
* @return linked elements grouped by HNSW graph level, or an empty list if the key or element does not exist
258258
* @since 6.7
259259
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
260260
*/
261261
@Experimental
262-
RedisFuture<List<V>> vlinks(K key, V element);
262+
RedisFuture<List<List<V>>> vlinks(K key, V element);
263263

264264
/**
265265
* Returns the neighbors of the specified {@code element} in the HNSW graph along with their scores.
@@ -270,12 +270,13 @@ public interface RedisVectorSetAsyncCommands<K, V> {
270270
*
271271
* @param key the key of the vector set
272272
* @param element the name of the element in the vector set
273-
* @return a list of elements with their similarity scores, or an empty list if the key or element does not exist
273+
* @return linked elements and their scores grouped by HNSW graph level, or an empty list if the key or element does not
274+
* exist
274275
* @since 6.7
275276
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
276277
*/
277278
@Experimental
278-
RedisFuture<Map<V, Double>> vlinksWithScores(K key, V element);
279+
RedisFuture<List<Map<V, Double>>> vlinksWithScores(K key, V element);
279280

280281
/**
281282
* Returns a random element from the vector set stored at {@code key}. This command is useful for sampling elements for

src/main/java/io/lettuce/core/api/reactive/RedisVectorSetReactiveCommands.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package io.lettuce.core.api.reactive;
88

99
import java.util.Map;
10+
import java.util.List;
1011
import io.lettuce.core.VAddArgs;
1112
import io.lettuce.core.VSimArgs;
1213
import io.lettuce.core.annotations.Experimental;
@@ -29,6 +30,7 @@
2930
* @param <K> Key type.
3031
* @param <V> Value type.
3132
* @author Tihomir Mateev
33+
* @author hutiefang76
3234
* @see <a href="https://redis.io/docs/latest/develop/data-types/vector-sets/">Redis Vector Sets</a>
3335
* @since 6.7
3436
* @generated by io.lettuce.apigenerator.CreateReactiveApi
@@ -253,13 +255,12 @@ public interface RedisVectorSetReactiveCommands<K, V> {
253255
*
254256
* @param key the key of the vector set
255257
* @param element the name of the element in the vector set
256-
* @return a list of elements that are linked to the specified element, or an empty list if the key or element does not
257-
* exist
258+
* @return linked elements grouped by HNSW graph level, or an empty list if the key or element does not exist
258259
* @since 6.7
259260
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
260261
*/
261262
@Experimental
262-
Flux<V> vlinks(K key, V element);
263+
Flux<List<V>> vlinks(K key, V element);
263264

264265
/**
265266
* Returns the neighbors of the specified {@code element} in the HNSW graph along with their scores.
@@ -270,12 +271,13 @@ public interface RedisVectorSetReactiveCommands<K, V> {
270271
*
271272
* @param key the key of the vector set
272273
* @param element the name of the element in the vector set
273-
* @return a list of elements with their similarity scores, or an empty list if the key or element does not exist
274+
* @return linked elements and their scores grouped by HNSW graph level, or an empty list if the key or element does not
275+
* exist
274276
* @since 6.7
275277
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
276278
*/
277279
@Experimental
278-
Mono<Map<V, Double>> vlinksWithScores(K key, V element);
280+
Mono<List<Map<V, Double>>> vlinksWithScores(K key, V element);
279281

280282
/**
281283
* Returns a random element from the vector set stored at {@code key}. This command is useful for sampling elements for

src/main/java/io/lettuce/core/api/sync/RedisVectorSetCommands.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* @param <K> Key type.
2929
* @param <V> Value type.
3030
* @author Tihomir Mateev
31+
* @author hutiefang76
3132
* @see <a href="https://redis.io/docs/latest/develop/data-types/vector-sets/">Redis Vector Sets</a>
3233
* @since 6.7
3334
* @generated by io.lettuce.apigenerator.CreateSyncApi
@@ -252,13 +253,12 @@ public interface RedisVectorSetCommands<K, V> {
252253
*
253254
* @param key the key of the vector set
254255
* @param element the name of the element in the vector set
255-
* @return a list of elements that are linked to the specified element, or an empty list if the key or element does not
256-
* exist
256+
* @return linked elements grouped by HNSW graph level, or an empty list if the key or element does not exist
257257
* @since 6.7
258258
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
259259
*/
260260
@Experimental
261-
List<V> vlinks(K key, V element);
261+
List<List<V>> vlinks(K key, V element);
262262

263263
/**
264264
* Returns the neighbors of the specified {@code element} in the HNSW graph along with their scores.
@@ -269,12 +269,13 @@ public interface RedisVectorSetCommands<K, V> {
269269
*
270270
* @param key the key of the vector set
271271
* @param element the name of the element in the vector set
272-
* @return a list of elements with their similarity scores, or an empty list if the key or element does not exist
272+
* @return linked elements and their scores grouped by HNSW graph level, or an empty list if the key or element does not
273+
* exist
273274
* @since 6.7
274275
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
275276
*/
276277
@Experimental
277-
Map<V, Double> vlinksWithScores(K key, V element);
278+
List<Map<V, Double>> vlinksWithScores(K key, V element);
278279

279280
/**
280281
* Returns a random element from the vector set stored at {@code key}. This command is useful for sampling elements for

src/main/java/io/lettuce/core/cluster/api/async/NodeSelectionVectorSetAsyncCommands.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* @param <K> Key type.
2929
* @param <V> Value type.
3030
* @author Tihomir Mateev
31+
* @author hutiefang76
3132
* @see <a href="https://redis.io/docs/latest/develop/data-types/vector-sets/">Redis Vector Sets</a>
3233
* @since 6.7
3334
* @generated by io.lettuce.apigenerator.CreateAsyncNodeSelectionClusterApi
@@ -252,13 +253,12 @@ public interface NodeSelectionVectorSetAsyncCommands<K, V> {
252253
*
253254
* @param key the key of the vector set
254255
* @param element the name of the element in the vector set
255-
* @return a list of elements that are linked to the specified element, or an empty list if the key or element does not
256-
* exist
256+
* @return linked elements grouped by HNSW graph level, or an empty list if the key or element does not exist
257257
* @since 6.7
258258
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
259259
*/
260260
@Experimental
261-
AsyncExecutions<List<V>> vlinks(K key, V element);
261+
AsyncExecutions<List<List<V>>> vlinks(K key, V element);
262262

263263
/**
264264
* Returns the neighbors of the specified {@code element} in the HNSW graph along with their scores.
@@ -269,12 +269,13 @@ public interface NodeSelectionVectorSetAsyncCommands<K, V> {
269269
*
270270
* @param key the key of the vector set
271271
* @param element the name of the element in the vector set
272-
* @return a list of elements with their similarity scores, or an empty list if the key or element does not exist
272+
* @return linked elements and their scores grouped by HNSW graph level, or an empty list if the key or element does not
273+
* exist
273274
* @since 6.7
274275
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
275276
*/
276277
@Experimental
277-
AsyncExecutions<Map<V, Double>> vlinksWithScores(K key, V element);
278+
AsyncExecutions<List<Map<V, Double>>> vlinksWithScores(K key, V element);
278279

279280
/**
280281
* Returns a random element from the vector set stored at {@code key}. This command is useful for sampling elements for

src/main/java/io/lettuce/core/cluster/api/sync/NodeSelectionVectorSetCommands.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
* @param <K> Key type.
2929
* @param <V> Value type.
3030
* @author Tihomir Mateev
31+
* @author hutiefang76
3132
* @see <a href="https://redis.io/docs/latest/develop/data-types/vector-sets/">Redis Vector Sets</a>
3233
* @since 6.7
3334
* @generated by io.lettuce.apigenerator.CreateSyncNodeSelectionClusterApi
@@ -252,13 +253,12 @@ public interface NodeSelectionVectorSetCommands<K, V> {
252253
*
253254
* @param key the key of the vector set
254255
* @param element the name of the element in the vector set
255-
* @return a list of elements that are linked to the specified element, or an empty list if the key or element does not
256-
* exist
256+
* @return linked elements grouped by HNSW graph level, or an empty list if the key or element does not exist
257257
* @since 6.7
258258
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
259259
*/
260260
@Experimental
261-
Executions<List<V>> vlinks(K key, V element);
261+
Executions<List<List<V>>> vlinks(K key, V element);
262262

263263
/**
264264
* Returns the neighbors of the specified {@code element} in the HNSW graph along with their scores.
@@ -269,12 +269,13 @@ public interface NodeSelectionVectorSetCommands<K, V> {
269269
*
270270
* @param key the key of the vector set
271271
* @param element the name of the element in the vector set
272-
* @return a list of elements with their similarity scores, or an empty list if the key or element does not exist
272+
* @return linked elements and their scores grouped by HNSW graph level, or an empty list if the key or element does not
273+
* exist
273274
* @since 6.7
274275
* @see <a href="https://redis.io/docs/latest/commands/vlinks/">Redis Documentation: VLINKS</a>
275276
*/
276277
@Experimental
277-
Executions<Map<V, Double>> vlinksWithScores(K key, V element);
278+
Executions<List<Map<V, Double>>> vlinksWithScores(K key, V element);
278279

279280
/**
280281
* Returns a random element from the vector set stored at {@code key}. This command is useful for sampling elements for
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/*
2+
* Copyright 2026, Redis Ltd. and Contributors
3+
* All rights reserved.
4+
*
5+
* Licensed under the MIT License.
6+
*/
7+
8+
package io.lettuce.core.output;
9+
10+
import io.lettuce.core.codec.RedisCodec;
11+
12+
import java.nio.ByteBuffer;
13+
import java.util.Collections;
14+
import java.util.List;
15+
import java.util.Map;
16+
17+
/**
18+
* {@link List} of value-to-double maps output.
19+
*
20+
* @param <K> Key type.
21+
* @param <V> Value type.
22+
*
23+
* @author hutiefang76
24+
* @since 7.7
25+
*/
26+
public class ValueDoubleMapListOutput<K, V> extends CommandOutput<K, V, List<Map<V, Double>>> {
27+
28+
private boolean initialized;
29+
30+
private ValueDoubleMapOutput<K, V> nested;
31+
32+
public ValueDoubleMapListOutput(RedisCodec<K, V> codec) {
33+
super(codec, Collections.emptyList());
34+
}
35+
36+
@Override
37+
public void set(ByteBuffer bytes) {
38+
if (nested != null) {
39+
nested.set(bytes);
40+
}
41+
}
42+
43+
@Override
44+
public void set(double number) {
45+
if (nested != null) {
46+
nested.set(number);
47+
}
48+
}
49+
50+
@Override
51+
public void complete(int depth) {
52+
if (nested != null && !output.isEmpty()) {
53+
output.set(output.size() - 1, nested.get());
54+
}
55+
}
56+
57+
@Override
58+
public void multi(int count) {
59+
if (!initialized) {
60+
output = OutputFactory.newList(count);
61+
initialized = true;
62+
return;
63+
}
64+
65+
nested = new ValueDoubleMapOutput<>(codec);
66+
nested.multi(count);
67+
output.add(nested.get());
68+
}
69+
70+
}

0 commit comments

Comments
 (0)