aboutsummaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo/schema/processing/Processor.java
blob: 9768f33c27d511f69a6f614705b33e7d1f5b50bd (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
153
154
155
156
157
// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.schema.processing;

import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.config.model.api.ModelContext;
import com.yahoo.document.DataType;
import com.yahoo.document.Field;
import com.yahoo.schema.Index;
import com.yahoo.schema.RankProfile;
import com.yahoo.schema.RankProfileRegistry;
import com.yahoo.schema.Schema;
import com.yahoo.schema.document.RankType;
import com.yahoo.schema.document.SDField;
import com.yahoo.schema.document.Stemming;
import com.yahoo.vespa.model.container.search.QueryProfiles;

import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;

/**
 * Abstract superclass of all search definition processors.
 *
 * @author bratseth
 */
public abstract class Processor {

    protected final Schema schema;
    protected final DeployLogger deployLogger;
    protected final RankProfileRegistry rankProfileRegistry;
    protected final QueryProfiles queryProfiles;

    /**
     * Base constructor
     *
     * @param schema the search to process
     * @param deployLogger Logger du use when logging deploy output.
     * @param rankProfileRegistry Registry with all rank profiles, used for lookup and insertion.
     * @param queryProfiles The query profiles contained in the application this search is part of.
     */
    public Processor(Schema schema,
                     DeployLogger deployLogger,
                     RankProfileRegistry rankProfileRegistry,
                     QueryProfiles queryProfiles) {
        this.schema = schema;
        this.deployLogger = deployLogger;
        this.rankProfileRegistry = rankProfileRegistry;
        this.queryProfiles = queryProfiles;
    }

    /**
     * Processes the input search definition by <b>modifying</b> the input search and its documents, and returns the
     * input search definition.
     *
     * @param validate true to throw exceptions on validation errors, false to make the best possible effort
     *                 at completing processing without throwing an exception.
     *                 If we are not validating, emitting warnings have no effect and can (but must not) be skipped.
     * @param documentsOnly true to skip processing (including validation, regardless of the validate setting)
     *                      of aspects not relating to document definitions (e.g rank profiles)
     */
    public abstract void process(boolean validate, boolean documentsOnly);

    /**
     * As above, possibly with properties from a context.  Override if needed.
     **/
    public void process(boolean validate, boolean documentsOnly, ModelContext.Properties properties) {
        process(validate, documentsOnly);
    }

    /**
     * Convenience method for adding a no-strings-attached implementation field for a regular field
     *
     * @param schema       the search definition in question
     * @param field        the field to add an implementation field for
     * @param suffix       the suffix of the added implementation field (without the underscore)
     * @param indexing     the indexing statement of the field
     * @param queryCommand the query command of the original field, or null if none
     * @return the implementation field which is added to the search
     */
    protected SDField addField(Schema schema, SDField field, String suffix, String indexing, String queryCommand) {
        SDField implementationField = schema.getConcreteField(field.getName() + "_" + suffix);
        if (implementationField != null) {
            deployLogger.logApplicationPackage(Level.WARNING, "Implementation field " + implementationField + " added twice");
        } else {
            implementationField = new SDField(schema.getDocument(), field.getName() + "_" + suffix, DataType.STRING);
        }
        implementationField.setRankType(RankType.EMPTY);
        implementationField.setStemming(Stemming.NONE);
        implementationField.getNormalizing().inferCodepoint();
        implementationField.parseIndexingScript(indexing);
        String indexName = field.getName();
        String implementationIndexName = indexName + "_" + suffix;
        Index implementationIndex = new Index(implementationIndexName);
        schema.addIndex(implementationIndex);
        if (queryCommand != null) {
            field.addQueryCommand(queryCommand);
        }
        schema.addExtraField(implementationField);
        schema.fieldSets().addBuiltInFieldSetItem(BuiltInFieldSets.INTERNAL_FIELDSET_NAME, implementationField.getName());
        return implementationField;
    }

    /**
     * Returns an iterator of all the rank settings with given type in all the rank  profiles in this search
     * definition.
     */
    protected Iterator<RankProfile.RankSetting> matchingRankSettingsIterator(
            Schema schema, RankProfile.RankSetting.Type type)
    {
        List<RankProfile.RankSetting> someRankSettings = new java.util.ArrayList<>();

        for (RankProfile profile : rankProfileRegistry.rankProfilesOf(schema)) {
            for (Iterator j = profile.declaredRankSettingIterator(); j.hasNext(); ) {
                RankProfile.RankSetting setting = (RankProfile.RankSetting)j.next();
                if (setting.getType().equals(type)) {
                    someRankSettings.add(setting);
                }
            }
        }
        return someRankSettings.iterator();
    }

    protected String formatError(String schemaName, String fieldName, String msg) {
        return "For schema '" + schemaName + "', field '" + fieldName + "': " + msg;
    }

    protected RuntimeException newProcessException(String schemaName, String fieldName, String msg) {
        return new IllegalArgumentException(formatError(schemaName, fieldName, msg));
    }

    protected RuntimeException newProcessException(Schema schema, Field field, String msg) {
        return newProcessException(schema.getName(), field.getName(), msg);
    }

    public void fail(Schema schema, Field field, String msg) {
        throw newProcessException(schema, field, msg);
    }

    protected void warn(String schemaName, String fieldName, String message) {
        String fullMsg = formatError(schemaName, fieldName, message);
        deployLogger.logApplicationPackage(Level.WARNING, fullMsg);
    }

    protected void warn(Schema schema, Field field, String message) {
        warn(schema.getName(), field.getName(), message);
    }

    protected void info(String schemaName, String fieldName, String message) {
        String fullMsg = formatError(schemaName, fieldName, message);
        deployLogger.logApplicationPackage(Level.INFO, fullMsg);
    }

    protected void info(Schema schema, Field field, String message) {
        info(schema.getName(), field.getName(), message);
    }

}