diff options
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.java | 90 |
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; + } } |