Repository: apache/skywalking (language: python)

Issue:
[Bug] AggregationQueryEsDAO sortMetrics NullPointerException for instanceScalarApdex metrics when logical shard is disabled
### Search before asking

- [X] I had searched in the [issues](https://github.com/apache/skywalking/issues?q=is%3Aissue) and found no similar issues.


### Apache SkyWalking Component

OAP server (apache/skywalking)

### What happened

[armeria-eventloop-epoll-4-4] WARN  [] - Exception while fetching data (/instanceScalarApdex_1) : null
java.lang.NullPointerException: null
        at org.apache.skywalking.oap.server.storage.plugin.elasticsearch.query.AggregationQueryEsDAO.sortMetrics(AggregationQueryEsDAO.java:126) 

### What you expected to happen

No error.

### How to reproduce

Use a topN query for a Apdex metric.

### Anything else

_No response_

### Are you willing to submit PR?

- [X] Yes I am willing to submit a PR!

### Code of Conduct

- [X] I agree to follow this project's [Code of Conduct](https://www.apache.org/foundation/policies/conduct)



Discussion / hints:

Fix patch:
diff --git a/docs/en/changes/changes.md b/docs/en/changes/changes.md
index b0efc15fb24d..eb89f143dc09 100644
--- a/docs/en/changes/changes.md
+++ b/docs/en/changes/changes.md
@@ -133,6 +133,7 @@
 * Fix Elasticsearch storage: In `No-Sharding Mode`, add specific analyzer to the template before index creation to avoid update index error.
 * Internal API: remove undocumented ElasticSearch API usage and use documented one.
 * Fix `BanyanDB.ShardingKey` annotation missed in the generated OAL metrics classes.
+* Fix Elasticsearch storage: Query `sortMetrics` missing transform real index column name.
 
 #### UI
 
diff --git a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
index 9006ff5f6c3b..e99d6a64175d 100644
--- a/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
+++ b/oap-server/server-storage-plugin/storage-elasticsearch-plugin/src/main/java/org/apache/skywalking/oap/server/storage/plugin/elasticsearch/query/AggregationQueryEsDAO.java
@@ -54,6 +54,7 @@ public List<SelectedRecord> sortMetrics(final TopNCondition condition,
                                             final String valueColumnName,
                                             final Duration duration,
                                             final List<KeyValue> additionalConditions) {
+        final String realValueColumn = IndexController.LogicIndicesRegister.getPhysicalColumnName(condition.getName(), valueColumnName);
         final RangeQueryBuilder basicQuery = Query.range(Metrics.TIME_BUCKET)
                                                   .lte(duration.getEndTimeBucket())
                                                   .gte(duration.getStartTimeBucket());
@@ -102,9 +103,9 @@ public List<SelectedRecord> sortMetrics(final TopNCondition condition,
         search.aggregation(
             Aggregation.terms(Metrics.ENTITY_ID)
                        .field(Metrics.ENTITY_ID)
-                       .order(BucketOrder.aggregation(valueColumnName, asc))
+                       .order(BucketOrder.aggregation(realValueColumn, asc))
                        .size(condition.getTopN())
-                       .subAggregation(Aggregation.avg(valueColumnName).field(valueColumnName))
+                       .subAggregation(Aggregation.avg(realValueColumn).field(realValueColumn))
                        .executionHint(TermsAggregationBuilder.ExecutionHint.MAP)
                        .collectMode(TermsAggregationBuilder.CollectMode.BREADTH_FIRST)
                        .build());
@@ -122,7 +123,7 @@ public List<SelectedRecord> sortMetrics(final TopNCondition condition,
         for (Map<String, Object> termsBucket : buckets) {
             SelectedRecord record = new SelectedRecord();
             record.setId((String) termsBucket.get("key"));
-            Map<String, Object> value = (Map<String, Object>) termsBucket.get(valueColumnName);
+            Map<String, Object> value = (Map<String, Object>) termsBucket.get(realValueColumn);
             record.setValue(String.valueOf(((Number) value.get("value")).longValue()));
             topNList.add(record);
         }


Test patch:
diff --git a/test/e2e-v2/cases/storage/expected/metrics-top-service-sla.yml b/test/e2e-v2/cases/storage/expected/metrics-top-service.yml
similarity index 100%
rename from test/e2e-v2/cases/storage/expected/metrics-top-service-sla.yml
rename to test/e2e-v2/cases/storage/expected/metrics-top-service.yml
diff --git a/test/e2e-v2/cases/storage/storage-cases.yaml b/test/e2e-v2/cases/storage/storage-cases.yaml
index 0dcd9f381165..520fbe42f2b0 100644
--- a/test/e2e-v2/cases/storage/storage-cases.yaml
+++ b/test/e2e-v2/cases/storage/storage-cases.yaml
@@ -57,8 +57,10 @@ cases:
       )
     expected: expected/trace-users-detail.yml
   # service metrics
+  - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics sorted --name service_apdex 5
+    expected: expected/metrics-top-service.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics top --name service_sla 5
-    expected: expected/metrics-top-service-sla.yml
+    expected: expected/metrics-top-service.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_sla --service-name=e2e-service-provider |yq e 'to_entries' -
     expected: expected/metrics-has-value.yml
   - query: swctl --display yaml --base-url=http://${oap_host}:${oap_12800}/graphql metrics linear --name=service_cpm --service-name=e2e-service-provider |yq e 'to_entries' -