You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@skywalking.apache.org by wu...@apache.org on 2020/04/21 13:26:00 UTC

[skywalking] 01/01: Add data type to the column definition to replace the simple isValue definition. And top N query is also requiring value column now.

This is an automated email from the ASF dual-hosted git repository.

wusheng pushed a commit to branch metrics-type
in repository https://gitbox.apache.org/repos/asf/skywalking.git

commit 481e1ef761dccfb8f3034e892d547bb70054a028
Author: Wu Sheng <wu...@foxmail.com>
AuthorDate: Tue Apr 21 21:25:06 2020 +0800

    Add data type to the column definition to replace the simple isValue definition. And top N query is also requiring value column now.
---
 .../skywalking/oap/server/core/CoreModule.java     |  2 +
 .../oap/server/core/CoreModuleProvider.java        |  2 +
 .../oap/server/core/analysis/topn/TopN.java        |  2 +-
 .../core/query/MetricsMetadataQueryService.java    | 51 ++++++++++++++++++++++
 .../server/core/query/TopNRecordsQueryService.java |  4 +-
 .../oap/server/core/storage/annotation/Column.java | 51 +++++++++++++++++++---
 .../storage/annotation/ValueColumnMetadata.java    | 18 ++++++--
 .../server/core/storage/model/StorageModels.java   |  6 +--
 .../core/storage/query/ITopNRecordsQueryDAO.java   |  4 +-
 .../oap/query/graphql/resolver/MetricsQuery.java   | 18 ++++++--
 .../elasticsearch/query/TopNRecordsQueryEsDAO.java |  5 ++-
 .../plugin/influxdb/query/TopNRecordsQuery.java    |  3 +-
 .../plugin/jdbc/h2/dao/H2TopNRecordsQueryDAO.java  |  5 ++-
 .../tool/profile/core/MockCoreModuleProvider.java  |  2 +
 14 files changed, 149 insertions(+), 24 deletions(-)

diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
index 82450bb..13c1cad 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModule.java
@@ -32,6 +32,7 @@ import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
 import org.apache.skywalking.oap.server.core.query.LogQueryService;
 import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
+import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
 import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.TopNRecordsQueryService;
