com.yahoo.schema.RankProfileRegistry 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;
import com.yahoo.schema.document.SDDocumentType;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Mapping from name to {@link RankProfile} as well as a reverse mapping of {@link RankProfile} to {@link Schema}.
* Having both of these mappings consolidated here make it easier to remove dependencies on these mappings at
* run time, since it is essentially only used when building rank profile config at deployment time.
*
* Global rank profiles are represented by the Search key null.
*
* @author Ulf Lilleengen
*/
public class RankProfileRegistry {
private final Map> rankProfiles = new LinkedHashMap<>();
private static final String globalRankProfilesKey = "[global]";
/* These rank profiles can be overridden: 'default' rank profile, as that is documented to work. And 'unranked'. */
static final Set overridableRankProfileNames = Set.of("default", "unranked");
public static RankProfileRegistry createRankProfileRegistryWithBuiltinRankProfiles(Schema schema) {
RankProfileRegistry rankProfileRegistry = new RankProfileRegistry();
rankProfileRegistry.add(new DefaultRankProfile(schema, rankProfileRegistry));
rankProfileRegistry.add(new UnrankedRankProfile(schema, rankProfileRegistry));
return rankProfileRegistry;
}
private String extractName(ImmutableSchema search) {
return search != null ? search.getName() : globalRankProfilesKey;
}
/** Adds a rank profile to this registry */
public void add(RankProfile rankProfile) {
String schemaName = extractName(rankProfile.schema());
if ( ! rankProfiles.containsKey(schemaName)) {
rankProfiles.put(schemaName, new LinkedHashMap<>());
}
checkForDuplicate(rankProfile);
rankProfiles.get(schemaName).put(rankProfile.name(), rankProfile);
}
private void checkForDuplicate(RankProfile rankProfile) {
String rankProfileName = rankProfile.name();
RankProfile existingRankProfileWithSameName = rankProfiles.get(extractName(rankProfile.schema())).get(rankProfileName);
if (existingRankProfileWithSameName == null) return;
if ( ! overridableRankProfileNames.contains(rankProfileName)) {
throw new IllegalArgumentException("Duplicate rank profile '" + rankProfileName + "' in " +
rankProfile.schema());
}
}
/**
* Returns a named rank profile, null if the search definition doesn't have one with the given name
*
* @param schema the {@link Schema} that owns the rank profile
* @param name the name of the rank profile
* @return the RankProfile to return.
*/
public RankProfile get(String schema, String name) {
Map profiles = rankProfiles.get(schema);
if (profiles == null) return null;
return profiles.get(name);
}
public RankProfile get(ImmutableSchema schema, String name) {
var profile = get(schema.getName(), name);
if (profile != null) return profile;
if (schema.inherited().isPresent()) return get(schema.inherited().get(), name);
return null;
}
public RankProfile getGlobal(String name) {
Map profiles = rankProfiles.get(globalRankProfilesKey);
if (profiles == null) return null;
return profiles.get(name);
}
public RankProfile resolve(SDDocumentType docType, String name) {
RankProfile rankProfile = get(docType.getName(), name);
if (rankProfile != null) return rankProfile;
for (var parent : docType.getInheritedTypes()) {
RankProfile parentProfile = resolve(parent, name);
if (parentProfile != null) return parentProfile;
}
return get(globalRankProfilesKey, name);
}
/**
* Rank profiles that are collected across clusters.
*
* @return a set of global {@link RankProfile} instances
*/
public Collection all() {
List all = new ArrayList<>();
for (var entry : rankProfiles.values()) {
all.addAll(entry.values());
}
return all;
}
/**
* Retrieve all rank profiles for a schema
*
* @param schema the schema to fetch rank profiles for, or null for the global ones
* @return a collection of {@link RankProfile} instances
*/
public Collection rankProfilesOf(ImmutableSchema schema) {
String key = schema == null ? globalRankProfilesKey : schema.getName();
if ( ! rankProfiles.containsKey(key)) return List.of();
var profiles = new LinkedHashMap<>(rankProfiles.get(key));
// Add all profiles in inherited schemas, unless they are already present (overridden)
while (schema != null && schema.inherited().isPresent()) {
schema = schema.inherited().get();
var inheritedProfiles = rankProfiles.get(schema.getName());
if (inheritedProfiles != null) {
for (Map.Entry inheritedProfile : inheritedProfiles.entrySet()) {
profiles.putIfAbsent(inheritedProfile.getKey(), inheritedProfile.getValue());
}
}
}
return profiles.values();
}
}