Skip to content

Commit 645678f

Browse files
authored
fix(recommendation): _score field as member of RecommendHit (#761)
1 parent 6e7d842 commit 645678f

File tree

6 files changed

+111
-131
lines changed

6 files changed

+111
-131
lines changed

algoliasearch-core/src/main/java/com/algolia/search/RecommendClient.java

Lines changed: 35 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,9 @@
44
import com.algolia.search.models.HttpMethod;
55
import com.algolia.search.models.RequestOptions;
66
import com.algolia.search.models.common.CallType;
7+
import com.algolia.search.models.indexing.RecommendHit;
78
import com.algolia.search.models.indexing.RecommendationsResult;
8-
import com.algolia.search.models.recommend.FrequentlyBoughtTogetherQuery;
9-
import com.algolia.search.models.recommend.GetRecommendationsResponse;
10-
import com.algolia.search.models.recommend.RecommendationsQuery;
11-
import com.algolia.search.models.recommend.RecommendationsRequests;
12-
import com.algolia.search.models.recommend.RelatedProductsQuery;
9+
import com.algolia.search.models.recommend.*;
1310
import java.io.Closeable;
1411
import java.io.IOException;
1512
import java.util.List;
@@ -60,23 +57,13 @@ public SearchConfig getConfig() {
6057
}
6158

6259
// region get_recommendations
63-
/**
64-
* Returns recommendations for a specific model and objectID.
65-
*
66-
* @param requests a list of recommendation requests to execute
67-
*/
68-
public List<RecommendationsResult<Object>> getRecommendations(
69-
@Nonnull List<RecommendationsQuery> requests) {
70-
return LaunderThrowable.await(getRecommendationsAsync(requests));
71-
}
72-
7360
/**
7461
* Returns recommendations for a specific model and objectID.
7562
*
7663
* @param requests a list of recommendation requests to execute
7764
* @param clazz The class held by the index. Could be your business object or {@link Object}
7865
*/
79-
public <T> List<RecommendationsResult<T>> getRecommendations(
66+
public <T extends RecommendHit> List<RecommendationsResult<T>> getRecommendations(
8067
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
8168
return LaunderThrowable.await(getRecommendationsAsync(requests, clazz));
8269
}
@@ -88,31 +75,22 @@ public <T> List<RecommendationsResult<T>> getRecommendations(
8875
* @param clazz The class held by the index. Could be your business object or {@link Object}
8976
* @param requestOptions options to pass to this request
9077
*/
91-
public <T> List<RecommendationsResult<T>> getRecommendations(
78+
public <T extends RecommendHit> List<RecommendationsResult<T>> getRecommendations(
9279
@Nonnull List<RecommendationsQuery> requests,
9380
@Nonnull Class<T> clazz,
9481
RequestOptions requestOptions) {
9582
return LaunderThrowable.await(getRecommendationsAsync(requests, clazz, requestOptions));
9683
}
9784

98-
/**
99-
* Returns recommendations for a specific model and objectID.
100-
*
101-
* @param requests a list of recommendation requests to execute
102-
*/
103-
public CompletableFuture<List<RecommendationsResult<Object>>> getRecommendationsAsync(
104-
@Nonnull List<RecommendationsQuery> requests) {
105-
return getRecommendationsAsync(requests, Object.class, null);
106-
}
107-
10885
/**
10986
* Returns recommendations for a specific model and objectID.
11087
*
11188
* @param requests a list of recommendation requests to execute
11289
* @param clazz The class held by the index. Could be your business object or {@link Object}
11390
*/
114-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
115-
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
91+
public <T extends RecommendHit>
92+
CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
93+
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
11694
return getRecommendationsAsync(requests, clazz, null);
11795
}
11896

@@ -123,10 +101,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsA
123101
* @param clazz The class held by the index. Could be your business object or {@link Object}
124102
* @param requestOptions options to pass to this request
125103
*/
126-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
127-
@Nonnull List<RecommendationsQuery> requests,
128-
@Nonnull Class<T> clazz,
129-
RequestOptions requestOptions) {
104+
public <T extends RecommendHit>
105+
CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
106+
@Nonnull List<RecommendationsQuery> requests,
107+
@Nonnull Class<T> clazz,
108+
RequestOptions requestOptions) {
130109
Objects.requireNonNull(requests);
131110
Objects.requireNonNull(clazz);
132111
RecommendationsRequests<RecommendationsQuery> data = new RecommendationsRequests<>(requests);
@@ -135,23 +114,13 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsA
135114
// endregion
136115

137116
// region get_related_products
138-
/**
139-
* Returns related products recommendations for a specific model and objectID.
140-
*
141-
* @param requests a list of recommendation requests to execute
142-
*/
143-
public List<RecommendationsResult<Object>> getRelatedProducts(
144-
@Nonnull List<RelatedProductsQuery> requests) {
145-
return LaunderThrowable.await(getRelatedProductsAsync(requests));
146-
}
147-
148117
/**
149118
* Returns related products recommendations for a specific model and objectID.
150119
*
151120
* @param requests a list of recommendation requests to execute
152121
* @param clazz The class held by the index. Could be your business object or {@link Object}
153122
*/
154-
public <T> List<RecommendationsResult<T>> getRelatedProducts(
123+
public <T extends RecommendHit> List<RecommendationsResult<T>> getRelatedProducts(
155124
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
156125
return LaunderThrowable.await(getRelatedProductsAsync(requests, clazz));
157126
}
@@ -163,31 +132,22 @@ public <T> List<RecommendationsResult<T>> getRelatedProducts(
163132
* @param clazz The class held by the index. Could be your business object or {@link Object}
164133
* @param requestOptions options to pass to this request
165134
*/
166-
public <T> List<RecommendationsResult<T>> getRelatedProducts(
135+
public <T extends RecommendHit> List<RecommendationsResult<T>> getRelatedProducts(
167136
@Nonnull List<RelatedProductsQuery> requests,
168137
@Nonnull Class<T> clazz,
169138
RequestOptions requestOptions) {
170139
return LaunderThrowable.await(getRelatedProductsAsync(requests, clazz, requestOptions));
171140
}
172141

173-
/**
174-
* Returns related products recommendations for a specific model and objectID.
175-
*
176-
* @param requests a list of recommendation requests to execute
177-
*/
178-
public CompletableFuture<List<RecommendationsResult<Object>>> getRelatedProductsAsync(
179-
@Nonnull List<RelatedProductsQuery> requests) {
180-
return getRelatedProductsAsync(requests, Object.class);
181-
}
182-
183142
/**
184143
* Returns related products recommendations for a specific model and objectID.
185144
*
186145
* @param requests a list of recommendation requests to execute
187146
* @param clazz The class held by the index. Could be your business object or {@link Object}
188147
*/
189-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
190-
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
148+
public <T extends RecommendHit>
149+
CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
150+
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
191151
return getRelatedProductsAsync(requests, clazz, null);
192152
}
193153

@@ -198,10 +158,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsA
198158
* @param clazz The class held by the index. Could be your business object or {@link Object}
199159
* @param requestOptions options to pass to this request
200160
*/
201-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
202-
@Nonnull List<RelatedProductsQuery> requests,
203-
@Nonnull Class<T> clazz,
204-
RequestOptions requestOptions) {
161+
public <T extends RecommendHit>
162+
CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
163+
@Nonnull List<RelatedProductsQuery> requests,
164+
@Nonnull Class<T> clazz,
165+
RequestOptions requestOptions) {
205166
Objects.requireNonNull(requests);
206167
Objects.requireNonNull(clazz);
207168
RecommendationsRequests<RelatedProductsQuery> data = new RecommendationsRequests<>(requests);
@@ -210,23 +171,13 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsA
210171
// endregion
211172

212173
// region get_frequently_bought_together
213-
/**
214-
* Returns frequently bought together recommendations for a specific model and objectID.
215-
*
216-
* @param requests a list of recommendation requests to execute
217-
*/
218-
public List<RecommendationsResult<Object>> getFrequentlyBoughtTogether(
219-
@Nonnull List<FrequentlyBoughtTogetherQuery> requests) {
220-
return LaunderThrowable.await(getFrequentlyBoughtTogetherAsync(requests));
221-
}
222-
223174
/**
224175
* Returns frequently bought together recommendations for a specific model and objectID.
225176
*
226177
* @param requests a list of recommendation requests to execute
227178
* @param clazz The class held by the index. Could be your business object or {@link Object}
228179
*/
229-
public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
180+
public <T extends RecommendHit> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
230181
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
231182
return LaunderThrowable.await(getFrequentlyBoughtTogetherAsync(requests, clazz));
232183
}
@@ -238,32 +189,23 @@ public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
238189
* @param clazz The class held by the index. Could be your business object or {@link Object}
239190
* @param requestOptions options to pass to this request
240191
*/
241-
public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
192+
public <T extends RecommendHit> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
242193
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
243194
@Nonnull Class<T> clazz,
244195
RequestOptions requestOptions) {
245196
return LaunderThrowable.await(
246197
getFrequentlyBoughtTogetherAsync(requests, clazz, requestOptions));
247198
}
248199

249-
/**
250-
* Returns frequently bought together recommendations for a specific model and objectID.
251-
*
252-
* @param requests a list of recommendation requests to execute
253-
*/
254-
public CompletableFuture<List<RecommendationsResult<Object>>> getFrequentlyBoughtTogetherAsync(
255-
@Nonnull List<FrequentlyBoughtTogetherQuery> requests) {
256-
return getFrequentlyBoughtTogetherAsync(requests, Object.class, null);
257-
}
258-
259200
/**
260201
* Returns frequently bought together recommendations for a specific model and objectID.
261202
*
262203
* @param requests a list of recommendation requests to execute
263204
* @param clazz The class held by the index. Could be your business object or {@link Object}
264205
*/
265-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
266-
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
206+
public <T extends RecommendHit>
207+
CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
208+
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
267209
return getFrequentlyBoughtTogetherAsync(requests, clazz, null);
268210
}
269211

@@ -274,10 +216,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBought
274216
* @param clazz The class held by the index. Could be your business object or {@link Object}
275217
* @param requestOptions options to pass to this request
276218
*/
277-
public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
278-
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
279-
@Nonnull Class<T> clazz,
280-
RequestOptions requestOptions) {
219+
public <T extends RecommendHit>
220+
CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
221+
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
222+
@Nonnull Class<T> clazz,
223+
RequestOptions requestOptions) {
281224
Objects.requireNonNull(requests);
282225
Objects.requireNonNull(clazz);
283226
RecommendationsRequests<FrequentlyBoughtTogetherQuery> data =
@@ -287,8 +230,9 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBought
287230
// endregion
288231

289232
@SuppressWarnings("unchecked")
290-
private <T> CompletableFuture<List<RecommendationsResult<T>>> performGetRecommends(
291-
Class<T> clazz, RequestOptions requestOptions, RecommendationsRequests<?> data) {
233+
private <T extends RecommendHit>
234+
CompletableFuture<List<RecommendationsResult<T>>> performGetRecommends(
235+
Class<T> clazz, RequestOptions requestOptions, RecommendationsRequests<?> data) {
292236
return transport
293237
.executeRequestAsync(
294238
HttpMethod.POST,
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package com.algolia.search.models.indexing;
2+
3+
import com.fasterxml.jackson.annotation.JsonProperty;
4+
import javax.annotation.Nonnull;
5+
6+
/** Recommend hit, similar to a search hit but associated with a score. */
7+
public interface RecommendHit {
8+
9+
/** Confidence score of the recommended item, the closer it’s to 100, the more relevant. */
10+
@Nonnull
11+
@JsonProperty("_score")
12+
Float getScore();
13+
}
Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,4 @@
11
package com.algolia.search.models.indexing;
22

3-
public class RecommendationsResult<T> extends SearchResult<T> {
4-
5-
private Integer score;
6-
7-
public Integer getScore() {
8-
return score;
9-
}
10-
11-
public RecommendationsResult<T> setScore(Integer score) {
12-
this.score = score;
13-
return this;
14-
}
15-
}
3+
/** Result of a recommendation request. */
4+
public class RecommendationsResult<T extends RecommendHit> extends SearchResult<T> {}

algoliasearch-core/src/main/java/com/algolia/search/models/recommend/GetRecommendationsResponse.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
package com.algolia.search.models.recommend;
22

3+
import com.algolia.search.models.indexing.RecommendHit;
34
import com.algolia.search.models.indexing.RecommendationsResult;
45
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
56
import com.fasterxml.jackson.annotation.JsonInclude;
67
import java.io.Serializable;
78
import java.util.List;
89

10+
/** Response from Recommend API. */
911
@JsonInclude(JsonInclude.Include.NON_NULL)
1012
@JsonIgnoreProperties(ignoreUnknown = true)
11-
public class GetRecommendationsResponse<T> implements Serializable {
13+
public class GetRecommendationsResponse<T extends RecommendHit> implements Serializable {
1214

15+
/** List of results in the order they were submitted, one per request. */
1316
private List<RecommendationsResult<T>> results;
1417

1518
public List<RecommendationsResult<T>> getResults() {

algoliasearch-core/src/test/java/com/algolia/search/JacksonParserTest.java

Lines changed: 23 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,38 +4,19 @@
44
import static com.algolia.search.models.synonyms.SynonymType.ONE_WAY_SYNONYM;
55
import static org.assertj.core.api.Assertions.assertThat;
66

7+
import com.algolia.search.integration.models.RecommendObject;
78
import com.algolia.search.models.common.InnerQuery;
8-
import com.algolia.search.models.indexing.Alternative;
9-
import com.algolia.search.models.indexing.AroundPrecision;
10-
import com.algolia.search.models.indexing.AroundRadius;
11-
import com.algolia.search.models.indexing.PartialUpdateOperation;
12-
import com.algolia.search.models.indexing.Query;
13-
import com.algolia.search.models.rules.Alternatives;
14-
import com.algolia.search.models.rules.AutomaticFacetFilter;
15-
import com.algolia.search.models.rules.Condition;
16-
import com.algolia.search.models.rules.Consequence;
17-
import com.algolia.search.models.rules.ConsequenceParams;
18-
import com.algolia.search.models.rules.ConsequencePromote;
19-
import com.algolia.search.models.rules.ConsequenceQuery;
20-
import com.algolia.search.models.rules.Edit;
21-
import com.algolia.search.models.rules.EditType;
22-
import com.algolia.search.models.rules.Rule;
23-
import com.algolia.search.models.rules.TimeRange;
24-
import com.algolia.search.models.settings.Distinct;
25-
import com.algolia.search.models.settings.IgnorePlurals;
26-
import com.algolia.search.models.settings.IndexSettings;
27-
import com.algolia.search.models.settings.RemoveStopWords;
28-
import com.algolia.search.models.settings.TypoTolerance;
9+
import com.algolia.search.models.indexing.*;
10+
import com.algolia.search.models.recommend.GetRecommendationsResponse;
11+
import com.algolia.search.models.rules.*;
12+
import com.algolia.search.models.settings.*;
2913
import com.algolia.search.models.synonyms.SynonymQuery;
3014
import com.fasterxml.jackson.core.JsonProcessingException;
15+
import com.fasterxml.jackson.databind.JavaType;
3116
import java.io.IOException;
3217
import java.time.OffsetDateTime;
3318
import java.time.ZoneOffset;
34-
import java.util.Arrays;
35-
import java.util.Collections;
36-
import java.util.HashMap;
37-
import java.util.List;
38-
import java.util.Map;
19+
import java.util.*;
3920
import org.junit.jupiter.api.Test;
4021
import org.junit.jupiter.params.ParameterizedTest;
4122
import org.junit.jupiter.params.provider.ValueSource;
@@ -1007,4 +988,20 @@ void rulesValidityTimeRange() throws IOException {
1007988
assertThat(timerange.getFrom()).isEqualTo(retrieveTimeRange.getFrom());
1008989
assertThat(timerange.getUntil()).isEqualTo(retrieveTimeRange.getUntil());
1009990
}
991+
992+
@Test
993+
void recommendations() throws JsonProcessingException {
994+
String json =
995+
"{\"results\":[{\"hits\":[{\"_highlightResult\":{\"category\":{\"matchLevel\":\"none\",\"matchedWords\":[],\"value\":\"Men - T-Shirts\"},\"image_link\":{\"matchLevel\":\"none\",\"matchedWords\":[],\"value\":\"https:\\/\\/example.org\\/image\\/D05927-8161-111-F01.jpg\"},\"name\":{\"matchLevel\":\"none\",\"matchedWords\":[],\"value\":\"Jirgi Half-Zip T-Shirt\"}},\"_score\":32.72,\"category\":\"Men - T-Shirts\",\"image_link\":\"https:\\/\\/example.org\\/image\\/D05927-8161-111-F01.jpg\",\"name\":\"Jirgi Half-Zip T-Shirt\",\"objectID\":\"D05927-8161-111\",\"position\":105,\"url\":\"men\\/t-shirts\\/d05927-8161-111\"}],\"hitsPerPage\":1,\"nbHits\":1,\"nbPages\":1,\"page\":0,\"processingTimeMS\":6,\"renderingContent\":{}}]}";
996+
JavaType type =
997+
Defaults.getObjectMapper()
998+
.getTypeFactory()
999+
.constructParametricType(GetRecommendationsResponse.class, RecommendObject.class);
1000+
GetRecommendationsResponse<RecommendObject> recommendations =
1001+
Defaults.getObjectMapper().readValue(json, type);
1002+
RecommendationsResult<RecommendObject> result = recommendations.getResults().get(0);
1003+
RecommendObject recommendHit = result.getHits().get(0);
1004+
assertThat(recommendHit.getObjectID()).isEqualTo("D05927-8161-111");
1005+
assertThat(recommendHit.getScore()).isEqualTo(32.72f);
1006+
}
10101007
}

0 commit comments

Comments
 (0)