// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.schema.derived; import com.yahoo.config.application.api.DeployLogger; import com.yahoo.document.DataType; import com.yahoo.prelude.fastsearch.DocsumDefinitionSet; import com.yahoo.schema.Schema; import com.yahoo.vespa.config.search.SummaryConfig; import com.yahoo.vespa.documentmodel.DocumentSummary; import com.yahoo.vespa.documentmodel.SummaryField; import com.yahoo.vespa.documentmodel.SummaryTransform; import java.util.Collections; import java.util.Map; import java.util.logging.Level; /** * A summary derived from a search definition. * Each summary definition have at least one summary, the default * which has the same name as the search definition. * * @author bratseth */ public class SummaryClass extends Derived { public static final String DOCUMENT_ID_FIELD = "documentid"; private final int id; /** True if this summary class needs to access summary information on disk */ private boolean accessingDiskSummary = false; private final boolean rawAsBase64; private final boolean omitSummaryFeatures; /** The summary fields of this indexed by name */ private final Map fields; private final DeployLogger deployLogger; /** * Creates a summary class from a search definition summary * * @param deployLogger a {@link DeployLogger} */ public SummaryClass(Schema schema, DocumentSummary summary, DeployLogger deployLogger) { super(summary.getName()); this.deployLogger = deployLogger; this.rawAsBase64 = schema.isRawAsBase64(); this.omitSummaryFeatures = summary.omitSummaryFeatures(); Map fields = new java.util.LinkedHashMap<>(); deriveFields(schema, summary, fields); deriveImplicitFields(summary, fields); this.fields = Collections.unmodifiableMap(fields); this.id = deriveId(summary.getName(), fields); } public int id() { return id; } /** MUST be called after all other fields are added */ private void deriveImplicitFields(DocumentSummary summary, Map fields) { if (summary.getName().equals("default")) { addField(SummaryClass.DOCUMENT_ID_FIELD, DataType.STRING, SummaryTransform.DOCUMENT_ID, fields); } } private void deriveFields(Schema schema, DocumentSummary summary, Map fields) { for (SummaryField summaryField : summary.getSummaryFields().values()) { if (!accessingDiskSummary && schema.isAccessingDiskSummary(summaryField)) { accessingDiskSummary = true; } addField(summaryField.getName(), summaryField.getDataType(), summaryField.getTransform(), fields); } } private void addField(String name, DataType type, SummaryTransform transform, Map fields) { if (fields.containsKey(name)) { SummaryClassField sf = fields.get(name); if ( SummaryClassField.convertDataType(type, transform, rawAsBase64) != sf.getType()) { deployLogger.logApplicationPackage(Level.WARNING, "Conflicting definition of field " + name + ". " + "Declared as type " + sf.getType() + " and " + type); } } else { fields.put(name, new SummaryClassField(name, type, transform, rawAsBase64)); } } public Map fields() { return fields; } private static int deriveId(String name, Map fields) { int hash = name.hashCode(); int number = 1; for (var field : fields.values()) { hash += number++ * (field.getName().hashCode() + 17 * field.getType().getName().hashCode()); } hash = Math.abs(hash); if (hash == DocsumDefinitionSet.SLIME_MAGIC_ID) hash++; return hash; } public SummaryConfig.Classes.Builder getSummaryClassConfig() { SummaryConfig.Classes.Builder classBuilder = new SummaryConfig.Classes.Builder(); classBuilder. id(id). name(getName()). omitsummaryfeatures(omitSummaryFeatures); for (SummaryClassField field : fields.values() ) { classBuilder.fields(new SummaryConfig.Classes.Fields.Builder(). name(field.getName()). type(field.getType().getName())); } return classBuilder; } @Override public int hashCode() { return id; } @Override protected String getDerivedName() { return "summary"; } @Override public String toString() { return "summary class '" + getName() + "'"; } }