aboutsummaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo/vespa/documentmodel/DocumentSummary.java
blob: 6cd2d7721d5e85cc6f4d7d4928dd91ffb3ddfcc1 (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
// Copyright Vespa.ai. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.vespa.documentmodel;

import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.schema.RankProfile;
import com.yahoo.schema.Schema;
import com.yahoo.searchlib.rankingexpression.Reference;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.logging.Level;

/**
 * A document summary definition - a list of summary fields.
 *
 * @author bratseth
 */
public class DocumentSummary extends FieldView {

    private boolean fromDisk = false;
    private boolean omitSummaryFeatures = false;
    private List<String> inherited = new ArrayList<>();

    private final Schema owner;

    /** Creates a DocumentSummary with the given name. */
    public DocumentSummary(String name, Schema owner) {
        super(name);
        this.owner = owner;
    }

    public void setFromDisk(boolean fromDisk) { this.fromDisk = fromDisk; }

    /** Returns whether the user has noted explicitly that this summary accesses disk */
    public boolean isFromDisk() { return fromDisk; }

    public void setOmitSummaryFeatures(boolean value) {
        omitSummaryFeatures = value;
    }

    public boolean omitSummaryFeatures() {
        return omitSummaryFeatures;
    }

    /**
     * The model is constrained to ensure that summary fields of the same name
     * in different classes have the same summary transform, because this is
     * what is supported by the backend currently.
     * 
     * @param summaryField the summaryfield to add
     */
    public void add(SummaryField summaryField) {
        summaryField.addDestination(getName());
        super.add(summaryField);
    }

    public SummaryField getSummaryField(String name) {
        var field = (SummaryField)get(name);
        if (field != null) return field;
        if (inherited().isEmpty()) return null;
        for (var inheritedSummary : inherited()) {
            var inheritedField = inheritedSummary.getSummaryField(name);
            if (inheritedField != null)
                return inheritedField;
        }
        return null;
    }

    public Map<String, SummaryField> getSummaryFields() {
        var allFields = new LinkedHashMap<String, SummaryField>(getFields().size());
        for (var inheritedSummary : inherited()) {
            if (inheritedSummary == null) continue;
            allFields.putAll(inheritedSummary.getSummaryFields());
        }
        for (var field : getFields())
            allFields.put(field.getName(), (SummaryField) field);
        return allFields;
    }

    /**
     * Removes implicit fields which shouldn't be included.
     * This is implicitly added fields which are sources for
     * other fields. We then assume they are not intended to be added
     * implicitly in addition.
     * This should be called when this summary is complete.
     */
    public void purgeImplicits() {
        List<SummaryField> falseImplicits = new ArrayList<>();
        for (SummaryField summaryField : getSummaryFields().values()) {
            if (summaryField.isImplicit()) continue;
            for (Iterator<SummaryField.Source> j = summaryField.sourceIterator(); j.hasNext(); ) {
                String sourceName = j.next().getName();
                if (sourceName.equals(summaryField.getName())) continue;
                SummaryField sourceField=getSummaryField(sourceName);
                if (sourceField == null) continue;
                if (!sourceField.isImplicit()) continue;
                falseImplicits.add(sourceField);
            }
        }
        for (SummaryField field : falseImplicits) {
            remove(field.getName());
        }
    }

    /** Adds a parent of this. Both summaries must be present in the same schema, or a parent schema. */
    public void addInherited(String inherited) {
        this.inherited.add(inherited);
    }

    /** Returns the parent of this, if any */
    public List<DocumentSummary> inherited() {
        return inherited.stream().map(name -> owner.getSummary(name)).toList();
    }

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

    public void validate(DeployLogger logger) {
        for (var inheritedName : inherited) {
            var inheritedSummary = owner.getSummary(inheritedName);
            if (inheritedSummary == null) {
                // TODO Vespa 9: Throw IllegalArgumentException instead
                logger.logApplicationPackage(Level.WARNING,
                                             this + " inherits '" + inheritedName + "' but this" + " is not present in " + owner);
            }
        }

    }

}