aboutsummaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo/searchdefinition/derived/SummaryClass.java
blob: 6c233aacf30be9ca0d956065017b988980ff798b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchdefinition.derived;

import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.document.DataType;
import com.yahoo.prelude.fastsearch.DocsumDefinitionSet;
import com.yahoo.searchdefinition.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.Iterator;
import java.util.Map;
import java.util.Random;
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";

    /** 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<String,SummaryClassField> fields = new java.util.LinkedHashMap<>();

    private final DeployLogger deployLogger;

    private final Random random = new Random(7);

    /**
     * Creates a summary class from a search definition summary
     *
     * @param deployLogger a {@link DeployLogger}
     */
    public SummaryClass(Schema schema, DocumentSummary summary, DeployLogger deployLogger) {
        this.deployLogger = deployLogger;
        this.rawAsBase64 = schema.isRawAsBase64();
        this.omitSummaryFeatures = summary.omitSummaryFeatures();
        deriveName(summary);
        deriveFields(schema, summary);
        deriveImplicitFields(summary);
    }

    private void deriveName(DocumentSummary summary) {
        setName(summary.getName());
    }

    /** MUST be called after all other fields are added */
    private void deriveImplicitFields(DocumentSummary summary) {
        if (summary.getName().equals("default")) {
            addField(SummaryClass.DOCUMENT_ID_FIELD, DataType.STRING);
        }
    }

    private void deriveFields(Schema schema, DocumentSummary summary) {
        for (SummaryField summaryField : summary.getSummaryFields().values()) {
            if (!accessingDiskSummary && schema.isAccessingDiskSummary(summaryField)) {
                accessingDiskSummary = true;
            }
            addField(summaryField.getName(), summaryField.getDataType(), summaryField.getTransform());
        }
    }

    private void addField(String name, DataType type) {
        addField(name, type, null);
    }

    private void addField(String name, DataType type, SummaryTransform transform) {
        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));
        }
    }


    /** Returns an iterator of the fields of this summary. Removes on this iterator removes the field from this summary */
    public Iterator<SummaryClassField> fieldIterator() {
        return fields.values().iterator();
    }

    public void addField(SummaryClassField field) {
        fields.put(field.getName(),field);
    }

    /** Returns the writable map of fields of this summary */ // TODO: Make read only, move writers to iterator/addField
    public Map<String,SummaryClassField> getFields() { return fields; }

    public SummaryClassField getField(String name) {
        return fields.get(name);
    }

    public int getFieldCount() { return fields.size(); }

    @Override
    public int hashCode() {
        int number = 1;
        int hash = getName().hashCode();
        for (Iterator i = fieldIterator(); i.hasNext(); ) {
            SummaryClassField field = (SummaryClassField)i.next();
            hash += number * (field.getName().hashCode() +
                              17*field.getType().getName().hashCode());
            number++;
        }
        if (hash < 0)
            hash *= -1;
        return hash;
    }

    public SummaryConfig.Classes.Builder getSummaryClassConfig() {
        SummaryConfig.Classes.Builder classBuilder = new SummaryConfig.Classes.Builder();
        int id = hashCode();
        if (id == DocsumDefinitionSet.SLIME_MAGIC_ID) {
            deployLogger.log(Level.WARNING, "Summary class '" + getName() + "' hashes to the SLIME_MAGIC_ID '" + id +
                                            "'. This is unlikely but I autofix it for you by adding a random number.");
            id += random.nextInt();
        }
        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
    protected String getDerivedName() { return "summary"; }

    @Override
    public String toString() {
        return "summary class " + getName();
    }

}