in oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/IMetricsQueryDAO.java [99:227]
MetricsValues readMetricsValues(MetricsCondition condition,
String valueColumnName,
Duration duration) throws IOException;
List<MetricsValues> readLabeledMetricsValues(MetricsCondition condition,
String valueColumnName,
List<KeyValue> labels,
Duration duration) throws IOException;
/**
* Read metrics values without entity. Used for get the labels' metadata.
*/
List<MetricsValues> readLabeledMetricsValuesWithoutEntity(String metricName,
String valueColumnName,
List<KeyValue> labels,
Duration duration) throws IOException;
HeatMap readHeatMap(MetricsCondition condition, String valueColumnName, Duration duration) throws IOException;
class Util {
/**
* Make sure the order is same as the expected order, add defaultValue if absent.
*/
public static IntValues sortValues(IntValues origin, List<String> expectedOrder, int defaultValue) {
IntValues intValues = new IntValues();
expectedOrder.forEach(id -> {
intValues.addKVInt(origin.findValue(id, defaultValue));
});
return intValues;
}
/**
* Make sure the order is same as the expected order, add defaultValue if absent.
*/
public static List<MetricsValues> sortValues(List<MetricsValues> origin,
List<String> expectedOrder,
int defaultValue) {
for (int i = 0; i < origin.size(); i++) {
final MetricsValues metricsValues = origin.get(i);
metricsValues.setValues(sortValues(metricsValues.getValues(), expectedOrder, defaultValue));
}
return origin;
}
/**
* Compose the multiple metric result based on conditions.
*/
public static List<MetricsValues> composeLabelValue(final String metricName,
final List<KeyValue> queryLabels,
final List<String> ids,
final Map<String, DataTable> idMap) {
final Optional<ValueColumnMetadata.ValueColumn> valueColumn
= ValueColumnMetadata.INSTANCE.readValueColumnDefinition(metricName);
if (valueColumn.isEmpty()) {
return Collections.emptyList();
}
//compatible with old version query
if (valueColumn.get().isMultiIntValues()) {
List<String> labelValues = buildLabelIndex(queryLabels, Const.COMMA).values()
.stream()
.flatMap(List::stream)
.collect(Collectors.toList());
return composeLabelValueForMultiIntValues(metricName, labelValues, ids, idMap);
}
return composeLabelValueForMultipleLabels(metricName, queryLabels, ids, idMap);
}
public static List<String> composeLabelConditions(final List<KeyValue> queryLabels,
final Collection<DataTable> metricValues) {
LinkedHashMap<String, List<String>> queryLabelIndex = buildLabelIndex(queryLabels, Const.COMMA);
List<String> labelConditions = new ArrayList<>();
if (queryLabelIndex.isEmpty()) {
labelConditions = metricValues.stream()
.flatMap(dataTable -> dataTable.keys().stream())
.distinct()
.filter(k -> k.startsWith(Const.LEFT_BRACE))
.collect(Collectors.toList());
} else {
List<Set<String>> keySets = new ArrayList<>();
for (Map.Entry<String, List<String>> queryLabel : queryLabelIndex.entrySet()) {
Set<String> keySet = new HashSet<>();
metricValues.forEach(dataTable -> {
var metricLabelIndex = dataTable.buildLabelIndex();
for (String labelValue : queryLabel.getValue()) {
//union labels
keySet.addAll(metricLabelIndex.getOrDefault(
queryLabel.getKey() + Const.EQUAL + labelValue,
new HashSet<>()
));
}
});
if (!keySet.isEmpty()) {
keySets.add(keySet);
}
}
//intersection labels
keySets.stream().reduce((a, b) -> {
a.retainAll(b);
return a;
}).ifPresent(labelConditions::addAll);
}
return labelConditions;
}
private static List<MetricsValues> composeLabelValueForMultiIntValues(final String metricName,
final List<String> labels,
final List<String> ids,
final Map<String, DataTable> idMap) {
List<String> allLabels;
if (Objects.isNull(labels) || labels.isEmpty() || labels.stream().allMatch(Strings::isNullOrEmpty)) {
allLabels = idMap.values().stream()
.flatMap(dataTable -> dataTable.keys().stream())
.distinct().filter(k -> !k.startsWith(Const.LEFT_BRACE)).collect(Collectors.toList());
} else {
allLabels = labels;
}
return buildMetricsValues(metricName, ids, idMap, allLabels);
}
private static List<MetricsValues> composeLabelValueForMultipleLabels(final String metricName,
final List<KeyValue> queryLabels,
final List<String> ids,
final Map<String, DataTable> idMap) {
List<String> labelConditions = composeLabelConditions(queryLabels, idMap.values());
return buildMetricsValues(metricName, ids, idMap, labelConditions);
}
}