caio.co/de/cerberus

SearchQuery: Replace dietThreshold() with diet()

This patch changes the query model to only allow a single chosen diet
(and its corresponding threshold). This is being done mostly to simplify
usage: the only code I have that makes use of the feature is unpublished
and for reporting only - The web UI only uses one and I have no plans
of allowing more than one.
Id
190acc9a0f310a71b2bc0e8019c9ad17e3a300c8
Author
Caio
Commit time
2019-05-24T15:21:29+02:00

Modified src/main/java/co/caio/cerberus/model/SearchQuery.java

@@ -1,10 +1,9
package co.caio.cerberus.model;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import java.util.Map;
import java.util.Optional;
import java.util.stream.Stream;
import org.immutables.value.Value;
@@ -32,22 +31,22

Optional<RangedSpec> carbohydrateContent();

- Map<String, Float> dietThreshold();
+ Optional<DietSpec> diet();

@Value.Derived
default long numSelectedFilters() {
return Stream.of(
- numIngredients(),
- prepTime(),
- cookTime(),
- totalTime(),
- calories(),
- fatContent(),
- proteinContent(),
- carbohydrateContent())
- .flatMap(Optional::stream)
- .count()
- + dietThreshold().size();
+ numIngredients(),
+ prepTime(),
+ cookTime(),
+ totalTime(),
+ calories(),
+ fatContent(),
+ proteinContent(),
+ carbohydrateContent(),
+ diet())
+ .flatMap(Optional::stream)
+ .count();
}

@Value.Derived
@@ -116,6 +115,30
}
}

+ @Value.Immutable(builder = false)
+ @JsonFormat(shape = JsonFormat.Shape.ARRAY)
+ @JsonPropertyOrder({"name", "threshold"})
+ @JsonSerialize(as = ImmutableDietSpec.class)
+ @JsonDeserialize(as = ImmutableDietSpec.class)
+ interface DietSpec {
+ @Value.Parameter
+ String name();
+
+ @Value.Parameter
+ float threshold();
+
+ static DietSpec of(String name, float threshold) {
+ return ImmutableDietSpec.of(name, threshold);
+ }
+
+ @Value.Check
+ default void check() {
+ if (threshold() <= 0 || threshold() > 1) {
+ throw new IllegalStateException("Threshold must be > 0 and <= 1");
+ }
+ }
+ }
+
@Value.Check
default void check() {
if (maxResults() < 1) {
@@ -127,19 +150,16
if (offset() < 0) {
throw new IllegalStateException("offset must be >= 0");
}
- dietThreshold()
- .forEach(
- (diet, score) -> {
- if (score <= 0 || score > 1) {
- throw new IllegalStateException("score must be in ]0,1]");
- }
- });
}

class Builder extends ImmutableSearchQuery.Builder {
- public Builder addMatchDiet(String dietName) {
- putDietThreshold(dietName, 1f);
+ public Builder diet(String dietName, float threshold) {
+ diet(DietSpec.of(dietName, threshold));
return this;
+ }
+
+ public Builder diet(String dietName) {
+ return diet(dietName, 1F);
}
}
}

Modified src/main/java/co/caio/cerberus/search/SearcherImpl.java

@@ -241,11 +241,12
Occur.MUST));

