summaryrefslogtreecommitdiffstats
path: root/container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java90
1 files changed, 65 insertions, 25 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java
index 708c6de1212..0559bd808bc 100644
--- a/container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/searcher/FieldCollapsingSearcher.java
@@ -6,18 +6,20 @@ import com.yahoo.component.chain.dependencies.After;
import com.yahoo.component.chain.dependencies.Before;
import com.yahoo.container.QrSearchersConfig;
import com.yahoo.prelude.fastsearch.FastHit;
+import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.Query;
import com.yahoo.search.Result;
import com.yahoo.search.Searcher;
-import com.yahoo.processing.request.CompoundName;
+import com.yahoo.search.query.Properties;
import com.yahoo.search.result.Hit;
import com.yahoo.search.searchchain.Execution;
import com.yahoo.search.searchchain.PhaseNames;
+import java.util.Arrays;
import java.util.Map;
/**
- * A searcher which does parametrized collapsing.
+ * A searcher which does parameterized collapsing.
*
* @author Steinar Knutsen
*/
@@ -30,12 +32,16 @@ public class FieldCollapsingSearcher extends Searcher {
private static final CompoundName collapsesize = CompoundName.from("collapsesize");
private static final CompoundName collapseSummaryName = CompoundName.from("collapse.summary");
+ /** Separator used for the fieldnames in collapsefield */
+ private static final String separator = ",";
+
/** Maximum number of queries to send next searcher */
private static final int maxQueries = 4;
/**
* The max number of hits that will be preserved per unique
- * value of the collapsing parameter.
+ * value of the collapsing parameter,
+ * if no field-specific value is configured.
*/
private int defaultCollapseSize;
@@ -85,11 +91,14 @@ public class FieldCollapsingSearcher extends Searcher {
*/
@Override
public Result search(com.yahoo.search.Query query, Execution execution) {
- String collapseField = query.properties().getString(collapsefield);
+ String collapseFieldParam = query.properties().getString(collapsefield);
+
+ if (collapseFieldParam == null) return execution.search(query);
+
+ String[] collapseFields = collapseFieldParam.split(separator);
- if (collapseField == null) return execution.search(query);
+ int globalCollapseSize = query.properties().getInteger(collapsesize, defaultCollapseSize);
- int collapseSize = query.properties().getInteger(collapsesize, defaultCollapseSize);
query.properties().set(collapse, "0");
int hitsToRequest = query.getHits() != 0 ? (int) Math.ceil((query.getOffset() + query.getHits() + 1) * extraFactor) : 0;
@@ -103,12 +112,15 @@ public class FieldCollapsingSearcher extends Searcher {
String collapseSummary = query.properties().getString(collapseSummaryName);
String summaryClass = (collapseSummary == null)
? query.getPresentation().getSummary() : collapseSummary;
- query.trace("Collapsing by '" + collapseField + "' using summary '" + collapseSummary + "'", 2);
+ query.trace("Collapsing by '" + Arrays.toString(collapseFields) + "' using summary '" + collapseSummary + "'", 2);
do {
resultSource = search(query.clone(), execution, nextOffset, hitsToRequest);
fill(resultSource, summaryClass, execution);
- collapse(result, knownCollapses, resultSource, collapseField, collapseSize);
+
+ collapse(result, knownCollapses, resultSource,
+ collapseFields, query.properties(), globalCollapseSize
+ );
hitsAfterCollapse = result.getHitCount();
if (resultSource.getTotalHitCount() < (hitsToRequest + nextOffset)) {
@@ -143,35 +155,63 @@ public class FieldCollapsingSearcher extends Searcher {
/**
* Collapse logic. Preserves only maxHitsPerField hits
- * for each unique value of the collapsing parameter.
+ * for each unique value of the collapsing parameters.
+ * Uses collapsefields sequentially.
*/
- private void collapse(Result result, Map<String, Integer> knownCollapses,
- Result resultSource, String collapseField, int collapseSize) {
+ private void collapse(Result result, Map<String, Integer> knownCollapses, Result resultSource,
+ String[] collapseFields, Properties queryProperties, int globalCollapseSize) {
+
for (Hit unknownHit : resultSource.hits()) {
if (!(unknownHit instanceof FastHit hit)) {
result.hits().add(unknownHit);
continue;
}
- Object peek = hit.getField(collapseField);
- String collapseId = peek != null ? peek.toString() : null;
- if (collapseId == null) {
- result.hits().add(hit);
- continue;
- }
- if (knownCollapses.containsKey(collapseId)) {
- int numHitsThisField = knownCollapses.get(collapseId);
+ boolean addHit = true;
- if (numHitsThisField < collapseSize) {
- result.hits().add(hit);
- ++numHitsThisField;
- knownCollapses.put(collapseId, numHitsThisField);
+ for (String collapseField : collapseFields) {
+
+ Object peek = hit.getField(collapseField);
+ String collapseId = peek != null ? peek.toString() : null;
+ if (collapseId == null) {
+ continue;
+ }
+
+ // prepending the fieldname is necessary to distinguish between values in the different collapsefields
+ // @ cannot occur in fieldnames
+ String collapseKey = collapseField + "@" + collapseId;
+
+ if (knownCollapses.containsKey(collapseKey)) {
+ int numHitsThisField = knownCollapses.get(collapseKey);
+ int collapseSize = getCollapseSize(queryProperties, collapseField, globalCollapseSize);
+
+ if (numHitsThisField < collapseSize) {
+ ++numHitsThisField;
+ knownCollapses.put(collapseKey, numHitsThisField);
+ } else {
+ addHit = false;
+ // immediate return, so that following collapseFields do not record the fieldvalues of this hit
+ // needed for sequential collapsing, otherwise later collapsefields would remove too many hits
+ break;
+ }
+ } else {
+ knownCollapses.put(collapseKey, 1);
}
- } else {
- knownCollapses.put(collapseId, 1);
+ }
+
+ if (addHit) {
result.hits().add(hit);
}
}
}
+ private int getCollapseSize(Properties properties, String fieldName, int globalCollapseSize) {
+ Integer fieldCollapseSize = properties.getInteger(collapsesize.append(fieldName));
+
+ if (fieldCollapseSize != null) {
+ return fieldCollapseSize;
+ }
+
+ return globalCollapseSize;
+ }
}