Skip to content

Commit 5fe530c

Browse files
Polishing.
Turn newly introduced methods on ParameterAccessor into default ones allowing modules to pick up changes at their own pace. Add issue references and missing documentation. Align Search- and GeoResults toString method with Page. Original Pull Request: #3285
1 parent ba8cb27 commit 5fe530c

File tree

11 files changed

+56
-42
lines changed

11 files changed

+56
-42
lines changed

src/main/antora/modules/ROOT/pages/repositories/vector-search.adoc

+6-6
Original file line numberDiff line numberDiff line change
@@ -80,11 +80,11 @@ Score values are not part of a domain model and therefore represented best as ou
8080
Generally, a Score is computed by a `ScoringFunction`.
8181
The actual scoring function used to calculate this score can depends on the underlying database and can be obtained from a search index or input parameters.
8282

83-
Spring Data supports declares constants for commonly used functions such as:
83+
Spring Data support declares constants for commonly used functions such as:
8484

85-
Euclidean distance:: Calculates the straight-line distance in n-dimensional space involving the square root of the sum of squared differences.
86-
Cosine similarity:: Measures the angle between two vectors by calculating the Dot product first and then normalizing its result by dividing by the product of their lengths.
87-
Dot product:: Computes the sum of element-wise multiplications.
85+
Euclidean Distance:: Calculates the straight-line distance in n-dimensional space involving the square root of the sum of squared differences.
86+
Cosine Similarity:: Measures the angle between two vectors by calculating the Dot product first and then normalizing its result by dividing by the product of their lengths.
87+
Dot Product:: Computes the sum of element-wise multiplications.
8888

8989
The choice of similarity function can impact both the performance and semantics of the search and is often determined by the underlying database or index being used.
9090
Spring Data adopts to the database's native scoring function capabilities and whether the score can be used to limit results.
@@ -107,7 +107,7 @@ Generally, you have the choice of declaring a search method using two approaches
107107
* Query Derivation
108108
* Declaring a String-based Query
109109

110-
Generally, Vector Search methods must declare a `Vector` parameter to define the query vector.
110+
Vector Search methods must declare a `Vector` parameter to define the query vector.
111111

112112
[[vector-search.method.derivation]]
113113
=== Derived Search Methods
@@ -142,7 +142,7 @@ endif::[]
142142

143143
With more control over the actual query, Spring Data can make fewer assumptions about the query and its parameters.
144144
For example, `Similarity` normalization uses the native score function within the query to normalize the given similarity into a score predicate value and vice versa.
145-
If an annotated query doesn't define e.g. the score, then the score value in the returned `SearchResult<T>` will be zero.
145+
If an annotated query does not define e.g. the score, then the score value in the returned `SearchResult<T>` will be zero.
146146

147147
[[vector-search.method.sorting]]
148148
=== Sorting

src/main/java/org/springframework/data/domain/SearchResult.java

-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.function.Function;
2121

2222
import org.jspecify.annotations.Nullable;
23-
2423
import org.springframework.util.Assert;
2524
import org.springframework.util.ObjectUtils;
2625

src/main/java/org/springframework/data/domain/SearchResults.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.springframework.data.util.Streamable;
2727
import org.springframework.util.Assert;
2828
import org.springframework.util.ObjectUtils;
29-
import org.springframework.util.StringUtils;
3029

3130
/**
3231
* Value object encapsulating a collection of {@link SearchResult} instances.
@@ -123,8 +122,7 @@ public int hashCode() {
123122

124123
@Override
125124
public String toString() {
126-
return results.isEmpty() ? "SearchResults: [empty]"
127-
: String.format("SearchResults: [results: %s]", StringUtils.collectionToCommaDelimitedString(results));
125+
return results.isEmpty() ? "SearchResults [empty]" : String.format("SearchResults [size: %s]", results.size());
128126
}
129127

130128
}

src/main/java/org/springframework/data/geo/GeoResult.java

+1-2
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import java.io.Serializable;
2020

2121
import org.jspecify.annotations.Nullable;
22-
2322
import org.springframework.util.Assert;
2423
import org.springframework.util.ObjectUtils;
2524

@@ -79,6 +78,6 @@ public int hashCode() {
7978

8079
@Override
8180
public String toString() {
82-
return String.format("GeoResult [content: %s, distance: %s, ]", content.toString(), distance.toString());
81+
return String.format("GeoResult [content: %s, distance: %s]", content, distance);
8382
}
8483
}

src/main/java/org/springframework/data/geo/GeoResults.java

+2-5
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,16 @@
1515
*/
1616
package org.springframework.data.geo;
1717

