diff --git a/.idea/runConfigurations/Debug_OpenSearch.xml b/.idea/runConfigurations/Debug_OpenSearch.xml
index 0d8bf59823acf..2e167812615e1 100644
--- a/.idea/runConfigurations/Debug_OpenSearch.xml
+++ b/.idea/runConfigurations/Debug_OpenSearch.xml
@@ -8,4 +8,4 @@
-
+
\ No newline at end of file
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e43865ad12b31..385b89f7417e2 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -26,6 +26,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
- Extend Approximation Framework to other numeric types ([#18530](https://github.com/opensearch-project/OpenSearch/issues/18530))
- Add Semantic Version field type mapper and extensive unit tests([#18454](https://github.com/opensearch-project/OpenSearch/pull/18454))
- Pass index settings to system ingest processor factories. ([#18708](https://github.com/opensearch-project/OpenSearch/pull/18708))
+- Add fetch phase profiling. ([#18664](https://github.com/opensearch-project/OpenSearch/pull/18664))
- Include named queries from rescore contexts in matched_queries array ([#18697](https://github.com/opensearch-project/OpenSearch/pull/18697))
- Add the configurable limit on rule cardinality ([#18663](https://github.com/opensearch-project/OpenSearch/pull/18663))
- [Experimental] Start in "clusterless" mode if a clusterless ClusterPlugin is loaded ([#18479](https://github.com/opensearch-project/OpenSearch/pull/18479))
diff --git a/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/130_script_fields_profile.yml b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/130_script_fields_profile.yml
new file mode 100644
index 0000000000000..beaf597dd768c
--- /dev/null
+++ b/modules/lang-painless/src/yamlRestTest/resources/rest-api-spec/test/painless/130_script_fields_profile.yml
@@ -0,0 +1,69 @@
+setup:
+ - do:
+ indices.create:
+ index: test_fetch_profile
+ body:
+ settings:
+ number_of_replicas: 0
+ number_of_shards: 1
+ mappings:
+ properties:
+ text_field:
+ type: text
+ fields:
+ keyword:
+ type: keyword
+ numeric_field:
+ type: integer
+ date_field:
+ type: date
+ object_field:
+ type: nested
+ properties:
+ nested_field:
+ type: keyword
+ stored_field:
+ type: keyword
+ store: true
+
+ - do:
+ bulk:
+ refresh: true
+ index: test_fetch_profile
+ body: |
+ { "index": {} }
+ { "text_field": "Hello world", "numeric_field": 42, "date_field": "2023-01-01", "object_field": { "nested_field": "nested value" }, "stored_field": "stored value" }
+ { "index": {} }
+ { "text_field": "Another document", "numeric_field": 100, "date_field": "2023-02-01", "object_field": { "nested_field": "another nested" }, "stored_field": "another stored" }
+ { "index": {} }
+ { "text_field": "Third document with more text", "numeric_field": 200, "date_field": "2023-03-01", "object_field": { "nested_field": "third nested" }, "stored_field": "third stored" }
+
+
+---
+"Script fields phase profiling":
+ - skip:
+ features: "contains"
+
+ - do:
+ search:
+ index: test_fetch_profile
+ body:
+ profile: true
+ query:
+ match_all: {}
+ script_fields:
+ my_field:
+ script:
+ lang: painless
+ source: "doc['numeric_field'].value * 2"
+
+ - contains:
+ profile.shards.0.fetch.0.children:
+ type: "ScriptFieldsPhase"
+ description: "ScriptFieldsPhase"
+ - length: { profile.shards.0.fetch.0.children: 1 }
+
+ - is_true: profile.shards.0.fetch.0.children.0.breakdown.process
+ - match: { profile.shards.0.fetch.0.children.0.breakdown.process_count: 3 }
+ - is_true: profile.shards.0.fetch.0.children.0.breakdown.set_next_reader
+ - match: { profile.shards.0.fetch.0.children.0.breakdown.set_next_reader_count: 1 }
diff --git a/qa/multi-cluster-search/src/test/java/org/opensearch/search/CCSDuelIT.java b/qa/multi-cluster-search/src/test/java/org/opensearch/search/CCSDuelIT.java
index d3460c616f454..a81062a584277 100644
--- a/qa/multi-cluster-search/src/test/java/org/opensearch/search/CCSDuelIT.java
+++ b/qa/multi-cluster-search/src/test/java/org/opensearch/search/CCSDuelIT.java
@@ -831,10 +831,12 @@ private static Map responseToMap(SearchResponse response) throws
Map responseMap = org.opensearch.common.xcontent.XContentHelper.convertToMap(bytesReference, false, MediaTypeRegistry.JSON).v2();
assertNotNull(responseMap.put("took", -1));
responseMap.remove("num_reduce_phases");
- Map profile = (Map)responseMap.get("profile");
+ Map profile = (Map) responseMap.get("profile");
if (profile != null) {
- List