searchQuery
- .dietThreshold()
- .forEach(
- (diet, score) ->
+ .diet()
+ .ifPresent(
+ (diet) ->
queryBuilder.add(
- FloatPoint.newRangeQuery(getFieldNameForDiet(diet), score, Float.MAX_VALUE),
+ FloatPoint.newRangeQuery(
+ getFieldNameForDiet(diet.name()), diet.threshold(), Float.MAX_VALUE),
Occur.MUST));

return queryBuilder.build();

Modified src/test/java/co/caio/cerberus/model/SearchQueryTest.java

@@ -39,20 +39,15

@Test
void addMatchDietAlias() {
- assertEquals(
- new Builder().addMatchDiet("keto").build(),
- new Builder().putDietThreshold("keto", 1f).build());
+ assertEquals(new Builder().diet("keto").build(), new Builder().diet("keto", 1f).build());
}

@Test
void dietThresholds() {
- assertThrows(
- IllegalStateException.class, () -> new Builder().putDietThreshold("paleo", 0).build());
- assertThrows(
- IllegalStateException.class, () -> new Builder().putDietThreshold("lowcarb", -1).build());
- assertThrows(
- IllegalStateException.class, () -> new Builder().putDietThreshold("vegan", 1.1f).build());
- assertDoesNotThrow(() -> new Builder().putDietThreshold("paleo", 1.0f).build());
+ assertThrows(IllegalStateException.class, () -> new Builder().diet("paleo", 0).build());
+ assertThrows(IllegalStateException.class, () -> new Builder().diet("lowcarb", -1).build());
+ assertThrows(IllegalStateException.class, () -> new Builder().diet("vegan", 1.1f).build());
+ assertDoesNotThrow(() -> new Builder().diet("paleo", 1.0f).build());
}

@Test
@@ -61,6 +56,6
assertEquals(0, builder.build().numSelectedFilters());
assertEquals(1, builder.numIngredients(RangedSpec.of(1, 10)).build().numSelectedFilters());
assertEquals(2, builder.carbohydrateContent(RangedSpec.of(0, 30)).build().numSelectedFilters());
- assertEquals(3, builder.addMatchDiet("keto").build().numSelectedFilters());
+ assertEquals(3, builder.diet("keto").build().numSelectedFilters());
}
}

Modified src/test/java/co/caio/cerberus/search/SearcherTest.java

@@ -94,7 +94,7
searcher.search(
new SearchQuery.Builder()
.fulltext("vegetarian")
- .addMatchDiet("vegetarian")
+ .diet("vegetarian")
.maxResults(1)
.build());
assertEquals(nrVegetarianRecipes, result.totalHits());
@@ -103,8 +103,7
// term<vegetarian> in the whole index would give us AT LEAST the same number
// as above, but maybe more since a recipe can be vegetarian without having to
// call itself vegetarian
- result =
- searcher.search(new SearchQuery.Builder().addMatchDiet("vegetarian").maxResults(1).build());
+ result = searcher.search(new SearchQuery.Builder().diet("vegetarian").maxResults(1).build());
assertTrue(result.totalHits() >= nrVegetarianRecipes);
}

@@ -121,21 +120,18
.crawlUrl("https://who.cares")
.addIngredients("doesnt matter")
.addInstructions("nothing to do");
- indexer.addRecipe(recipeBuilder.putDiets("keto", 0.8f).putDiets("paleo", 0.5f).build());
- indexer.addRecipe(recipeBuilder.putDiets("keto", 0.6f).putDiets("paleo", 0.1f).build());
+ indexer.addRecipe(recipeBuilder.putDiets("keto", 0.8F).build());
+ indexer.addRecipe(recipeBuilder.putDiets("keto", 0.6F).build());
+ indexer.addRecipe(recipeBuilder.putDiets("keto", 1F).build());
indexer.commit();

var searcher = indexer.buildSearcher();
- var result = searcher.search(new SearchQuery.Builder().putDietThreshold("keto", 0.9f).build());
- assertEquals(0, result.totalHits());
+ var sqb = new SearchQuery.Builder();

- result =
- searcher.search(
- new SearchQuery.Builder()
- .putDietThreshold("keto", 0.8f)
- .putDietThreshold("paleo", 0.1f)
- .build());
- assertEquals(1, result.totalHits());
+ assertEquals(1, searcher.search(sqb.diet("keto").build()).totalHits());
+ assertEquals(1, searcher.search(sqb.diet("keto", 1F).build()).totalHits());
+ assertEquals(2, searcher.search(sqb.diet("keto", 0.7F).build()).totalHits());
+ assertEquals(3, searcher.search(sqb.diet("keto", 0.6F).build()).totalHits());
}

@Test