18-
1918
import java.io.Serial;
2019
import java.io.Serializable;
2120
import java.util.Collections;
2221
import java.util.Iterator;
2322
import java.util.List;
2423

2524
import org.jspecify.annotations.Nullable;
26-
2725
import org.springframework.data.annotation.PersistenceCreator;
2826
import org.springframework.util.Assert;
2927
import org.springframework.util.ObjectUtils;
30-
import org.springframework.util.StringUtils;
3128

3229
/**
3330
* Value object to capture {@link GeoResult}s as well as the average distance they have.
@@ -129,8 +126,8 @@ public int hashCode() {
129126

130127
@Override
131128
public String toString() {
132-
return String.format("GeoResults: [averageDistance: %s, results: %s]", averageDistance.toString(),
133-
StringUtils.collectionToCommaDelimitedString(results));
129+
return results.isEmpty() ? "GeoResults [empty]"
130+
: String.format("GeoResults [averageDistance: %s, size: %s]", averageDistance, results.size());
134131
}
135132

136133
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {

src/main/java/org/springframework/data/repository/query/ParameterAccessor.java

+9-6
Original file line numberDiff line numberDiff line change
@@ -39,22 +39,25 @@ public interface ParameterAccessor extends Iterable<Object> {
3939
* @return the {@link Vector} of the parameters, if available; {@literal null} otherwise.
4040
* @since 4.0
4141
*/
42-
@Nullable
43-
Vector getVector();
42+
default @Nullable Vector getVector() {
43+
return null;
44+
}
4445

4546
/**
4647
* @return the {@link Score} of the parameters, if available; {@literal null} otherwise.
4748
* @since 4.0
4849
*/
49-
@Nullable
50-
Score getScore();
50+
default @Nullable Score getScore() {
51+
return null;
52+
}
5153

5254
/**
5355
* @return the {@link Range} of {@link Score} of the parameters, if available; {@literal null} otherwise.
5456
* @since 4.0
5557
*/
56-
@Nullable
57-
Range<Score> getScoreRange();
58+
default @Nullable Range<Score> getScoreRange() {
59+
return null;
60+
}
5861

5962
/**
6063
* @return the {@link ScrollPosition} of the parameters, if available; {@literal null} otherwise.

src/main/java/org/springframework/data/repository/query/Parameters.java

+20-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616
package org.springframework.data.repository.query;
1717

18-
import static java.lang.String.*;
18+
import static java.lang.String.format;
1919

2020
import java.lang.reflect.Method;
2121
import java.util.ArrayList;
@@ -227,6 +227,12 @@ public boolean hasVectorParameter() {
227227
return vectorIndex != -1;
228228
}
229229

230+
/**
231+
* Returns the index of the {@link Vector} argument.
232+
*
233+
* @return the argument index or {@literal -1} if none defined.
234+
* @since 4.0
235+
*/
230236
public int getVectorIndex() {
231237
return vectorIndex;
232238
}
@@ -241,12 +247,18 @@ public boolean hasScoreParameter() {
241247
return scoreIndex != -1;
242248
}
243249

250+
/**
251+
* Returns the index of the {@link Score} argument.
252+
*
253+
* @return the argument index or {@literal -1} if none defined.
254+
* @since 4.0
255+
*/
244256
public int getScoreIndex() {
245257
return scoreIndex;
246258
}
247259

248260
/**
249-
* Returns whether the method the {@link Parameters} was created for contains a {@link Range} of {@link Score}
261+
* Returns whether the method, the {@link Parameters} was created for, contains a {@link Range} of {@link Score}
250262
* argument.
251263
*
252264
* @return
@@ -256,6 +268,12 @@ public boolean hasScoreRangeParameter() {
256268
return scoreRangeIndex != -1;
257269
}
258270

271+
/**
272+
* Returns the index of the argument that contains a {@link Range} of {@link Score}.
273+
*
274+
* @return the argument index or {@literal -1} if none defined.
275+
* @since 4.0
276+
*/
259277
public int getScoreRangeIndex() {
260278
return scoreRangeIndex;
261279
}

src/test/java/org/springframework/data/domain/SearchResultUnitTests.java

