Skip to content

Commit

Permalink
fix(recommendation): _score field as member of RecommendHit (#761)
Browse files Browse the repository at this point in the history
  • Loading branch information
aallam committed Oct 26, 2021
1 parent 6e7d842 commit 645678f
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 131 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,9 @@
import com.algolia.search.models.HttpMethod;
import com.algolia.search.models.RequestOptions;
import com.algolia.search.models.common.CallType;
import com.algolia.search.models.indexing.RecommendHit;
import com.algolia.search.models.indexing.RecommendationsResult;
import com.algolia.search.models.recommend.FrequentlyBoughtTogetherQuery;
import com.algolia.search.models.recommend.GetRecommendationsResponse;
import com.algolia.search.models.recommend.RecommendationsQuery;
import com.algolia.search.models.recommend.RecommendationsRequests;
import com.algolia.search.models.recommend.RelatedProductsQuery;
import com.algolia.search.models.recommend.*;
import java.io.Closeable;
import java.io.IOException;
import java.util.List;
Expand Down Expand Up @@ -60,23 +57,13 @@ public SearchConfig getConfig() {
}

// region get_recommendations
/**
* Returns recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public List<RecommendationsResult<Object>> getRecommendations(
@Nonnull List<RecommendationsQuery> requests) {
return LaunderThrowable.await(getRecommendationsAsync(requests));
}

/**
* Returns recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> List<RecommendationsResult<T>> getRecommendations(
public <T extends RecommendHit> List<RecommendationsResult<T>> getRecommendations(
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
return LaunderThrowable.await(getRecommendationsAsync(requests, clazz));
}
Expand All @@ -88,31 +75,22 @@ public <T> List<RecommendationsResult<T>> getRecommendations(
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> List<RecommendationsResult<T>> getRecommendations(
public <T extends RecommendHit> List<RecommendationsResult<T>> getRecommendations(
@Nonnull List<RecommendationsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
return LaunderThrowable.await(getRecommendationsAsync(requests, clazz, requestOptions));
}

/**
* Returns recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public CompletableFuture<List<RecommendationsResult<Object>>> getRecommendationsAsync(
@Nonnull List<RecommendationsQuery> requests) {
return getRecommendationsAsync(requests, Object.class, null);
}

/**
* Returns recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
@Nonnull List<RecommendationsQuery> requests, @Nonnull Class<T> clazz) {
return getRecommendationsAsync(requests, clazz, null);
}

Expand All @@ -123,10 +101,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsA
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
@Nonnull List<RecommendationsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsAsync(
@Nonnull List<RecommendationsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
Objects.requireNonNull(requests);
Objects.requireNonNull(clazz);
RecommendationsRequests<RecommendationsQuery> data = new RecommendationsRequests<>(requests);
Expand All @@ -135,23 +114,13 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRecommendationsA
// endregion

// region get_related_products
/**
* Returns related products recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public List<RecommendationsResult<Object>> getRelatedProducts(
@Nonnull List<RelatedProductsQuery> requests) {
return LaunderThrowable.await(getRelatedProductsAsync(requests));
}

/**
* Returns related products recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> List<RecommendationsResult<T>> getRelatedProducts(
public <T extends RecommendHit> List<RecommendationsResult<T>> getRelatedProducts(
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
return LaunderThrowable.await(getRelatedProductsAsync(requests, clazz));
}
Expand All @@ -163,31 +132,22 @@ public <T> List<RecommendationsResult<T>> getRelatedProducts(
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> List<RecommendationsResult<T>> getRelatedProducts(
public <T extends RecommendHit> List<RecommendationsResult<T>> getRelatedProducts(
@Nonnull List<RelatedProductsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
return LaunderThrowable.await(getRelatedProductsAsync(requests, clazz, requestOptions));
}

/**
* Returns related products recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public CompletableFuture<List<RecommendationsResult<Object>>> getRelatedProductsAsync(
@Nonnull List<RelatedProductsQuery> requests) {
return getRelatedProductsAsync(requests, Object.class);
}

/**
* Returns related products recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
@Nonnull List<RelatedProductsQuery> requests, @Nonnull Class<T> clazz) {
return getRelatedProductsAsync(requests, clazz, null);
}

Expand All @@ -198,10 +158,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsA
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
@Nonnull List<RelatedProductsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsAsync(
@Nonnull List<RelatedProductsQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
Objects.requireNonNull(requests);
Objects.requireNonNull(clazz);
RecommendationsRequests<RelatedProductsQuery> data = new RecommendationsRequests<>(requests);
Expand All @@ -210,23 +171,13 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getRelatedProductsA
// endregion

// region get_frequently_bought_together
/**
* Returns frequently bought together recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public List<RecommendationsResult<Object>> getFrequentlyBoughtTogether(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests) {
return LaunderThrowable.await(getFrequentlyBoughtTogetherAsync(requests));
}

/**
* Returns frequently bought together recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
public <T extends RecommendHit> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
return LaunderThrowable.await(getFrequentlyBoughtTogetherAsync(requests, clazz));
}
Expand All @@ -238,32 +189,23 @@ public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
public <T extends RecommendHit> List<RecommendationsResult<T>> getFrequentlyBoughtTogether(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
return LaunderThrowable.await(
getFrequentlyBoughtTogetherAsync(requests, clazz, requestOptions));
}

/**
* Returns frequently bought together recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
*/
public CompletableFuture<List<RecommendationsResult<Object>>> getFrequentlyBoughtTogetherAsync(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests) {
return getFrequentlyBoughtTogetherAsync(requests, Object.class, null);
}

/**
* Returns frequently bought together recommendations for a specific model and objectID.
*
* @param requests a list of recommendation requests to execute
* @param clazz The class held by the index. Could be your business object or {@link Object}
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests, @Nonnull Class<T> clazz) {
return getFrequentlyBoughtTogetherAsync(requests, clazz, null);
}

Expand All @@ -274,10 +216,11 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBought
* @param clazz The class held by the index. Could be your business object or {@link Object}
* @param requestOptions options to pass to this request
*/
public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
public <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBoughtTogetherAsync(
@Nonnull List<FrequentlyBoughtTogetherQuery> requests,
@Nonnull Class<T> clazz,
RequestOptions requestOptions) {
Objects.requireNonNull(requests);
Objects.requireNonNull(clazz);
RecommendationsRequests<FrequentlyBoughtTogetherQuery> data =
Expand All @@ -287,8 +230,9 @@ public <T> CompletableFuture<List<RecommendationsResult<T>>> getFrequentlyBought
// endregion

@SuppressWarnings("unchecked")
private <T> CompletableFuture<List<RecommendationsResult<T>>> performGetRecommends(
Class<T> clazz, RequestOptions requestOptions, RecommendationsRequests<?> data) {
private <T extends RecommendHit>
CompletableFuture<List<RecommendationsResult<T>>> performGetRecommends(
Class<T> clazz, RequestOptions requestOptions, RecommendationsRequests<?> data) {
return transport
.executeRequestAsync(
HttpMethod.POST,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.algolia.search.models.indexing;

import com.fasterxml.jackson.annotation.JsonProperty;
import javax.annotation.Nonnull;

/** Recommend hit, similar to a search hit but associated with a score. */
public interface RecommendHit {

/** Confidence score of the recommended item, the closer it’s to 100, the more relevant. */
@Nonnull
@JsonProperty("_score")
Float getScore();
}
Original file line number Diff line number Diff line change
@@ -1,15 +1,4 @@
package com.algolia.search.models.indexing;

public class RecommendationsResult<T> extends SearchResult<T> {

private Integer score;

public Integer getScore() {
return score;
}

public RecommendationsResult<T> setScore(Integer score) {
this.score = score;
return this;
}
}
/** Result of a recommendation request. */
public class RecommendationsResult<T extends RecommendHit> extends SearchResult<T> {}
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
package com.algolia.search.models.recommend;

import com.algolia.search.models.indexing.RecommendHit;
import com.algolia.search.models.indexing.RecommendationsResult;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonInclude;
import java.io.Serializable;
import java.util.List;

/** Response from Recommend API. */
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonIgnoreProperties(ignoreUnknown = true)
public class GetRecommendationsResponse<T> implements Serializable {
public class GetRecommendationsResponse<T extends RecommendHit> implements Serializable {

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

public List<RecommendationsResult<T>> getResults() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,19 @@
import static com.algolia.search.models.synonyms.SynonymType.ONE_WAY_SYNONYM;
import static org.assertj.core.api.Assertions.assertThat;

import com.algolia.search.integration.models.RecommendObject;
import com.algolia.search.models.common.InnerQuery;
import com.algolia.search.models.indexing.Alternative;
import com.algolia.search.models.indexing.AroundPrecision;
import com.algolia.search.models.indexing.AroundRadius;
import com.algolia.search.models.indexing.PartialUpdateOperation;
import com.algolia.search.models.indexing.Query;
import com.algolia.search.models.rules.Alternatives;
import com.algolia.search.models.rules.AutomaticFacetFilter;
import com.algolia.search.models.rules.Condition;
import com.algolia.search.models.rules.Consequence;
import com.algolia.search.models.rules.ConsequenceParams;
import com.algolia.search.models.rules.ConsequencePromote;
import com.algolia.search.models.rules.ConsequenceQuery;
import com.algolia.search.models.rules.Edit;
import com.algolia.search.models.rules.EditType;
import com.algolia.search.models.rules.Rule;
import com.algolia.search.models.rules.TimeRange;
import com.algolia.search.models.settings.Distinct;
import com.algolia.search.models.settings.IgnorePlurals;
import com.algolia.search.models.settings.IndexSettings;
import com.algolia.search.models.settings.RemoveStopWords;
import com.algolia.search.models.settings.TypoTolerance;
import com.algolia.search.models.indexing.*;
import com.algolia.search.models.recommend.GetRecommendationsResponse;
import com.algolia.search.models.rules.*;
import com.algolia.search.models.settings.*;
import com.algolia.search.models.synonyms.SynonymQuery;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import java.io.IOException;
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
Expand Down Expand Up @@ -1007,4 +988,20 @@ void rulesValidityTimeRange() throws IOException {
assertThat(timerange.getFrom()).isEqualTo(retrieveTimeRange.getFrom());
assertThat(timerange.getUntil()).isEqualTo(retrieveTimeRange.getUntil());
}

@Test
void recommendations() throws JsonProcessingException {
String json =
"{\"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\":{}}]}";
JavaType type =
Defaults.getObjectMapper()
.getTypeFactory()
.constructParametricType(GetRecommendationsResponse.class, RecommendObject.class);
GetRecommendationsResponse<RecommendObject> recommendations =
Defaults.getObjectMapper().readValue(json, type);
RecommendationsResult<RecommendObject> result = recommendations.getResults().get(0);
RecommendObject recommendHit = result.getHits().get(0);
assertThat(recommendHit.getObjectID()).isEqualTo("D05927-8161-111");
assertThat(recommendHit.getScore()).isEqualTo(32.72f);
}
}

0 comments on commit 645678f

Please sign in to comment.