@@ -90,6 +91,7 @@ public class CoreModule extends ModuleDefine {
 
     private void addQueryService(List<Class> classes) {
         classes.add(TopologyQueryService.class);
+        classes.add(MetricsMetadataQueryService.class);
         classes.add(MetricsQueryService.class);
         classes.add(TraceQueryService.class);
         classes.add(LogQueryService.class);
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
index 03a1be7..cf81132 100755
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/CoreModuleProvider.java
@@ -48,6 +48,7 @@ import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
 import org.apache.skywalking.oap.server.core.query.LogQueryService;
 import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
+import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
 import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.TopNRecordsQueryService;
@@ -213,6 +214,7 @@ public class CoreModuleProvider extends ModuleProvider {
             NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
 
         this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager()));
+        this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
         this.registerServiceImplementation(MetricsQueryService.class, new MetricsQueryService(getManager()));
         this.registerServiceImplementation(TraceQueryService.class, new TraceQueryService(getManager()));
         this.registerServiceImplementation(LogQueryService.class, new LogQueryService(getManager()));
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/topn/TopN.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/topn/TopN.java
index 8f97078..4ec3763 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/topn/TopN.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/analysis/topn/TopN.java
@@ -39,7 +39,7 @@ public abstract class TopN extends Record implements ComparableStorageData {
     private String statement;
     @Getter
     @Setter
-    @Column(columnName = LATENCY)
+    @Column(columnName = LATENCY, dataType = Column.ValueDataType.SAMPLED_RECORD)
     private long latency;
     @Getter
     @Setter
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsMetadataQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsMetadataQueryService.java
new file mode 100644
index 0000000..93483a1
--- /dev/null
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/MetricsMetadataQueryService.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package org.apache.skywalking.oap.server.core.query;
+
+import java.util.Optional;
+import org.apache.skywalking.oap.server.core.query.enumeration.MetricsType;
+import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
+import org.apache.skywalking.oap.server.library.module.Service;
+
+/**
+ * MetricsMetadataQueryService provides the metadata of metrics to other modules.
+ */
+public class MetricsMetadataQueryService implements Service {
+    public MetricsType typeOfMetrics(String metricsName) {
+        final Optional<ValueColumnMetadata.ValueColumn> valueColumn
+            = ValueColumnMetadata.INSTANCE.readValueColumnDefinition(metricsName);
+        if (valueColumn.isPresent()) {
+            switch (valueColumn.get().getDataType()) {
+                case COMMON_VALUE:
+                    return MetricsType.REGULAR_VALUE;
+                case LABELED_VALUE:
+                    return MetricsType.LABELED_VALUE;
+                case HISTOGRAM:
+                    return MetricsType.HEATMAP;
+                case SAMPLED_RECORD:
+                    return MetricsType.SAMPLED_RECORD;
+                case NOT_VALUE:
+                default:
+                    return MetricsType.UNKNOWN;
+            }
+        } else {
+            return MetricsType.UNKNOWN;
+        }
+    }
+}
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopNRecordsQueryService.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopNRecordsQueryService.java
index 1e8e4c8..31c55d5 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopNRecordsQueryService.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/query/TopNRecordsQueryService.java
@@ -24,6 +24,7 @@ import org.apache.skywalking.oap.server.core.query.input.Duration;
 import org.apache.skywalking.oap.server.core.query.input.TopNCondition;
 import org.apache.skywalking.oap.server.core.query.type.SelectedRecord;
 import org.apache.skywalking.oap.server.core.storage.StorageModule;
+import org.apache.skywalking.oap.server.core.storage.annotation.ValueColumnMetadata;
 import org.apache.skywalking.oap.server.core.storage.query.ITopNRecordsQueryDAO;
 import org.apache.skywalking.oap.server.library.module.ModuleManager;
 import org.apache.skywalking.oap.server.library.module.Service;
@@ -46,6 +47,7 @@ public class TopNRecordsQueryService implements Service {
     }
 
     public List<SelectedRecord> readSampledRecords(TopNCondition condition, Duration duration) throws IOException {
-        return getTopNRecordsQueryDAO().readSampledRecords(condition, duration);
+        return getTopNRecordsQueryDAO().readSampledRecords(
+            condition, ValueColumnMetadata.INSTANCE.getValueCName(condition.getName()), duration);
     }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
index 6a8ddb5..ce0b433 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/Column.java
@@ -22,6 +22,7 @@ import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
+import lombok.Getter;
 import org.apache.skywalking.oap.server.core.query.sql.Function;
 import org.apache.skywalking.oap.server.core.storage.model.IModelOverride;
 
@@ -38,17 +39,12 @@ public @interface Column {
     String columnName();
 
     /**
-     * The column value is used in metrics value query.
-     */
-    boolean isValue() default false;
-
-    /**
      * The function is used in aggregation query.
      */
     Function function() default Function.None;
 
     /**
-     * The default value of this column, when its {@link #isValue()} == true.
+     * The default value of this column, when its {@link #dataType()} != {@link ValueDataType#NOT_VALUE}.
      */
     int defaultValue() default 0;
 
@@ -68,4 +64,47 @@ public @interface Column {
      * @since 7.1.0
      */
     int length() default 200;
+
+    /**
+     * @return the data type of this value column. The value column is the query related value Set {@link
+     * ValueDataType#NOT_VALUE} if this is not the value column, read {@link ValueDataType} for more details.
+     * @since 8.0.0
+     */
+    ValueDataType dataType() default ValueDataType.NOT_VALUE;
+
+    /**
+     * ValueDataType represents the data structure of value column. The persistent way of the value column determine the
+     * available ways to query the data.
+     */
+    enum ValueDataType {
+        /**
+         * NOT_VALUE represents this value wouldn't be queried directly through metrics v2 protocol. It could be never
+         * queried, or just through hard code to do so, uch as the lines of topology and service.
+         */
+        NOT_VALUE(false),
+        /**
+         * COMMON_VALUE represents a single value, usually int or long.
+         */
+        COMMON_VALUE(true),
+        /**
+         * LABELLED_VALUE represents this metrics have multiple values with different labels.
+         */
+        LABELED_VALUE(true),
+        /**
+         * HISTOGRAM represents the values are grouped by the buckets, usually suitable for heatmap query.
+         */
+        HISTOGRAM(true),
+        /**
+         * SAMPLED_RECORD represents the values are detail data, being persistent by following some sampled rules.
+         * Usually do topn query based on value column value ASC or DESC.
+         */
+        SAMPLED_RECORD(true);
+
+        @Getter
+        private boolean isValue = false;
+
+        ValueDataType(final boolean isValue) {
+            this.isValue = isValue;
+        }
+    }
 }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
index 968262f..76af49d 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/annotation/ValueColumnMetadata.java
@@ -20,6 +20,8 @@ package org.apache.skywalking.oap.server.core.storage.annotation;
 
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Optional;
+import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import org.apache.skywalking.oap.server.core.query.sql.Function;
 
@@ -35,8 +37,12 @@ public enum ValueColumnMetadata {
     /**
      * Register the new metadata for the given model name.
      */
-    public void putIfAbsent(String modelName, String valueCName, Function function, int defaultValue) {
-        mapping.putIfAbsent(modelName, new ValueColumn(valueCName, function, defaultValue));
+    public void putIfAbsent(String modelName,
+                            String valueCName,
+                            Column.ValueDataType dataType,
+                            Function function,
+                            int defaultValue) {
+        mapping.putIfAbsent(modelName, new ValueColumn(valueCName, dataType, function, defaultValue));
     }
 
     /**
@@ -57,6 +63,10 @@ public enum ValueColumnMetadata {
         return findColumn(metricsName).defaultValue;
     }
 
+    public Optional<ValueColumn> readValueColumnDefinition(String metricsName) {
+        return Optional.ofNullable(mapping.get(metricsName));
+    }
+
     private ValueColumn findColumn(String metricsName) {
         ValueColumn column = mapping.get(metricsName);
         if (column == null) {
@@ -65,9 +75,11 @@ public enum ValueColumnMetadata {
         return column;
     }
 
+    @Getter
     @RequiredArgsConstructor
-    class ValueColumn {
+    public class ValueColumn {
         private final String valueCName;
+        private final Column.ValueDataType dataType;
         private final Function function;
         private final int defaultValue;
     }
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
index 0a25e74..93e7d30 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/model/StorageModels.java
@@ -76,13 +76,13 @@ public class StorageModels implements IModelManager, INewModel, IModelOverride {
                 modelColumns.add(
                     new ModelColumn(
                         new ColumnName(modelName, column.columnName()), field.getType(), column.matchQuery(), column
-                        .storageOnly(), column.isValue(), column.length()));
+                        .storageOnly(), column.dataType().isValue(), column.length()));
                 if (log.isDebugEnabled()) {
                     log.debug("The field named {} with the {} type", column.columnName(), field.getType());
                 }
-                if (column.isValue()) {
+                if (column.dataType().isValue()) {
                     ValueColumnMetadata.INSTANCE.putIfAbsent(
-                        modelName, column.columnName(), column.function(), column.defaultValue());
+                        modelName, column.columnName(), column.dataType(), column.function(), column.defaultValue());
                 }
 
                 List<QueryUnifiedIndex> indexDefinitions = new ArrayList<>();
diff --git a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopNRecordsQueryDAO.java b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopNRecordsQueryDAO.java
index a818d5c..7805bb0 100644
--- a/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopNRecordsQueryDAO.java
+++ b/oap-server/server-core/src/main/java/org/apache/skywalking/oap/server/core/storage/query/ITopNRecordsQueryDAO.java
@@ -33,5 +33,7 @@ import org.apache.skywalking.oap.server.library.module.Service;
  * @since 8.0.0
  */
 public interface ITopNRecordsQueryDAO extends Service {
-    List<SelectedRecord> readSampledRecords(TopNCondition condition, Duration duration) throws IOException;
+    List<SelectedRecord> readSampledRecords(TopNCondition condition,
+                                            final String valueColumnName,
+                                            Duration duration) throws IOException;
 }
diff --git a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
index b450a3c..d9f091e 100644
--- a/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
+++ b/oap-server/server-query-plugin/query-graphql-plugin/src/main/java/org/apache/skywalking/oap/query/graphql/resolver/MetricsQuery.java
@@ -23,6 +23,7 @@ import java.io.IOException;
 import java.util.List;
 import org.apache.skywalking.oap.server.core.CoreModule;
 import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
+import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
 import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.TopNRecordsQueryService;
 import org.apache.skywalking.oap.server.core.query.enumeration.MetricsType;
@@ -44,11 +45,21 @@ public class MetricsQuery implements GraphQLQueryResolver {
     private MetricsQueryService metricsQueryService;
     private AggregationQueryService queryService;
     private TopNRecordsQueryService topNRecordsQueryService;
+    private MetricsMetadataQueryService metricsMetadataQueryService;
 
     public MetricsQuery(ModuleManager moduleManager) {
         this.moduleManager = moduleManager;
     }
 
+    private MetricsMetadataQueryService getMetricsMetadataQueryService() {
+        if (metricsMetadataQueryService == null) {
+            this.metricsMetadataQueryService = moduleManager.find(CoreModule.NAME)
+                                                            .provider()
+                                                            .getService(MetricsMetadataQueryService.class);
+        }
+        return metricsMetadataQueryService;
+    }
+
     private AggregationQueryService getQueryService() {
         if (queryService == null) {
             this.queryService = moduleManager.find(CoreModule.NAME)
@@ -80,7 +91,7 @@ public class MetricsQuery implements GraphQLQueryResolver {
      * Metrics definition metadata query. Response the metrics type which determines the suitable query methods.
      */
     public MetricsType typeOfMetrics(String name) throws IOException {
-        return MetricsType.UNKNOWN;
+        return getMetricsMetadataQueryService().typeOfMetrics(name);
     }
 
     /**
@@ -118,9 +129,8 @@ public class MetricsQuery implements GraphQLQueryResolver {
     /**
      * Heatmap is bucket based value statistic result.
      *
-     * @return heapmap including the latency distribution
-     * {@link HeatMap#getBuckets()}
-     * {@link HeatMap.HeatMapColumn#getValues()} follows this rule.
+     * @return heapmap including the latency distribution {@link HeatMap#getBuckets()} {@link
+     * HeatMap.HeatMapColumn#getValues()} follows this rule.
      * <pre>
      *      key = 0, represents [0, 100), value = count of requests in the latency range.
      *      key = 100, represents [100, 200), value = count of requests in the latency range.
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopNRecordsQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopNRecordsQueryEsDAO.java
index 7b324a7..f630a08 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopNRecordsQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/TopNRecordsQueryEsDAO.java
@@ -45,6 +45,7 @@ public class TopNRecordsQueryEsDAO extends EsDAO implements ITopNRecordsQueryDAO
 
     @Override
     public List<SelectedRecord> readSampledRecords(final TopNCondition condition,
+                                                   final String valueColumnName,
                                                    final Duration duration) throws IOException {
         SearchSourceBuilder sourceBuilder = SearchSourceBuilder.searchSource();
         BoolQueryBuilder boolQueryBuilder = QueryBuilders.boolQuery();
@@ -59,7 +60,7 @@ public class TopNRecordsQueryEsDAO extends EsDAO implements ITopNRecordsQueryDAO
 
         sourceBuilder.query(boolQueryBuilder);
         sourceBuilder.size(condition.getTopN())
-                     .sort(TopN.LATENCY, condition.getOrder().equals(Order.DES) ? SortOrder.DESC : SortOrder.ASC);
+                     .sort(valueColumnName, condition.getOrder().equals(Order.DES) ? SortOrder.DESC : SortOrder.ASC);
         SearchResponse response = getClient().search(condition.getName(), sourceBuilder);
 
         List<SelectedRecord> results = new ArrayList<>(condition.getTopN());
@@ -68,7 +69,7 @@ public class TopNRecordsQueryEsDAO extends EsDAO implements ITopNRecordsQueryDAO
             SelectedRecord record = new SelectedRecord();
             record.setName((String) searchHit.getSourceAsMap().get(TopN.STATEMENT));
             record.setRefId((String) searchHit.getSourceAsMap().get(TopN.TRACE_ID));
-            record.setValue(((Number) searchHit.getSourceAsMap().get(TopN.LATENCY)).toString());
+            record.setValue(((Number) searchHit.getSourceAsMap().get(valueColumnName)).toString());
             results.add(record);
         }
 
diff --git a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/TopNRecordsQuery.java b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/TopNRecordsQuery.java
index ba7a592..9608fd8 100644
--- a/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/TopNRecordsQuery.java
+++ b/oap-server/server-storage-plugin/storage-influxdb-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/influxdb/query/TopNRecordsQuery.java
@@ -52,6 +52,7 @@ public class TopNRecordsQuery implements ITopNRecordsQueryDAO {
 
     @Override
     public List<SelectedRecord> readSampledRecords(final TopNCondition condition,
+                                                   final String valueColumnName,
                                                    final Duration duration) throws IOException {
         String function = InfluxConstants.SORT_ASC;
         // Have to re-sort here. Because the function, top()/bottom(), get the result ordered by the `time`.
@@ -62,7 +63,7 @@ public class TopNRecordsQuery implements ITopNRecordsQueryDAO {
         }
 
         WhereQueryImpl query = select()
-            .function(function, TopN.LATENCY, condition.getTopN())
+            .function(function, valueColumnName, condition.getTopN())
             .column(TopN.STATEMENT)
             .column(TopN.TRACE_ID)
             .from(client.getDatabase(), condition.getName())
diff --git a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopNRecordsQueryDAO.java b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopNRecordsQueryDAO.java
index 2f9a22d..f1a9b8d 100644
--- a/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopNRecordsQueryDAO.java
+++ b/oap-server/server-storage-plugin/storage-jdbc-hikaricp-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/jdbc/h2/dao/H2TopNRecordsQueryDAO.java
@@ -43,6 +43,7 @@ public class H2TopNRecordsQueryDAO implements ITopNRecordsQueryDAO {
 
     @Override
     public List<SelectedRecord> readSampledRecords(final TopNCondition condition,
+                                                   final String valueColumnName,
                                                    final Duration duration) throws IOException {
         StringBuilder sql = new StringBuilder("select * from " + condition.getName() + " where ");
         List<Object> parameters = new ArrayList<>(10);
@@ -58,7 +59,7 @@ public class H2TopNRecordsQueryDAO implements ITopNRecordsQueryDAO {
         sql.append(" and ").append(TopN.TIME_BUCKET).append(" <= ?");
         parameters.add(duration.getEndTimeBucket());
 
-        sql.append(" order by ").append(TopN.LATENCY);
+        sql.append(" order by ").append(valueColumnName);
         if (condition.getOrder().equals(Order.DES)) {
             sql.append(" desc ");
         } else {
@@ -74,7 +75,7 @@ public class H2TopNRecordsQueryDAO implements ITopNRecordsQueryDAO {
                     SelectedRecord record = new SelectedRecord();
                     record.setName(resultSet.getString(TopN.STATEMENT));
                     record.setRefId(resultSet.getString(TopN.TRACE_ID));
-                    record.setValue(resultSet.getString(TopN.LATENCY));
+                    record.setValue(resultSet.getString(valueColumnName));
                     results.add(record);
                 }
             }
diff --git a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
index b48790f..8f32900 100755
--- a/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
+++ b/oap-server/server-tools/profile-exporter/tool-profile-snapshot-server-mock/src/main/java/org/apache/skywalking/oap/server/tool/profile/core/MockCoreModuleProvider.java
@@ -36,6 +36,7 @@ import org.apache.skywalking.oap.server.core.query.AggregationQueryService;
 import org.apache.skywalking.oap.server.core.query.AlarmQueryService;
 import org.apache.skywalking.oap.server.core.query.LogQueryService;
 import org.apache.skywalking.oap.server.core.query.MetadataQueryService;
+import org.apache.skywalking.oap.server.core.query.MetricsMetadataQueryService;
 import org.apache.skywalking.oap.server.core.query.MetricsQueryService;
 import org.apache.skywalking.oap.server.core.query.ProfileTaskQueryService;
 import org.apache.skywalking.oap.server.core.query.TopNRecordsQueryService;
@@ -132,6 +133,7 @@ public class MockCoreModuleProvider extends CoreModuleProvider {
             NetworkAddressAliasCache.class, new NetworkAddressAliasCache(moduleConfig));
 
         this.registerServiceImplementation(TopologyQueryService.class, new TopologyQueryService(getManager()));
+        this.registerServiceImplementation(MetricsMetadataQueryService.class, new MetricsMetadataQueryService());
         this.registerServiceImplementation(MetricsQueryService.class, new MetricsQueryService(getManager()));
         this.registerServiceImplementation(TraceQueryService.class, new TraceQueryService(getManager()));
         this.registerServiceImplementation(LogQueryService.class, new LogQueryService(getManager()));