caio.co/de/cerberus

Make SearchPolicy allow rewriting queries

This patch changes the query inspection interface to return a Query
object, thus allowing for conditional rewrites client-side.
Id
9df2ebd1be0ac22adfa2c8001429043c6b477ffd
Author
Caio
Commit time
2019-04-14T18:07:32+02:00

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

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

import org.apache.lucene.search.Query;

public interface SearchPolicy {
- void inspectParsedFulltextQuery(Query query);
+ Query rewriteParsedFulltextQuery(Query query);

boolean shouldComputeFacets(int totalHits);
}

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

@@ -19,7 +19,6
@Override
Query parseFulltext(String fulltext) {
var parsed = super.parseFulltext(fulltext);
- searchPolicy.inspectParsedFulltextQuery(parsed);
- return parsed;
+ return searchPolicy.rewriteParsedFulltextQuery(parsed);
}
}

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

@@ -1,8 +1,9
package co.caio.cerberus.search;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
@@ -20,6 +21,8
import java.util.List;
import java.util.OptionalInt;
import java.util.function.Function;
+import org.apache.lucene.search.MatchAllDocsQuery;
+import org.apache.lucene.search.MatchNoDocsQuery;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

@@ -268,6 +271,8
void policyInspectLuceneQueryIsAlwaysCalled() {
var policyMock = mock(SearchPolicy.class);

+ given(policyMock.rewriteParsedFulltextQuery(any())).willReturn(new MatchAllDocsQuery());
+
var searcherWithPolicy =
new Searcher.Builder()
.searchPolicy(policyMock)
@@ -276,12 +281,14

searcherWithPolicy.search(new SearchQuery.Builder().fulltext("unused").build());

- verify(policyMock).inspectParsedFulltextQuery(any());
+ verify(policyMock).rewriteParsedFulltextQuery(any());
}

@Test
void policyShouldComputeFacetsIsOnlyCalledWhenRelevant() {
var policyMock = mock(SearchPolicy.class);
+
+ given(policyMock.rewriteParsedFulltextQuery(any())).willReturn(new MatchAllDocsQuery());

var searcherWithPolicy =
new Searcher.Builder()
@@ -300,6 +307,25
}

@Test
+ void policyRewriteIsCalled() {
+ var policyMock = mock(SearchPolicy.class);
+
+ // Policy will rewrite to MatchNoDocsQuery()
+ given(policyMock.rewriteParsedFulltextQuery(any())).willReturn(new MatchNoDocsQuery());
+
+ var searcherWithPolicy =
+ new Searcher.Builder()
+ .searchPolicy(policyMock)
+ .dataDirectory(Util.getTestDataDir())
+ .build();
+
+ // So even when searching for all docs, we should
+ // get zero results
+ var allQuery = new SearchQuery.Builder().fulltext("*").build();
+ assertEquals(0, searcherWithPolicy.search(allQuery).totalHits());
+ }
+
+ @Test
void throwingFromPolicyIsAllowed() {
var policyMock = mock(SearchPolicy.class);

@@ -315,7 +341,7
}
}

- doThrow(CustomTestException.class).when(policyMock).inspectParsedFulltextQuery(any());
+ doThrow(CustomTestException.class).when(policyMock).rewriteParsedFulltextQuery(any());

assertThrows(
CustomTestException.class,
@@ -325,6 +351,8
@Test
void negatingShouldComputeFacetsSkipsFacetComputation() {
var policyMock = mock(SearchPolicy.class);
+
+ given(policyMock.rewriteParsedFulltextQuery(any())).willReturn(new MatchAllDocsQuery());

var searcherWithPolicy =
new Searcher.Builder()