com.yahoo.schema.processing.AdjustPositionSummaryFields Maven / Gradle / Ivy
// Copyright Vespa.ai. 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.ArrayDataType;
import com.yahoo.document.DataType;
import com.yahoo.document.PositionDataType;
import com.yahoo.schema.RankProfileRegistry;
import com.yahoo.schema.Schema;
import com.yahoo.schema.document.Attribute;
import com.yahoo.schema.document.GeoPos;
import com.yahoo.schema.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(Schema schema, DeployLogger deployLogger, RankProfileRegistry rankProfileRegistry, QueryProfiles queryProfiles) {
super(schema, deployLogger, rankProfileRegistry, queryProfiles);
}
private boolean useV8GeoPositions = false;
@Override
public void process(boolean validate, boolean documentsOnly, ModelContext.Properties properties) {
this.useV8GeoPositions = properties.featureFlags().useV8GeoPositions();
process(validate, documentsOnly);
}
@Override
public void process(boolean validate, boolean documentsOnly) {
for (DocumentSummary summary : schema.getSummaries().values()) {
scanSummary(summary);
}
}
static String getPositionSummaryFieldName(String fieldName) {
// Only used in v7 legacy mode, remove in Vespa 9
return fieldName + ".position";
}
static String getDistanceSummaryFieldName(String fieldName) {
// Only used in v7 legacy mode, remove in Vespa 9
return fieldName + ".distance";
}
private void scanSummary(DocumentSummary summary) {
for (SummaryField summaryField : summary.getSummaryFields().values()) {
if ( ! GeoPos.isAnyPos(summaryField.getDataType())) continue;
String originalSource = summaryField.getSingleSource();
if (originalSource.indexOf('.') == -1) { // Eliminate summary fields with pos.x or pos.y as source
ImmutableSDField sourceField = schema.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,
getPositionSummaryFieldName(summaryField.getName()),
DataType.getArray(DataType.STRING),
source,
SummaryTransform.POSITIONS);
ensureSummaryField(summary,
getDistanceSummaryFieldName(summaryField.getName()),
DataType.INT,
source,
SummaryTransform.DISTANCE);
}
private void ensureSummaryField(DocumentSummary summary, String fieldName, DataType dataType, Source source, SummaryTransform transform) {
SummaryField oldField = schema.getSummaryField(fieldName);
if (oldField == null) {
if (useV8GeoPositions) return;
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 + "'");
}
if (useV8GeoPositions) return;
summary.add(oldField);
}
private boolean hasPositionAttribute(String name) {
Attribute attribute = schema.getAttribute(name);
if (attribute == null) {
ImmutableSDField field = schema.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 DataType makeZCurveDataType(DataType dataType) {
return dataType instanceof ArrayDataType ? DataType.getArray(DataType.LONG) : DataType.LONG;
}
private void fail(SummaryField summaryField, String msg) {
throw newProcessException(schema.getName(), summaryField.getName(), msg);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy