/*
 * Licensed to Elasticsearch under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch 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.elasticsearch.search.fetch.subphase;

import org.apache.lucene.index.NumericDocValues;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.lucene.uid.Versions;
import org.elasticsearch.index.mapper.VersionFieldMapper;
import org.elasticsearch.search.fetch.FetchSubPhase;
import org.elasticsearch.search.internal.SearchContext;

import java.io.IOException;

public final class VersionFetchSubPhase implements FetchSubPhase {

    @Override
    public void hitExecute(SearchContext context, HitContext hitContext) {
        if (context.version() == false ||
            (context.storedFieldsContext() != null && context.storedFieldsContext().fetchFields() == false)) {
            return;
        }
        long version = Versions.NOT_FOUND;
        try {
            NumericDocValues versions = hitContext.reader().getNumericDocValues(VersionFieldMapper.NAME);
            if (versions != null && versions.advanceExact(hitContext.docId())) {
                version = versions.longValue();
            }
        } catch (IOException e) {
            throw new ElasticsearchException("Could not retrieve version", e);
        }
        hitContext.hit().version(version < 0 ? -1 : version);
    }
}

@@ -867,73 +867,117 @@
 dex.
-NumericDocValues;%0Aimport org.elasticsearch.ElasticsearchException
+LeafReaderContext;%0Aimport org.apache.lucene.index.NumericDocValues;%0Aimport org.apache.lucene.index.ReaderUtil
 ;%0Aim
@@ -1085,16 +1085,59 @@
 Mapper;%0A
+import org.elasticsearch.search.SearchHit;%0A
 import o
@@ -1265,16 +1265,70 @@
 ception;
+%0Aimport java.util.Arrays;%0Aimport java.util.Comparator;
 %0A%0Apublic
@@ -1388,17 +1388,16 @@
 Phase %7B%0A
-%0A
     @Ove
@@ -1421,16 +1421,17 @@
 void hit
+s
 Execute(
@@ -1457,30 +1457,44 @@
 xt, 
-HitContext hitContext)
+SearchHit%5B%5D hits) throws IOException
  %7B%0A 
@@ -1675,24 +1675,25 @@
       %7D%0A
+%0A
         
 long ver
@@ -1688,85 +1688,519 @@
     
-long version = Versions.NOT_FOUND;%0A        try %7B%0A            NumericDocValues
+hits = hits.clone(); // don't modify the incoming hits%0A        Arrays.sort(hits, Comparator.comparingInt(SearchHit::docId));%0A%0A        int lastReaderId = -1;%0A        NumericDocValues versions = null;%0A        for (SearchHit hit : hits) %7B%0A            int readerId = ReaderUtil.subIndex(hit.docId(), context.searcher().getIndexReader().leaves());%0A            LeafReaderContext subReaderContext = context.searcher().getIndexReader().leaves().get(readerId);%0A            if (lastReaderId != readerId) %7B%0A               
  ver
@@ -2207,19 +2207,25 @@
 sions = 
-hit
+subReader
 Context.
@@ -2295,57 +2295,98 @@
     
-if (versions != null && versions.advanceExact(hit
+    lastReaderId = readerId;%0A            %7D%0A            int docId = hit.docId() - subReader
 Cont
@@ -2396,16 +2396,13 @@
 .doc
-Id())) %7B
+Base;
 %0A   
@@ -2402,35 +2402,36 @@
 se;%0A            
-   
+long
  version = versi
@@ -2429,17 +2429,17 @@
 n = 
-v
+V
 ersions.
 long
@@ -2438,19 +2438,17 @@
 ons.
-longValue()
+NOT_FOUND
 ;%0A  
@@ -2461,120 +2461,109 @@
     
-%7D%0A        %7D catch (IOException e) %7B%0A            throw new ElasticsearchException(%22Could not retrieve version%22, e
+if (versions != null && versions.advanceExact(docId)) %7B%0A                version = versions.longValue(
 );%0A 
@@ -2573,34 +2573,29 @@
     
+ 
-%7D%0A        hitContext.
+   %7D%0A            
 hit
-()
 .ver
@@ -2628,16 +2628,26 @@
 rsion);%0A
+        %7D%0A
     %7D%0A%7D%0A

Change VersionFetchSubPhase to create doc values iterator once per segment (#26809)