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
|
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
package com.yahoo.search.query.profile;
import com.yahoo.processing.request.CompoundName;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfile;
import com.yahoo.search.query.profile.compiled.CompiledQueryProfileRegistry;
import com.yahoo.search.query.profile.compiled.DimensionalMap;
import com.yahoo.search.query.profile.types.QueryProfileType;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Compile a set of query profiles into compiled profiles.
*
* @author bratseth
*/
public class QueryProfileCompiler {
private static final Logger log = Logger.getLogger(QueryProfileCompiler.class.getName());
public static CompiledQueryProfileRegistry compile(QueryProfileRegistry input) {
CompiledQueryProfileRegistry output = new CompiledQueryProfileRegistry(input.getTypeRegistry());
for (QueryProfile inputProfile : input.allComponents()) {
output.register(compile(inputProfile, output));
}
return output;
}
public static CompiledQueryProfile compile(QueryProfile in, CompiledQueryProfileRegistry registry) {
DimensionalMap.Builder<CompoundName, Object> values = new DimensionalMap.Builder<>();
DimensionalMap.Builder<CompoundName, QueryProfileType> types = new DimensionalMap.Builder<>();
DimensionalMap.Builder<CompoundName, Object> references = new DimensionalMap.Builder<>();
DimensionalMap.Builder<CompoundName, Object> unoverridables = new DimensionalMap.Builder<>();
// Resolve values for each existing variant and combine into a single data structure
Set<DimensionBindingForPath> variants = new HashSet<>();
collectVariants(CompoundName.empty, in, DimensionBinding.nullBinding, variants);
variants.add(new DimensionBindingForPath(DimensionBinding.nullBinding, CompoundName.empty)); // if this contains no variants
if (log.isLoggable(Level.FINE))
log.fine("Compiling " + in.toString() + " having " + variants.size() + " variants");
int i = 0;
for (DimensionBindingForPath variant : variants) {
if (log.isLoggable(Level.FINER))
log.finer(" Compiling variant " + i++ + ": " + variant);
for (Map.Entry<String, Object> entry : in.listValues(variant.path(), variant.binding().getContext(), null).entrySet())
values.put(variant.path().append(entry.getKey()), variant.binding(), entry.getValue());
for (Map.Entry<CompoundName, QueryProfileType> entry : in.listTypes(variant.path(), variant.binding().getContext()).entrySet())
types.put(variant.path().append(entry.getKey()), variant.binding(), entry.getValue());
for (CompoundName reference : in.listReferences(variant.path(), variant.binding().getContext()))
references.put(variant.path().append(reference), variant.binding(), Boolean.TRUE); // Used as a set; value is ignored
for (CompoundName name : in.listUnoverridable(variant.path(), variant.binding().getContext()))
unoverridables.put(variant.path().append(name), variant.binding(), Boolean.TRUE); // Used as a set; value is ignored
}
return new CompiledQueryProfile(in.getId(), in.getType(),
values.build(), types.build(), references.build(), unoverridables.build(),
registry);
}
/**
* Returns all the unique combinations of dimension values which have values set reachable from this profile.
*
* @param profile the profile we are collecting the variants of
* @param currentVariant the variant we must have to arrive at this point in the query profile graph
* @param allVariants the set of all variants accumulated so far
*/
private static void collectVariants(CompoundName path, QueryProfile profile, DimensionBinding currentVariant, Set<DimensionBindingForPath> allVariants) {
for (QueryProfile inheritedProfile : profile.inherited())
collectVariants(path, inheritedProfile, currentVariant, allVariants);
collectVariantsFromValues(path, profile.getContent(), currentVariant, allVariants);
collectVariantsInThis(path, profile, currentVariant, allVariants);
if (profile instanceof BackedOverridableQueryProfile)
collectVariantsInThis(path, ((BackedOverridableQueryProfile) profile).getBacking(), currentVariant, allVariants);
}
private static void collectVariantsInThis(CompoundName path, QueryProfile profile, DimensionBinding currentVariant, Set<DimensionBindingForPath> allVariants) {
QueryProfileVariants profileVariants = profile.getVariants();
if (profileVariants != null) {
for (QueryProfileVariant variant : profile.getVariants().getVariants()) {
DimensionBinding combinedVariant =
DimensionBinding.createFrom(profile.getDimensions(), variant.getDimensionValues()).combineWith(currentVariant);
if (combinedVariant.isInvalid()) continue; // values at this point in the graph are unreachable
collectVariantsFromValues(path, variant.values(), combinedVariant, allVariants);
for (QueryProfile variantInheritedProfile : variant.inherited())
collectVariants(path, variantInheritedProfile, combinedVariant, allVariants);
}
}
}
private static void collectVariantsFromValues(CompoundName path, Map<String, Object> values, DimensionBinding currentVariant, Set<DimensionBindingForPath> allVariants) {
if ( ! values.isEmpty())
allVariants.add(new DimensionBindingForPath(currentVariant, path)); // there are actual values for this variant
for (Map.Entry<String, Object> entry : values.entrySet()) {
if (entry.getValue() instanceof QueryProfile)
collectVariants(path.append(entry.getKey()), (QueryProfile)entry.getValue(), currentVariant, allVariants);
}
}
private static class DimensionBindingForPath {
private final DimensionBinding binding;
private final CompoundName path;
public DimensionBindingForPath(DimensionBinding binding, CompoundName path) {
this.binding = binding;
this.path = path;
}
public DimensionBinding binding() { return binding; }
public CompoundName path() { return path; }
@Override
public boolean equals(Object o) {
if ( o == this ) return true;
if ( ! (o instanceof DimensionBindingForPath)) return false;
DimensionBindingForPath other = (DimensionBindingForPath)o;
return other.binding.equals(this.binding) && other.path.equals(this.path);
}
@Override
public int hashCode() {
return binding.hashCode() + 17*path.hashCode();
}
@Override
public String toString() {
return binding + " for path " + path;
}
}
}
|