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
This commit is contained in:
committed by
Mark Paluch
parent
ecb2592493
commit
9a7ea62b2e
@@ -80,11 +80,11 @@ Score values are not part of a domain model and therefore represented best as ou
|
||||
Generally, a Score is computed by a `ScoringFunction`.
|
||||
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.
|
||||
|
||||
Spring Data supports declares constants for commonly used functions such as:
|
||||
Spring Data support declares constants for commonly used functions such as:
|
||||
|
||||
Euclidean distance:: Calculates the straight-line distance in n-dimensional space involving the square root of the sum of squared differences.
|
||||
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.
|
||||
Dot product:: Computes the sum of element-wise multiplications.
|
||||
Euclidean Distance:: Calculates the straight-line distance in n-dimensional space involving the square root of the sum of squared differences.
|
||||
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.
|
||||
Dot Product:: Computes the sum of element-wise multiplications.
|
||||
|
||||
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.
|
||||
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
|
||||
* Query Derivation
|
||||
* Declaring a String-based Query
|
||||
|
||||
Generally, Vector Search methods must declare a `Vector` parameter to define the query vector.
|
||||
Vector Search methods must declare a `Vector` parameter to define the query vector.
|
||||
|
||||
[[vector-search.method.derivation]]
|
||||
=== Derived Search Methods
|
||||
@@ -142,7 +142,7 @@ endif::[]
|
||||
|
||||
With more control over the actual query, Spring Data can make fewer assumptions about the query and its parameters.
|
||||
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.
|
||||
If an annotated query doesn't define e.g. the score, then the score value in the returned `SearchResult<T>` will be zero.
|
||||
If an annotated query does not define e.g. the score, then the score value in the returned `SearchResult<T>` will be zero.
|
||||
|
||||
[[vector-search.method.sorting]]
|
||||
=== Sorting
|
||||
|
||||
@@ -20,7 +20,6 @@ import java.io.Serializable;
|
||||
import java.util.function.Function;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
|
||||
@@ -26,7 +26,6 @@ import java.util.stream.Stream;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object encapsulating a collection of {@link SearchResult} instances.
|
||||
@@ -123,8 +122,7 @@ public class SearchResults<T> implements Iterable<SearchResult<T>>, Serializable
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return results.isEmpty() ? "SearchResults: [empty]"
|
||||
: String.format("SearchResults: [results: %s]", StringUtils.collectionToCommaDelimitedString(results));
|
||||
return results.isEmpty() ? "SearchResults [empty]" : String.format("SearchResults [size: %s]", results.size());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,7 +19,6 @@ import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
|
||||
@@ -79,6 +78,6 @@ public final class GeoResult<T> implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("GeoResult [content: %s, distance: %s, ]", content.toString(), distance.toString());
|
||||
return String.format("GeoResult [content: %s, distance: %s]", content, distance);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.data.geo;
|
||||
|
||||
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import java.util.Collections;
|
||||
@@ -23,11 +22,9 @@ import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
import org.jspecify.annotations.Nullable;
|
||||
|
||||
import org.springframework.data.annotation.PersistenceCreator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to capture {@link GeoResult}s as well as the average distance they have.
|
||||
@@ -129,8 +126,8 @@ public class GeoResults<T> implements Iterable<GeoResult<T>>, Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return String.format("GeoResults: [averageDistance: %s, results: %s]", averageDistance.toString(),
|
||||
StringUtils.collectionToCommaDelimitedString(results));
|
||||
return results.isEmpty() ? "GeoResults [empty]"
|
||||
: String.format("GeoResults [averageDistance: %s, size: %s]", averageDistance, results.size());
|
||||
}
|
||||
|
||||
private static Distance calculateAverageDistance(List<? extends GeoResult<?>> results, Metric metric) {
|
||||
|
||||
@@ -39,22 +39,25 @@ public interface ParameterAccessor extends Iterable<Object> {
|
||||
* @return the {@link Vector} of the parameters, if available; {@literal null} otherwise.
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nullable
|
||||
Vector getVector();
|
||||
default @Nullable Vector getVector() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Score} of the parameters, if available; {@literal null} otherwise.
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nullable
|
||||
Score getScore();
|
||||
default @Nullable Score getScore() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link Range} of {@link Score} of the parameters, if available; {@literal null} otherwise.
|
||||
* @since 4.0
|
||||
*/
|
||||
@Nullable
|
||||
Range<Score> getScoreRange();
|
||||
default @Nullable Range<Score> getScoreRange() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the {@link ScrollPosition} of the parameters, if available; {@literal null} otherwise.
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.repository.query;
|
||||
|
||||
import static java.lang.String.*;
|
||||
import static java.lang.String.format;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
@@ -226,6 +226,12 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
return vectorIndex != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the {@link Vector} argument.
|
||||
*
|
||||
* @return the argument index or {@literal -1} if none defined.
|
||||
* @since 4.0
|
||||
*/
|
||||
public int getVectorIndex() {
|
||||
return vectorIndex;
|
||||
}
|
||||
@@ -240,12 +246,18 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
return scoreIndex != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the {@link Score} argument.
|
||||
*
|
||||
* @return the argument index or {@literal -1} if none defined.
|
||||
* @since 4.0
|
||||
*/
|
||||
public int getScoreIndex() {
|
||||
return scoreIndex;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the method the {@link Parameters} was created for contains a {@link Range} of {@link Score}
|
||||
* Returns whether the method, the {@link Parameters} was created for, contains a {@link Range} of {@link Score}
|
||||
* argument.
|
||||
*
|
||||
* @return
|
||||
@@ -255,6 +267,12 @@ public abstract class Parameters<S extends Parameters<S, T>, T extends Parameter
|
||||
return scoreRangeIndex != -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the argument that contains a {@link Range} of {@link Score}.
|
||||
*
|
||||
* @return the argument index or {@literal -1} if none defined.
|
||||
* @since 4.0
|
||||
*/
|
||||
public int getScoreRangeIndex() {
|
||||
return scoreRangeIndex;
|
||||
}
|
||||
|
||||
@@ -33,12 +33,12 @@ class SearchResultUnitTests {
|
||||
SearchResult<String> third = new SearchResult<>("Bar", Score.of(2.5));
|
||||
SearchResult<String> fourth = new SearchResult<>("Foo", Score.of(5.2));
|
||||
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
void considersSameInstanceEqual() {
|
||||
assertThat(first.equals(first)).isTrue();
|
||||
}
|
||||
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
void considersSameValuesAsEqual() {
|
||||
|
||||
assertThat(first.equals(second)).isTrue();
|
||||
@@ -49,14 +49,13 @@ class SearchResultUnitTests {
|
||||
assertThat(fourth.equals(first)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
// GH-
|
||||
void rejectsNullContent() {
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> new SearchResult(null, Score.of(2.5)));
|
||||
}
|
||||
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
@SuppressWarnings("unchecked")
|
||||
void testSerialization() {
|
||||
|
||||
|
||||
@@ -33,7 +33,7 @@ import org.springframework.util.SerializationUtils;
|
||||
class SearchResultsUnitTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
void testSerialization() {
|
||||
|
||||
var result = new SearchResult<>("test", Score.of(2));
|
||||
@@ -45,7 +45,7 @@ class SearchResultsUnitTests {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
void testStream() {
|
||||
|
||||
var result = new SearchResult<>("test", Score.of(2));
|
||||
@@ -56,7 +56,7 @@ class SearchResultsUnitTests {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test // GH-
|
||||
@Test // GH-3285
|
||||
void testContentStream() {
|
||||
|
||||
var result = new SearchResult<>("test", Score.of(2));
|
||||
|
||||
@@ -15,7 +15,8 @@
|
||||
*/
|
||||
package org.springframework.data.domain;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalArgumentException;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
@@ -26,14 +27,14 @@ import org.junit.jupiter.api.Test;
|
||||
*/
|
||||
class SimilarityUnitTests {
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldBeBounded() {
|
||||
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> Similarity.of(-1));
|
||||
assertThatIllegalArgumentException().isThrownBy(() -> Similarity.of(1.01));
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldConstructRawSimilarity() {
|
||||
|
||||
Similarity similarity = Similarity.raw(2, ScoringFunction.unspecified());
|
||||
@@ -41,7 +42,7 @@ class SimilarityUnitTests {
|
||||
assertThat(similarity.getValue()).isEqualTo(2);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldConstructGenericSimilarity() {
|
||||
|
||||
Similarity similarity = Similarity.of(1);
|
||||
@@ -51,7 +52,7 @@ class SimilarityUnitTests {
|
||||
assertThat(similarity.getFunction()).isEqualTo(ScoringFunction.unspecified());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldConstructMeteredSimilarity() {
|
||||
|
||||
Similarity similarity = Similarity.of(1, VectorScoringFunctions.COSINE);
|
||||
@@ -62,7 +63,7 @@ class SimilarityUnitTests {
|
||||
assertThat(similarity.getFunction()).isEqualTo(VectorScoringFunctions.COSINE);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldConstructRange() {
|
||||
|
||||
Range<Similarity> range = Similarity.between(0.5, 1);
|
||||
@@ -74,7 +75,7 @@ class SimilarityUnitTests {
|
||||
assertThat(range.getUpperBound().isInclusive()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void shouldConstructRangeWithFunction() {
|
||||
|
||||
Range<Similarity> range = Similarity.between(0.5, 1, VectorScoringFunctions.COSINE);
|
||||
|
||||
@@ -128,7 +128,7 @@ class SimpleParameterAccessorUnitTests {
|
||||
assertThat(accessor.getSort()).isEqualTo(sort);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void returnsScoreIfAvailable() {
|
||||
|
||||
Score score = Score.of(1);
|
||||
@@ -137,7 +137,7 @@ class SimpleParameterAccessorUnitTests {
|
||||
assertThat(accessor.getScore()).isEqualTo(score);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test // GH-3285
|
||||
void returnsScoreRangeIfAvailable() {
|
||||
|
||||
Range<Similarity> range = Similarity.between(0, 1);
|
||||
|
||||
Reference in New Issue
Block a user