summaryrefslogtreecommitdiffstats
path: root/config-model/src/main/java/com/yahoo/searchdefinition/processing/AdjustPositionSummaryFields.java
blob: e8c958f9609d352f61c8c734ba8a24402ef31f8c (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
// Copyright 2018 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.searchdefinition.processing;

import com.yahoo.config.application.api.DeployLogger;
import com.yahoo.document.ArrayDataType;
import com.yahoo.document.DataType;
import com.yahoo.document.PositionDataType;
import com.yahoo.searchdefinition.RankProfileRegistry;
import com.yahoo.searchdefinition.Search;
import com.yahoo.searchdefinition.document.Attribute;
import com.yahoo.searchdefinition.document.ImmutableSDField;
import com.yahoo.vespa.documentmodel.DocumentSummary;
import com.yahoo.vespa.documentmodel.SummaryField;
import com.yahoo.vespa.documentmodel.SummaryField.Source;
import com.yahoo.vespa.documentmodel.SummaryTransform;
import com.yahoo.vespa.model.container.search.QueryProfiles;

/*
 * Adjusts position summary fields by adding derived summary fields (.distance and .position) and setting summary
 * transform and source.
 */
public class AdjustPositionSummaryFields extends Processor {

    public AdjustPositionSummaryFields(Search search, DeployLogger deployLogger, RankProfileRegistry rankProfileRegistry, QueryProfiles queryProfiles) {
        super(search, deployLogger, rankProfileRegistry, queryProfiles);
    }

    @Override
    public void process(boolean validate, boolean documentsOnly) {
        for (DocumentSummary summary : search.getSummaries().values()) {
            scanSummary(summary);
        }
    }

    private void scanSummary(DocumentSummary summary) {
        for (SummaryField summaryField : summary.getSummaryFields()) {
            if (isPositionDataType(summaryField.getDataType())) {
                String originalSource = summaryField.getSingleSource();
                if (originalSource.indexOf('.') == -1) { // Eliminate summary fields with pos.x or pos.y as source
                    ImmutableSDField sourceField = search.getField(originalSource);
                    if (sourceField != null) {
                        String zCurve = null;
                        if (sourceField.getDataType().equals(summaryField.getDataType())) {
                            zCurve = PositionDataType.getZCurveFieldName(originalSource);
                        } else if (sourceField.getDataType().equals(makeZCurveDataType(summaryField.getDataType())) &&
                            hasZCurveSuffix(originalSource)) {
                            zCurve = originalSource;
                        }
                        if (zCurve != null) {
                            if (hasPositionAttribute(zCurve)) {
                                Source source = new Source(zCurve);
                                adjustPositionField(summary, summaryField, source);
                            } else if (sourceField.isImportedField() || !summaryField.getName().equals(originalSource)) {
                                fail(summaryField, "No position attribute '" + zCurve + "'");
                            }
                        }
                    }
                }
            }
        }
    }

    private void adjustPositionField(DocumentSummary summary, SummaryField summaryField, Source source) {
        summaryField.setTransform(SummaryTransform.GEOPOS);
        summaryField.getSources().clear();
        summaryField.addSource(source);
        ensureSummaryField(summary,
                           PositionDataType.getPositionSummaryFieldName(summaryField.getName()),
                           DataType.getArray(DataType.STRING),
                           source,
                           SummaryTransform.POSITIONS);
        ensureSummaryField(summary,
                           PositionDataType.getDistanceSummaryFieldName(summaryField.getName()),
                           DataType.INT,
                           source,
                           SummaryTransform.DISTANCE);
    }

    private void ensureSummaryField(DocumentSummary summary, String fieldName, DataType dataType, Source source, SummaryTransform transform) {
        SummaryField oldField = search.getSummaryField(fieldName);
        if (oldField == null) {
            SummaryField newField = new SummaryField(fieldName, dataType, transform);
            newField.addSource(source);
            summary.add(newField);
            return;
        }
        if (!oldField.getDataType().equals(dataType)) {
            fail(oldField, "exists with type '" + oldField.getDataType().toString() + "', should be of type '" + dataType.toString() + "'");
        }
        if (oldField.getTransform() != transform) {
            fail(oldField, "has summary transform '" + oldField.getTransform().toString() + "', should have transform '" + transform.toString() + "'");
        }
        if (oldField.getSourceCount() != 1 || !oldField.getSingleSource().equals(source.getName())) {
            fail(oldField, "has source '" + oldField.getSources().toString() + "', should have source '" + source + "'");
        }
        summary.add(oldField);
    }

    private boolean hasPositionAttribute(String name) {
        Attribute attribute = search.getAttribute(name);
        if (attribute == null) {
            ImmutableSDField field = search.getField(name);
            if (field != null && field.isImportedField()) {
                attribute = field.getAttribute();
            }
        }
        return attribute != null && attribute.isPosition();
    }

    private static boolean hasZCurveSuffix(String name) {
        String suffix = PositionDataType.getZCurveFieldName("");
        return name.length() > suffix.length() && name.substring(name.length() - suffix.length()).equals(suffix);
    }

    private static boolean isPositionDataType(DataType dataType) {
        return dataType.equals(PositionDataType.INSTANCE) || dataType.equals(DataType.getArray(PositionDataType.INSTANCE));
    }

    private static DataType makeZCurveDataType(DataType dataType) {
        return dataType instanceof ArrayDataType ? DataType.getArray(DataType.LONG) : DataType.LONG;
    }

    private void fail(SummaryField summaryField, String msg) {
        throw newProcessException(search.getName(), summaryField.getName(), msg);
    }

}