+4-5
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,12 @@ class SearchResultUnitTests {
3333
SearchResult<String> third = new SearchResult<>("Bar", Score.of(2.5));
3434
SearchResult<String> fourth = new SearchResult<>("Foo", Score.of(5.2));
3535

36-
@Test // GH-
36+
@Test // GH-3285
3737
void considersSameInstanceEqual() {
3838
assertThat(first.equals(first)).isTrue();
3939
}
4040

41-
@Test // GH-
41+
@Test // GH-3285
4242
void considersSameValuesAsEqual() {
4343

4444
assertThat(first.equals(second)).isTrue();
@@ -49,14 +49,13 @@ void considersSameValuesAsEqual() {
4949
assertThat(fourth.equals(first)).isFalse();
5050
}
5151

52-
@Test
52+
@Test // GH-3285
5353
@SuppressWarnings({ "rawtypes", "unchecked" })
54-
// GH-
5554
void rejectsNullContent() {
5655
assertThatIllegalArgumentException().isThrownBy(() -> new SearchResult(null, Score.of(2.5)));
5756
}
5857

59-
@Test // GH-
58+
@Test // GH-3285
6059
@SuppressWarnings("unchecked")
6160
void testSerialization() {
6261

src/test/java/org/springframework/data/domain/SearchResultsUnitTests.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
class SearchResultsUnitTests {
3434

3535
@SuppressWarnings("unchecked")
36-
@Test // GH-
36+
@Test // GH-3285
3737
void testSerialization() {
3838

3939
var result = new SearchResult<>("test", Score.of(2));
@@ -45,7 +45,7 @@ void testSerialization() {
4545
}
4646

4747
@SuppressWarnings("unchecked")
48-
@Test // GH-
48+
@Test // GH-3285
4949
void testStream() {
5050

5151
var result = new SearchResult<>("test", Score.of(2));
@@ -56,7 +56,7 @@ void testStream() {
5656
}
5757

5858
@SuppressWarnings("unchecked")
59-
@Test // GH-
59+
@Test // GH-3285
6060
void testContentStream() {
6161

6262
var result = new SearchResult<>("test", Score.of(2));

src/test/java/org/springframework/data/domain/SimilarityUnitTests.java

+8-7
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515
*/
1616
package org.springframework.data.domain;
1717

18-
import static org.assertj.core.api.Assertions.*;
18+
import static org.assertj.core.api.Assertions.assertThat;
19+
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
1920

2021
import org.junit.jupiter.api.Test;
2122

@@ -26,22 +27,22 @@
2627
*/
2728
class SimilarityUnitTests {
2829

29-
@Test
30+
@Test // GH-3285
3031
void shouldBeBounded() {
3132

3233
assertThatIllegalArgumentException().isThrownBy(() -> Similarity.of(-1));
3334
assertThatIllegalArgumentException().isThrownBy(() -> Similarity.of(1.01));
3435
}
3536

36-
@Test
37+
@Test // GH-3285
3738
void shouldConstructRawSimilarity() {
3839

3940
Similarity similarity = Similarity.raw(2, ScoringFunction.unspecified());
4041

4142
assertThat(similarity.getValue()).isEqualTo(2);
4243
}
4344

44-
@Test
45+
@Test // GH-3285
4546
void shouldConstructGenericSimilarity() {
4647

4748
Similarity similarity = Similarity.of(1);
@@ -51,7 +52,7 @@ void shouldConstructGenericSimilarity() {
5152
assertThat(similarity.getFunction()).isEqualTo(ScoringFunction.unspecified());
5253
}
5354

54-
@Test
55+
@Test // GH-3285
5556
void shouldConstructMeteredSimilarity() {
5657

5758
Similarity similarity = Similarity.of(1, VectorScoringFunctions.COSINE);
@@ -62,7 +63,7 @@ void shouldConstructMeteredSimilarity() {
6263
assertThat(similarity.getFunction()).isEqualTo(VectorScoringFunctions.COSINE);
6364
}
6465

65-
@Test
66+
@Test // GH-3285
6667
void shouldConstructRange() {
6768

6869
Range<Similarity> range = Similarity.between(0.5, 1);
@@ -74,7 +75,7 @@ void shouldConstructRange() {
7475
assertThat(range.getUpperBound().isInclusive()).isTrue();
7576
}
7677

77-
@Test
78+
@Test // GH-3285
7879
void shouldConstructRangeWithFunction() {
7980

8081
Range<Similarity> range = Similarity.between(0.5, 1, VectorScoringFunctions.COSINE);

src/test/java/org/springframework/data/repository/query/SimpleParameterAccessorUnitTests.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,7 @@ void returnsSortFromPageableIfAvailable() throws Exception {
128128
assertThat(accessor.getSort()).isEqualTo(sort);
129129
}
130130

131-
@Test
131+
@Test // GH-3285
132132
void returnsScoreIfAvailable() {
133133

134134
Score score = Score.of(1);
@@ -137,7 +137,7 @@ void returnsScoreIfAvailable() {
137137
assertThat(accessor.getScore()).isEqualTo(score);
138138
}
139139

140-
@Test
140+
@Test // GH-3285
141141
void returnsScoreRangeIfAvailable() {
142142

143143
Range<Similarity> range = Similarity.between(0, 1);

0 commit comments

Comments
 (0)