aboutsummaryrefslogtreecommitdiffstats
path: root/container-search/src
diff options
context:
space:
mode:
authorJon Bratseth <bratseth@oath.com>2018-05-11 16:11:49 +0200
committerGitHub <noreply@github.com>2018-05-11 16:11:49 +0200
commitd6254bf1814d8046f432ff89410cc25aa059a2f0 (patch)
treeb14ffd54caac84af2f61995f72edc71a26b7fef9 /container-search/src
parent270a07a699463c6e0d509987c70509114b1ca870 (diff)
Revert "Bratseth/allocation free hit field traversal"
Diffstat (limited to 'container-search/src')
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java115
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java6
-rw-r--r--container-search/src/main/java/com/yahoo/prelude/searcher/QuotingSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java6
-rw-r--r--container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java2
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java23
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java66
-rw-r--r--container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java31
-rw-r--r--container-search/src/main/java/com/yahoo/search/result/Hit.java35
-rw-r--r--container-search/src/main/java/com/yahoo/search/yql/FieldFilter.java7
-rw-r--r--container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java9
-rw-r--r--container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java1
-rw-r--r--container-search/src/test/java/com/yahoo/search/yql/FieldFilterTestCase.java6
15 files changed, 166 insertions, 151 deletions
diff --git a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
index 4310124037e..298bd839393 100644
--- a/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
+++ b/container-search/src/main/java/com/yahoo/prelude/fastsearch/FastHit.java
@@ -19,7 +19,6 @@ import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
-import java.util.function.BiConsumer;
/**
* A regular hit from a Vespa backend
@@ -218,13 +217,7 @@ public class FastHit extends Hit {
return getSummaryValue(name);
}
- @Override
- public void forEachField(BiConsumer<String, Object> consumer) {
- super.forEachField(consumer);
- for (SummaryData summaryData : summaries)
- summaryData.forEachField(consumer);
- }
-
+ /** Returns the fields of this as a read-only map. This is more costly than fieldIterator() */
@Override
public Map<String, Object> fields() {
Map<String, Object> fields = new HashMap<>();
@@ -235,23 +228,14 @@ public class FastHit extends Hit {
return fields;
}
+ /** Returns a modifiable iterator over the fields of this */
@Override
public Iterator<Map.Entry<String, Object>> fieldIterator() {
return new FieldIterator(this, super.fieldIterator());
}
- /**
- * Returns the keys of the fields of this hit as a modifiable view.
- * This follows the rules of key sets returned from maps: Key removals are reflected
- * in the map, add and addAll is not supported.
- */
- @Override
- public Set<String> fieldKeys() {
- return new FieldSet(this);
- }
-
/** Returns a modifiable iterator over the field names of this */
- private Iterator<String> fieldNameIterator() {
+ Iterator<String> fieldNameIterator() {
return new FieldNameIterator(this, super.fieldKeys().iterator());
}
@@ -284,6 +268,16 @@ public class FastHit extends Hit {
return removedValue;
}
+ /**
+ * Returns the keys of the fields of this hit as a modifiable view.
+ * This follows the rules of key sets returned from maps: Key removals are reflected
+ * in the map, add and addAll is not supported.
+ */
+ @Override
+ public Set<String> fieldKeys() {
+ return new FieldSet(this);
+ }
+
private Set<String> mapFieldKeys() {
return super.fieldKeys();
}
@@ -526,36 +520,25 @@ public class FastHit extends Hit {
return fieldType.convert(fieldValue);
}
- void forEachField(BiConsumer<String, Object> consumer) {
- data.traverse((ObjectTraverser)(name, value) -> {
- if ( ! shadowed(name) && ! removed(name))
- consumer.accept(name, value);
- });
- }
-
- Iterator<Map.Entry<String, Object>> fieldIterator() {
- return new SummaryDataFieldIterator(this, type, data.fields().iterator());
- }
-
- Iterator<String> fieldNameIterator() {
- return new SummaryDataFieldNameIterator(this, data.fields().iterator());
+ /** Decodes the given summary into the field map in the parent */
+ private void decodeInto(FastHit hit) {
+ hit.reserve(type.getFieldCount());
+ for (DocsumField field : type.getFields()) {
+ String fieldName = field.getName();
+ Inspector f = data.field(fieldName);
+ if (field.getEmulConfig().forceFillEmptyFields() || f.valid()) {
+ if (hit.getField(fieldName) == null)
+ hit.setField(fieldName, field.convert(f));
+ }
+ }
}
- /**
- * Returns whether this field is present in the map properties
- * or an earlier (lower index) summary in this hit
- */
- private boolean shadowed(String name) {
- if (hit.hasField(name)) return true;
- for (int i = 0; i < index; i++) {
- if (hit.summaries.get(i).type.fieldNames().contains(name))
- return true;
- }
- return false;
+ private Iterator<Map.Entry<String, Object>> fieldIterator() {
+ return new SummaryDataFieldIterator(hit, type, data.fields().iterator(), index);
}
- private boolean removed(String fieldName) {
- return hit.removedFields != null && hit.removedFields.contains(fieldName);
+ private Iterator<String> fieldNameIterator() {
+ return new SummaryDataFieldNameIterator(hit, data.fields().iterator(), index);
}
/**
@@ -564,15 +547,19 @@ public class FastHit extends Hit {
*/
private static abstract class SummaryDataIterator<VALUE> implements Iterator<VALUE> {
- private final SummaryData summaryData;
+ private final FastHit hit;
private final Iterator<Map.Entry<String, Inspector>> fieldIterator;
+ private final int index;
/** The next value or null if none, eagerly read because we need to skip removed and overwritten values */
private VALUE next;
- SummaryDataIterator(SummaryData summaryData, Iterator<Map.Entry<String, Inspector>> fieldIterator) {
- this.summaryData = summaryData;
+ SummaryDataIterator(FastHit hit,
+ Iterator<Map.Entry<String, Inspector>> fieldIterator,
+ int index) {
+ this.hit = hit;
this.fieldIterator = fieldIterator;
+ this.index = index;
}
@Override
@@ -596,23 +583,40 @@ public class FastHit extends Hit {
Map.Entry<String, Inspector> nextEntry = fieldIterator.next();
String fieldName = nextEntry.getKey();
next = toValue(nextEntry);
- if ( next != null && ! summaryData.shadowed(fieldName) && ! summaryData.removed(fieldName))
+ if ( next != null &&
+ ! hit.hasField(fieldName) &&
+ ! isRemoved(fieldName) &&
+ ! isAlreadyReturned(fieldName))
return;
}
next = null;
}
+ private boolean isRemoved(String fieldName) {
+ return hit.removedFields != null && hit.removedFields.contains(fieldName);
+ }
+
+ private boolean isAlreadyReturned(String fieldName) {
+ for (int i = 0; i < index; i++) {
+ if (hit.summaries.get(i).type.fieldNames().contains(fieldName))
+ return true;
+ }
+ return false;
+ }
+
}
+
/** Iterator over the fields in a SummaryData instance. Read only. */
private static class SummaryDataFieldIterator extends SummaryDataIterator<Map.Entry<String, Object>> {
private final DocsumDefinition type;
- SummaryDataFieldIterator(SummaryData summaryData,
+ SummaryDataFieldIterator(FastHit hit,
DocsumDefinition type,
- Iterator<Map.Entry<String, Inspector>> fieldIterator) {
- super(summaryData, fieldIterator);
+ Iterator<Map.Entry<String, Inspector>> fieldIterator,
+ int index) {
+ super(hit, fieldIterator, index);
this.type = type;
advanceNext();
}
@@ -650,9 +654,10 @@ public class FastHit extends Hit {
/** Iterator over the field names in a SummaryData instance. Read only. */
private static class SummaryDataFieldNameIterator extends SummaryDataIterator<String> {
- SummaryDataFieldNameIterator(SummaryData summaryData,
- Iterator<Map.Entry<String, Inspector>> fieldIterator) {
- super(summaryData, fieldIterator);
+ SummaryDataFieldNameIterator(FastHit hit,
+ Iterator<Map.Entry<String, Inspector>> fieldIterator,
+ int index) {
+ super(hit, fieldIterator, index);
advanceNext();
}
diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java
index 415ebd7871c..164ff9a993b 100644
--- a/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/searcher/DocumentSourceSearcher.java
@@ -74,7 +74,7 @@ public class DocumentSourceSearcher extends Searcher {
removePropertiesNotStartingByA(attributeHit);
attributeHit.setFillable();
attributeHit.setRelevance(fullHit.getRelevance());
- for (Object propertyKeyObject : fullHit.fields().keySet()) {
+ for (Object propertyKeyObject : (Set) fullHit.fields().keySet()) {
String propertyKey=propertyKeyObject.toString();
if (propertyKey.startsWith("attribute"))
attributeHit.setField(propertyKey, fullHit.getField(propertyKey));
diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java
index ca87c0c1d46..9e1808bb08e 100644
--- a/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/searcher/JuniperSearcher.java
@@ -107,12 +107,6 @@ public class JuniperSearcher extends Searcher {
if (searchDefinitionField == null) continue;
String searchDefinitionName = searchDefinitionField.toString();
- // TODO: Switch to iterate over indexes in the outer loop:
- //for (Index index : indexFacts.getIndexes(searchDefinitionName())) {
- // if (index.getDynamicSummary() || index.getHighlightSummary()) {
- // insertTags(hit.buildHitField(index.getName(), true, true), bolding, index.getDynamicSummary());
- // }
- //}
for (String fieldName : hit.fields().keySet()) {
Index index = indexFacts.getIndex(fieldName, searchDefinitionName);
if (index.getDynamicSummary() || index.getHighlightSummary())
diff --git a/container-search/src/main/java/com/yahoo/prelude/searcher/QuotingSearcher.java b/container-search/src/main/java/com/yahoo/prelude/searcher/QuotingSearcher.java
index d4cad7f1246..7ff5b1b1a0e 100644
--- a/container-search/src/main/java/com/yahoo/prelude/searcher/QuotingSearcher.java
+++ b/container-search/src/main/java/com/yahoo/prelude/searcher/QuotingSearcher.java
@@ -20,7 +20,7 @@ import com.yahoo.search.searchchain.Execution;
*
* May be extended to do quoting template sensitive.
*
- * @author Steinar Knutsen
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
*/
public class QuotingSearcher extends Searcher {
diff --git a/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java b/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java
index 37906c8012f..259b219b181 100644
--- a/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/grouping/result/HitRenderer.java
@@ -13,7 +13,7 @@ import java.util.Map;
/**
* This is a helper class for rendering grouping results.
*
- * @author Simon Thoresen
+ * @author <a href="mailto:simon@yahoo-inc.com">Simon Thoresen</a>
*/
public abstract class HitRenderer {
@@ -50,7 +50,9 @@ public abstract class HitRenderer {
if (hit instanceof RootGroup) {
renderContinuation(Continuation.THIS_PAGE, ((RootGroup)hit).continuation(), writer);
}
- hit.forEachField((name, value) -> writer.openTag(TAG_OUTPUT).attribute(ATR_LABEL, name).content(value, false).closeTag());
+ for (String label : hit.fieldKeys()) {
+ writer.openTag(TAG_OUTPUT).attribute(ATR_LABEL, label).content(hit.getField(label), false).closeTag();
+ }
} else if (hit instanceof HitList) {
writer.openTag(TAG_HIT_LIST).attribute(ATR_LABEL, ((HitList)hit).getLabel());
renderContinuations(((HitList)hit).continuations(), writer);
diff --git a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
index 3e6e82a5584..97a5bdd72ca 100644
--- a/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
+++ b/container-search/src/main/java/com/yahoo/search/pagetemplates/engine/Organizer.java
@@ -37,7 +37,11 @@ public class Organizer {
sectionGroup.setQuery(result.hits().getQuery());
if (errors!=null && errors instanceof DefaultErrorHit)
sectionGroup.add((DefaultErrorHit)errors);
- result.hits().forEachField((name, value) -> sectionGroup.setField(name, value));
+ for (Iterator<Map.Entry<String, Object>> it = result.hits().fieldIterator(); it.hasNext(); ) {
+ Map.Entry<String, Object> field = it.next();
+ sectionGroup.setField(field.getKey(), field.getValue());
+ }
+
result.setHits(sectionGroup);
}
diff --git a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
index 2768a546cd0..c64927072e2 100644
--- a/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
+++ b/container-search/src/main/java/com/yahoo/search/querytransform/NGramSearcher.java
@@ -160,7 +160,7 @@ public class NGramSearcher extends Searcher {
if (hit.isMeta()) continue;
Object sddocname = hit.getField(Hit.SDDOCNAME_FIELD);
if (sddocname == null) return;
- for (String fieldName : hit.fieldKeys()) { // TODO: Iterate over indexes instead
+ for (String fieldName : hit.fieldKeys()) {
Index index = session.getIndex(fieldName, sddocname.toString());
if (index.isNGram() && (index.getHighlightSummary() || index.getDynamicSummary())) {
hit.setField(fieldName, recombineNGramsField(hit.getField(fieldName), index.getGramSize()));
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
index 2d69a262f15..bae1185d6a9 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/DefaultRenderer.java
@@ -185,19 +185,28 @@ public final class DefaultRenderer extends AsynchronousSectionedRenderer<Result>
private void renderHitFields(XMLWriter writer, Hit hit) {
renderSyntheticRelevanceField(writer, hit);
- hit.forEachField((name, value) -> renderField(writer, name, value));
+ for (Iterator<Map.Entry<String, Object>> it = hit.fieldIterator(); it.hasNext(); ) {
+ renderField(writer, hit, it);
+ }
+ }
+
+ private void renderField(XMLWriter writer, Hit hit, Iterator<Map.Entry<String, Object>> it) {
+ renderGenericField(writer, hit, it.next());
}
- private void renderField(XMLWriter writer, String name, Object value) {
- if (name.startsWith("$")) return;
+ private void renderGenericField(XMLWriter writer, Hit hit, Map.Entry<String, Object> entry) {
+ String fieldName = entry.getKey();
+
+ // skip depending on hit type
+ if (fieldName.startsWith("$")) return; // Don't render fields that start with $ // TODO: Move to should render
- writeOpenFieldElement(writer, name);
- renderFieldContent(writer, value);
+ writeOpenFieldElement(writer, fieldName);
+ renderFieldContent(writer, hit, fieldName);
writeCloseFieldElement(writer);
}
- private void renderFieldContent(XMLWriter writer, Object value) {
- writer.escapedContent(asXML(value), false);
+ private void renderFieldContent(XMLWriter writer, Hit hit, String fieldName) {
+ writer.escapedContent(asXML(hit.getField(fieldName)), false);
}
private String asXML(Object value) {
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
index 6c7018317c3..34b02b1bee8 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/JsonRenderer.java
@@ -14,7 +14,7 @@ import com.yahoo.document.datatypes.FieldValue;
import com.yahoo.document.datatypes.StringFieldValue;
import com.yahoo.document.datatypes.TensorFieldValue;
import com.yahoo.document.json.JsonWriter;
-import com.yahoo.lang.MutableBoolean;
+import com.yahoo.prelude.fastsearch.FastHit;
import com.yahoo.processing.Response;
import com.yahoo.processing.execution.Execution.Trace;
import com.yahoo.processing.rendering.AsynchronousSectionedRenderer;
@@ -49,7 +49,6 @@ import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
-import java.io.UncheckedIOException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
@@ -473,14 +472,14 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> {
return ! (hit instanceof DefaultErrorHit);
}
- private void fieldsStart(MutableBoolean hasFieldsField) throws IOException {
- if (hasFieldsField.get()) return;
+ private boolean fieldsStart(boolean hasFieldsField) throws IOException {
+ if (hasFieldsField) return true;
generator.writeObjectFieldStart(FIELDS);
- hasFieldsField.set(true);
+ return true;
}
- private void fieldsEnd(MutableBoolean hasFieldsField) throws IOException {
- if ( ! hasFieldsField.get()) return;
+ private void fieldsEnd(boolean hasFieldsField) throws IOException {
+ if (!hasFieldsField) return;
generator.writeEndObject();
}
@@ -509,37 +508,39 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> {
}
private void renderAllFields(Hit hit) throws IOException {
- MutableBoolean hasFieldsField = new MutableBoolean(false);
- renderTotalHitCount(hit, hasFieldsField);
- renderStandardFields(hit, hasFieldsField);
+ boolean hasFieldsField = false;
+
+ hasFieldsField |= renderTotalHitCount(hit, hasFieldsField);
+ hasFieldsField |= renderStandardFields(hit, hasFieldsField);
fieldsEnd(hasFieldsField);
}
- private void renderStandardFields(Hit hit, MutableBoolean hasFieldsField) {
- hit.forEachField((name, value) -> {
- try {
- if (shouldRender(name, value)) {
- fieldsStart(hasFieldsField);
- renderField(name, value);
- }
- }
- catch (IOException e) {
- throw new UncheckedIOException(e);
- }
- });
+ private boolean renderStandardFields(Hit hit, boolean initialHasFieldsField) throws IOException {
+ boolean hasFieldsField = initialHasFieldsField;
+ for (String fieldName : hit.fieldKeys()) {
+ if (!shouldRender(fieldName, hit)) continue;
+
+ // We can't look at the size of fieldKeys() and know whether we need
+ // the fields object, as all fields may be hidden.
+ hasFieldsField |= fieldsStart(hasFieldsField);
+ renderField(fieldName, hit);
+ }
+ return hasFieldsField;
}
- private boolean shouldRender(String name, Object value) {
+ private boolean shouldRender(String fieldName, Hit hit) {
if (debugRendering) return true;
- if (name.startsWith(VESPA_HIDDEN_FIELD_PREFIX)) return false;
+ if (fieldName.startsWith(VESPA_HIDDEN_FIELD_PREFIX)) return false;
- if (value instanceof CharSequence && ((CharSequence) value).length() == 0) return false;
+ Object field = hit.getField(fieldName);
+
+ if (field instanceof CharSequence && ((CharSequence) field).length() == 0) return false;
// StringFieldValue cannot hold a null, so checking length directly is OK:
- if (value instanceof StringFieldValue && ((StringFieldValue) value).getString().isEmpty()) return false;
+ if (field instanceof StringFieldValue && ((StringFieldValue) field).getString().isEmpty()) return false;
- if (value instanceof NanNumber) return false;
+ if (field instanceof NanNumber) return false;
return true;
}
@@ -606,16 +607,17 @@ public class JsonRenderer extends AsynchronousSectionedRenderer<Result> {
return (id instanceof RawBucketId ? Arrays.toString(((RawBucketId) id).getTo()) : id.getTo()).toString();
}
- private void renderTotalHitCount(Hit hit, MutableBoolean hasFieldsField) throws IOException {
- if ( ! (getRecursionLevel() == 1 && hit instanceof HitGroup)) return;
+ private boolean renderTotalHitCount(Hit hit, boolean hasFieldsField) throws IOException {
+ if ( ! (getRecursionLevel() == 1 && hit instanceof HitGroup)) return false;
fieldsStart(hasFieldsField);
generator.writeNumberField(TOTAL_COUNT, getResult().getTotalHitCount());
+ return true;
}
- private void renderField(String name, Object value) throws IOException {
- generator.writeFieldName(name);
- renderFieldContents(value);
+ private void renderField(String fieldName, Hit hit) throws IOException {
+ generator.writeFieldName(fieldName);
+ renderFieldContents(hit.getField(fieldName));
}
private void renderFieldContents(Object field) throws IOException {
diff --git a/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java b/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
index 08599540cb1..dc72061e224 100644
--- a/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
+++ b/container-search/src/main/java/com/yahoo/search/rendering/SyncDefaultRenderer.java
@@ -271,19 +271,25 @@ public final class SyncDefaultRenderer extends Renderer {
private void renderHitFields(XMLWriter writer, Hit hit) {
renderSyntheticRelevanceField(writer, hit);
- hit.forEachField((name, value) -> renderField(writer, name, value));
+ for (Iterator<Map.Entry<String, Object>> it = hit.fieldIterator(); it.hasNext(); ) {
+ renderField(writer, hit, it);
+ }
}
- private void renderField(XMLWriter writer, String name, Object value) {
- if (name.startsWith("$")) return;
+ private void renderField(XMLWriter writer, Hit hit, Iterator<Map.Entry<String, Object>> it) {
+ Map.Entry<String, Object> entry = it.next();
+ String fieldName = entry.getKey();
+
+ if ( ! shouldRenderField(hit, fieldName)) return;
+ if (fieldName.startsWith("$")) return; // Don't render fields that start with $ // TODO: Move to should render
- writeOpenFieldElement(writer, name);
- renderFieldContent(writer, value);
+ writeOpenFieldElement(writer, fieldName);
+ renderFieldContent(writer, hit, fieldName);
writeCloseFieldElement(writer);
}
- private void renderFieldContent(XMLWriter writer, Object value) {
- writer.escapedContent(asXML(value), false);
+ private void renderFieldContent(XMLWriter writer, Hit hit, String fieldName) {
+ writer.escapedContent(asXML(hit.getField(fieldName)), false);
}
private String asXML(Object value) {
@@ -298,10 +304,10 @@ public final class SyncDefaultRenderer extends Renderer {
}
private void renderSyntheticRelevanceField(XMLWriter writer, Hit hit) {
- String relevancyFieldName = "relevancy";
- Relevance relevance = hit.getRelevance();
+ final String relevancyFieldName = "relevancy";
+ final Relevance relevance = hit.getRelevance();
- if (relevance != null) {
+ if (shouldRenderField(hit, relevancyFieldName) && relevance != null) {
renderSimpleField(writer, relevancyFieldName, relevance);
}
}
@@ -326,6 +332,11 @@ public final class SyncDefaultRenderer extends Renderer {
writer.closeStartTag();
}
+ private boolean shouldRenderField(Hit hit, String relevancyFieldName) {
+ // skip depending on hit type
+ return true;
+ }
+
private void renderHitAttributes(XMLWriter writer, Hit hit) {
writer.attribute(TYPE, hit.types().stream().collect(Collectors.joining(" ")));
if (hit.getRelevance() != null) {
diff --git a/container-search/src/main/java/com/yahoo/search/result/Hit.java b/container-search/src/main/java/com/yahoo/search/result/Hit.java
index f68916c8a68..15c148b7db7 100644
--- a/container-search/src/main/java/com/yahoo/search/result/Hit.java
+++ b/container-search/src/main/java/com/yahoo/search/result/Hit.java
@@ -21,7 +21,6 @@ import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
-import java.util.function.BiConsumer;
import java.util.stream.Collectors;
/**
@@ -402,30 +401,10 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
/** Returns the name of the source creating this hit */
public String getSource() { return source; }
- /**
- * Receive a callback on the given object for each field in this hit.
- * This is the most resource efficient way of traversing all the fields of a hit.
- */
- public void forEachField(BiConsumer<String, Object> consumer) {
- if (fields == null) return;
- fields.forEach(consumer);
- }
-
/** Returns the fields of this as a read-only map. This is more costly than fieldIterator() */
+ // TODO Should it be deprecated ?
public Map<String, Object> fields() { return getUnmodifiableFieldMap(); }
- /** Returns a modifiable iterator over the fields of this */
- public Iterator<Map.Entry<String, Object>> fieldIterator() { return getFieldMap().entrySet().iterator(); }
-
- /**
- * Returns the keys of the fields of this hit as a modifiable view.
- * This follows the rules of key sets returned from maps: Key removals are reflected
- * in the map, add and addAll is not supported.
- */
- public Set<String> fieldKeys() {
- return getFieldMap().keySet();
- }
-
/** Allocate room for the given number of fields to avoid resizing. */
public void reserve(int minSize) {
getFieldMap(minSize);
@@ -440,6 +419,9 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
return getFieldMap().put(key, value);
}
+ /** Returns a modifiable iterator over the fields of this */
+ public Iterator<Map.Entry<String, Object>> fieldIterator() { return getFieldMap().entrySet().iterator(); }
+
/** Returns a field value or null if not present */
public Object getField(String value) { return fields != null ? fields.get(value) : null; }
@@ -457,6 +439,15 @@ public class Hit extends ListenableFreezableClass implements Data, Comparable<Hi
return getFieldMap().remove(field);
}
+ /**
+ * Returns the keys of the fields of this hit as a modifiable view.
+ * This follows the rules of key sets returned from maps: Key removals are reflected
+ * in the map, add and addAll is not supported.
+ */
+ public Set<String> fieldKeys() {
+ return getFieldMap().keySet();
+ }
+
protected boolean hasField(String name) {
return fields != null && fields.containsKey(name);
}
diff --git a/container-search/src/main/java/com/yahoo/search/yql/FieldFilter.java b/container-search/src/main/java/com/yahoo/search/yql/FieldFilter.java
index 14dce2f6342..75c2865d0a5 100644
--- a/container-search/src/main/java/com/yahoo/search/yql/FieldFilter.java
+++ b/container-search/src/main/java/com/yahoo/search/yql/FieldFilter.java
@@ -52,7 +52,12 @@ public class FieldFilter extends Searcher {
for (Iterator<Hit> i = result.hits().unorderedDeepIterator(); i.hasNext();) {
Hit h = i.next();
if (h.isMeta()) continue;
- h.fieldKeys().retainAll(requestedFields);
+ for (Iterator<Entry<String, Object>> fields = h.fieldIterator(); fields.hasNext();) {
+ Entry<String, Object> field = fields.next();
+ if ( ! requestedFields.contains(field.getKey()))
+ fields.remove();
+ }
+
}
}
diff --git a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java
index 1b74a6c5b29..83871b559b4 100644
--- a/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java
+++ b/container-search/src/test/java/com/yahoo/prelude/fastsearch/SlimeSummaryTestCase.java
@@ -31,7 +31,6 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
public class SlimeSummaryTestCase {
@@ -287,14 +286,6 @@ public class SlimeSummaryTestCase {
assertEquals(field.getValue(), expected.get(field.getKey()));
}
assertEquals(expected.size(), fieldIteratorFieldCount);
- // field traverser
- Map<String, Object> traversed = new HashMap<>();
- hit.forEachField((name, value) -> {
- if (traversed.containsKey(name))
- fail("Multiple callbacks for " + name);
- traversed.put(name, value);
- });
- assertEquals(expected, traversed);
}
private byte[] emptySummary() {
diff --git a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java
index 4a0075c0cf1..defabc7463b 100644
--- a/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/rendering/JsonRendererTestCase.java
@@ -1069,6 +1069,7 @@ public class JsonRendererTestCase {
r.getElapsedTime().add(t);
renderer.setTimeSource(() -> 8L);
String summary = render(r);
+ System.out.println(summary);
assertEqualJson(expected, summary);
}
diff --git a/container-search/src/test/java/com/yahoo/search/yql/FieldFilterTestCase.java b/container-search/src/test/java/com/yahoo/search/yql/FieldFilterTestCase.java
index 50313b630ea..f5097aec6e1 100644
--- a/container-search/src/test/java/com/yahoo/search/yql/FieldFilterTestCase.java
+++ b/container-search/src/test/java/com/yahoo/search/yql/FieldFilterTestCase.java
@@ -20,10 +20,9 @@ import com.yahoo.search.searchchain.testutil.DocumentSourceSearcher;
/**
* Smoketest that we remove fields in a sane manner.
*
- * @author Steinar Knutsen
+ * @author <a href="mailto:steinar@yahoo-inc.com">Steinar Knutsen</a>
*/
public class FieldFilterTestCase {
-
private static final String FIELD_C = "c";
private static final String FIELD_B = "b";
private static final String FIELD_A = "a";
@@ -42,7 +41,8 @@ public class FieldFilterTestCase {
DocumentSourceSearcher mockBackend = new DocumentSourceSearcher();
mockBackend.addResult(query, result);
- searchChain = new Chain<Searcher>(new FieldFilter(), mockBackend);
+ searchChain = new Chain<Searcher>(new FieldFilter(),
+ mockBackend);
context = Execution.Context.createContextStub(null);
execution = new Execution(searchChain, context);