You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by ds...@apache.org on 2021/04/21 17:55:22 UTC

[solr] branch main updated: SOLR-15356: Remove UninvertDocValuesMergePolicyFactory(#83)

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

dsmiley pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git


The following commit(s) were added to refs/heads/main by this push:
     new 8ad07a2  SOLR-15356: Remove UninvertDocValuesMergePolicyFactory(#83)
8ad07a2 is described below

commit 8ad07a28fbf6f1cd3a7f952619db77650045f3df
Author: David Smiley <ds...@apache.org>
AuthorDate: Wed Apr 21 13:55:08 2021 -0400

    SOLR-15356: Remove UninvertDocValuesMergePolicyFactory(#83)
    
     (and TestHalfAndHalfDocValues)
    
    Co-authored-by: Christine Poerschke <cp...@apache.org>
---
 solr/CHANGES.txt                                   |   3 +
 .../index/UninvertDocValuesMergePolicyFactory.java | 214 ------------------
 ...rconfig-uninvertdocvaluesmergepolicyfactory.xml |  38 ----
 .../index/UninvertDocValuesMergePolicyTest.java    | 242 ---------------------
 .../solr/schema/TestHalfAndHalfDocValues.java      | 131 -----------
 .../src/indexconfig-in-solrconfig.adoc             |   3 +-
 .../src/major-changes-in-solr-9.adoc               |   4 +
 7 files changed, 9 insertions(+), 626 deletions(-)

diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 094eaeb..04c2373 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -268,6 +268,9 @@ Other Changes
 
 * SOLR-15356: "mergeindexes" should not use UninvertingReader (FieldCache). (David Smiley)
 
+* SOLR-15356: UninvertDocValuesMergePolicy was removed because it's incompatible with Lucene 9.
+  (David Smiley, Christine Poerschke)
+
 Bug Fixes
 ---------------------
 * SOLR-14546: Fix for a relatively hard to hit issue in OverseerTaskProcessor that could lead to out of order execution
diff --git a/solr/core/src/java/org/apache/solr/index/UninvertDocValuesMergePolicyFactory.java b/solr/core/src/java/org/apache/solr/index/UninvertDocValuesMergePolicyFactory.java
deleted file mode 100644
index 65394cc..0000000
--- a/solr/core/src/java/org/apache/solr/index/UninvertDocValuesMergePolicyFactory.java
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * 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.solr.index;
-
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.lucene.codecs.DocValuesProducer;
-import org.apache.lucene.index.BinaryDocValues;
-import org.apache.lucene.index.CodecReader;
-import org.apache.lucene.index.DocValuesType;
-import org.apache.lucene.index.FieldInfo;
-import org.apache.lucene.index.FieldInfos;
-import org.apache.lucene.index.FilterCodecReader;
-import org.apache.lucene.index.IndexOptions;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.MergePolicy;
-import org.apache.lucene.index.NumericDocValues;
-import org.apache.lucene.index.OneMergeWrappingMergePolicy;
-import org.apache.lucene.index.SegmentCommitInfo;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.lucene.index.SortedNumericDocValues;
-import org.apache.lucene.index.SortedSetDocValues;
-import org.apache.solr.core.SolrResourceLoader;
-import org.apache.solr.schema.IndexSchema;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.uninverting.UninvertingReader;
-
-/**
- * A merge policy that can detect schema changes and  write docvalues into merging segments when a field has docvalues enabled
- * Using UninvertingReader.
- * 
- * This merge policy will delegate to the wrapped merge policy for selecting merge segments
- * 
- */
-public class UninvertDocValuesMergePolicyFactory extends WrapperMergePolicyFactory {
-  
-  final private boolean skipIntegrityCheck;
-
-  /**
-   * Whether or not the wrapped docValues producer should check consistency 
-   */
-  public boolean getSkipIntegrityCheck() {
-    return skipIntegrityCheck;
-  }
-
-  public UninvertDocValuesMergePolicyFactory(SolrResourceLoader resourceLoader, MergePolicyFactoryArgs args, IndexSchema schema) {
-    super(resourceLoader, args, schema);
-    final Boolean sic = (Boolean)args.remove("skipIntegrityCheck");
-    if (sic != null) {
-      this.skipIntegrityCheck = sic.booleanValue();
-    } else {
-      this.skipIntegrityCheck = false;
-    }
-    if (!args.keys().isEmpty()) {
-      throw new IllegalArgumentException("Arguments were "+args+" but "+getClass().getSimpleName()+" takes no arguments.");
-    }
-  }
-
-  @Override
-  protected MergePolicy getMergePolicyInstance(MergePolicy wrappedMP) {
-    return new OneMergeWrappingMergePolicy(wrappedMP, (merge) -> new UninvertDocValuesOneMerge(merge.segments));
-  }
-  
-  private UninvertingReader.Type getUninversionType(FieldInfo fi) {
-    SchemaField sf = schema.getFieldOrNull(fi.name);
-    
-    if (null != sf &&
-        sf.hasDocValues() &&
-        fi.getDocValuesType() == DocValuesType.NONE &&
-        fi.getIndexOptions() != IndexOptions.NONE) {
-      return sf.getType().getUninversionType(sf);
-    } else {
-      return null;
-    }
-  }
-    
-  private class UninvertDocValuesOneMerge extends MergePolicy.OneMerge {
-
-    public UninvertDocValuesOneMerge(List<SegmentCommitInfo> segments) {
-      super(segments);
-    }
-    
-    @Override
-    public CodecReader wrapForMerge(CodecReader reader) throws IOException {
-      // Wrap the reader with an uninverting reader if any of the fields have no docvalues but the 
-      // Schema says there should be
-      
-      
-      Map<String,UninvertingReader.Type> uninversionMap = null;
-      
-      for(FieldInfo fi: reader.getFieldInfos()) {
-        final UninvertingReader.Type type = getUninversionType(fi);
-        if (type != null) {
-          if (uninversionMap == null) {
-            uninversionMap = new HashMap<>();
-          }
-          uninversionMap.put(fi.name, type);
-        }
-        
-      }
-      
-      if(uninversionMap == null) {
-        return reader; // Default to normal reader if nothing to uninvert
-      } else {
-        return new UninvertingFilterCodecReader(reader, uninversionMap);
-      }
-      
-    }
-    
-  }
-  
-  
-  /**
-   * Delegates to an Uninverting for fields with docvalues
-   * 
-   * This is going to blow up FieldCache, look into an alternative implementation that uninverts without
-   * fieldcache
-   */
-  private class UninvertingFilterCodecReader extends FilterCodecReader {
-
-    private final LeafReader uninvertingReader;
-    private final DocValuesProducer docValuesProducer;
-
-    public UninvertingFilterCodecReader(CodecReader in, Map<String,UninvertingReader.Type> uninversionMap) {
-      super(in);
-
-      this.uninvertingReader = UninvertingReader.wrap(in, uninversionMap::get);
-      this.docValuesProducer = new DocValuesProducer() {
-
-        @Override
-        public NumericDocValues getNumeric(FieldInfo field) throws IOException {
-          return uninvertingReader.getNumericDocValues(field.name);
-        }
-
-        @Override
-        public BinaryDocValues getBinary(FieldInfo field) throws IOException {
-          return uninvertingReader.getBinaryDocValues(field.name);
-        }
-
-        @Override
-        public SortedDocValues getSorted(FieldInfo field) throws IOException {
-          return uninvertingReader.getSortedDocValues(field.name);
-        }
-
-        @Override
-        public SortedNumericDocValues getSortedNumeric(FieldInfo field) throws IOException {
-          return uninvertingReader.getSortedNumericDocValues(field.name);
-        }
-
-        @Override
-        public SortedSetDocValues getSortedSet(FieldInfo field) throws IOException {
-          return uninvertingReader.getSortedSetDocValues(field.name);
-        }
-
-        @Override
-        public void checkIntegrity() throws IOException {
-          if (!skipIntegrityCheck) {
-            uninvertingReader.checkIntegrity();
-          }
-        }
-
-        @Override
-        public void close() throws IOException {
-        }
-      };
-    }
-    
-    @Override
-    protected void doClose() throws IOException {
-      docValuesProducer.close();
-      uninvertingReader.close();
-      super.doClose();
-    }
-
-    @Override
-    public DocValuesProducer getDocValuesReader() {
-      return docValuesProducer;
-    }
-    
-    @Override
-    public FieldInfos getFieldInfos() {
-      return uninvertingReader.getFieldInfos();
-    }
-
-    @Override
-    public CacheHelper getCoreCacheHelper() {
-      return in.getCoreCacheHelper();
-    }
-
-    @Override
-    public CacheHelper getReaderCacheHelper() {
-      return in.getReaderCacheHelper();
-    }
-    
-  }
-
-}
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-uninvertdocvaluesmergepolicyfactory.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-uninvertdocvaluesmergepolicyfactory.xml
deleted file mode 100644
index 5f15430..0000000
--- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-uninvertdocvaluesmergepolicyfactory.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" ?>
-
-<!--
- 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.
--->
-
-<config>
-  <luceneMatchVersion>${tests.luceneMatchVersion:LATEST}</luceneMatchVersion>
-  <directoryFactory name="DirectoryFactory" class="${solr.directoryFactory:solr.RAMDirectoryFactory}"/>
-  <schemaFactory class="ClassicIndexSchemaFactory"/>
-
-  <indexConfig>
-    <useCompoundFile>${useCompoundFile:false}</useCompoundFile>
-    <mergePolicyFactory class="org.apache.solr.index.UninvertDocValuesMergePolicyFactory">
-      <str name="wrapped.prefix">inner</str>
-      <str name="inner.class">org.apache.solr.index.DefaultMergePolicyFactory</str>
-      <bool name="skipIntegrityCheck">${solr.tests.skipIntegrityCheck:false}</bool>
-    </mergePolicyFactory>
-     
-    <mergeScheduler class="org.apache.lucene.index.ConcurrentMergeScheduler"/>
-  </indexConfig>
-
-  <requestHandler name="/select" class="solr.SearchHandler"></requestHandler>
-
-</config>
diff --git a/solr/core/src/test/org/apache/solr/index/UninvertDocValuesMergePolicyTest.java b/solr/core/src/test/org/apache/solr/index/UninvertDocValuesMergePolicyTest.java
deleted file mode 100644
index d13034c..0000000
--- a/solr/core/src/test/org/apache/solr/index/UninvertDocValuesMergePolicyTest.java
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * 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.solr.index;
-
-import java.util.Random;
-import java.util.function.IntUnaryOperator;
-
-import org.apache.lucene.document.Document;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.DocValuesType;
-import org.apache.lucene.index.FieldInfos;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.lucene.index.SortedDocValues;
-import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.schema.IndexSchema;
-import org.apache.solr.schema.SchemaField;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.util.RefCounted;
-import org.apache.solr.util.TestHarness;
-import org.junit.After;
-import org.junit.AfterClass;
-import org.junit.Before;
-import org.junit.BeforeClass;
-
-public class UninvertDocValuesMergePolicyTest extends SolrTestCaseJ4 {
-
-  private static String SOLR_TESTS_SKIP_INTEGRITY_CHECK = "solr.tests.skipIntegrityCheck";
-  private static String ID_FIELD = "id";
-  private static String TEST_FIELD = "string_add_dv_later";
-
-  @BeforeClass
-  public static void beforeTests() throws Exception {
-    System.setProperty(SOLR_TESTS_SKIP_INTEGRITY_CHECK, (random().nextBoolean() ? "true" : "false"));
-  }
-
-  @AfterClass
-  public static void afterTests() {
-    System.clearProperty(SOLR_TESTS_SKIP_INTEGRITY_CHECK);
-  }
-
-  @After
-  public void after() throws Exception {
-    deleteCore();
-  }
-  
-  @Before
-  public void before() throws Exception {
-    initCore("solrconfig-uninvertdocvaluesmergepolicyfactory.xml", "schema-docValues.xml");
-  }
-
-  public void testIndexAndAddDocValues() throws Exception {
-    Random rand = random();
-    
-    for(int i=0; i < 100; i++) {
-      assertU(adoc(ID_FIELD, String.valueOf(i), TEST_FIELD, String.valueOf(i)));
-      
-      if(rand.nextBoolean()) {
-        assertU(commit());
-      }
-    }
-    
-    assertU(commit());
-    
-    // Assert everything has been indexed and there are no docvalues
-    withNewRawReader(h, topReader -> {
-      assertEquals(100, topReader.numDocs());
-
-      final FieldInfos infos = FieldInfos.getMergedFieldInfos(topReader);
-
-      // The global field type should not have docValues yet
-      assertEquals(DocValuesType.NONE, infos.fieldInfo(TEST_FIELD).getDocValuesType());
-    });
-    
-    
-    addDocValuesTo(h, TEST_FIELD);
-    
-    
-    // Add some more documents with doc values turned on including updating some
-    for(int i=90; i < 110; i++) {
-      assertU(adoc(ID_FIELD, String.valueOf(i), TEST_FIELD, String.valueOf(i)));
-      
-      if(rand.nextBoolean()) {
-        assertU(commit());
-      }
-    }
-    
-    assertU(commit());
-    
-    withNewRawReader(h, topReader -> {
-      assertEquals(110, topReader.numDocs());
-
-      final FieldInfos infos = FieldInfos.getMergedFieldInfos(topReader);
-      // The global field type should have docValues because a document with dvs was added
-      assertEquals(DocValuesType.SORTED, infos.fieldInfo(TEST_FIELD).getDocValuesType());
-    });
-    
-    int optimizeSegments = 1;
-    assertU(optimize("maxSegments", String.valueOf(optimizeSegments)));
-    
-    
-    // Assert all docs have the right docvalues
-    withNewRawReader(h, topReader -> {
-      // Assert merged into one segment 
-      assertEquals(110, topReader.numDocs());
-      assertEquals(optimizeSegments, topReader.leaves().size());
-      
-
-      final FieldInfos infos = FieldInfos.getMergedFieldInfos(topReader);
-      // The global field type should have docValues because a document with dvs was added
-      assertEquals(DocValuesType.SORTED, infos.fieldInfo(TEST_FIELD).getDocValuesType());
-      
-      
-      // Check that all segments have the right docvalues type with the correct value
-      // Also check that other fields (e.g. the id field) didn't mistakenly get docvalues added
-      for (LeafReaderContext ctx : topReader.leaves()) {
-        LeafReader r = ctx.reader();
-        SortedDocValues docvalues = r.getSortedDocValues(TEST_FIELD);
-        for(int i = 0; i < r.numDocs(); ++i) {
-          Document doc = r.document(i);
-          String v = doc.getField(TEST_FIELD).stringValue();
-          String id = doc.getField(ID_FIELD).stringValue();
-          assertEquals(DocValuesType.SORTED, r.getFieldInfos().fieldInfo(TEST_FIELD).getDocValuesType());
-          assertEquals(DocValuesType.NONE, r.getFieldInfos().fieldInfo(ID_FIELD).getDocValuesType());
-          assertEquals(v, id);
-          
-          docvalues.nextDoc();
-          assertEquals(v, docvalues.lookupOrd(docvalues.ordValue()).utf8ToString());
-        }
-      }
-    });
-  }
-  
-  
-  // When an non-indexed field gets merged, it exhibit the old behavior
-  // The field will be merged, docvalues headers updated, but no docvalues for this field
-  public void testNonIndexedFieldDoesNonFail() throws Exception {
-    // Remove Indexed from fieldType
-    removeIndexFrom(h, TEST_FIELD);
-    
-    assertU(adoc(ID_FIELD, String.valueOf(1), TEST_FIELD, String.valueOf(1)));
-    assertU(commit());
-    
-    addDocValuesTo(h, TEST_FIELD);
-    
-    assertU(adoc(ID_FIELD, String.valueOf(2), TEST_FIELD, String.valueOf(2)));
-    assertU(commit());
-    
-    assertU(optimize("maxSegments", "1"));
-    
-    withNewRawReader(h, topReader -> {
-      // Assert merged into one segment 
-      assertEquals(2, topReader.numDocs());
-      assertEquals(1, topReader.leaves().size());
-      
-
-      final FieldInfos infos = FieldInfos.getMergedFieldInfos(topReader);
-      // The global field type should have docValues because a document with dvs was added
-      assertEquals(DocValuesType.SORTED, infos.fieldInfo(TEST_FIELD).getDocValuesType());
-      
-      for (LeafReaderContext ctx : topReader.leaves()) {
-        LeafReader r = ctx.reader();
-        SortedDocValues docvalues = r.getSortedDocValues(TEST_FIELD);
-        for(int i = 0; i < r.numDocs(); ++i) {
-          Document doc = r.document(i);
-          String v = doc.getField(TEST_FIELD).stringValue();
-          String id = doc.getField(ID_FIELD).stringValue();
-          assertEquals(DocValuesType.SORTED, r.getFieldInfos().fieldInfo(TEST_FIELD).getDocValuesType());
-          assertEquals(DocValuesType.NONE, r.getFieldInfos().fieldInfo(ID_FIELD).getDocValuesType());
-          
-         
-          if(id.equals("2")) {
-            assertTrue(docvalues.advanceExact(i));
-            assertEquals(v, docvalues.lookupOrd(docvalues.ordValue()).utf8ToString());
-          } else {
-            assertFalse(docvalues.advanceExact(i));
-          }
-          
-        }
-      }  
-    });
-  }
-
-  
-  private static void addDocValuesTo(TestHarness h, String fieldName) {
-    implUpdateSchemaField(h, fieldName, (p) -> (p | 0x00008000)); // FieldProperties.DOC_VALUES
-  }
-
-  private static void removeIndexFrom(TestHarness h, String fieldName) {
-    implUpdateSchemaField(h, fieldName, (p) -> (p ^ 0x00000001)); // FieldProperties.INDEXED
-  }
-
-  private static void implUpdateSchemaField(TestHarness h, String fieldName, IntUnaryOperator propertiesModifier) {
-    try (SolrCore core = h.getCoreInc()) {
-
-      // Add docvalues to the field type
-      IndexSchema schema = core.getLatestSchema();
-      SchemaField oldSchemaField = schema.getField(fieldName);
-      SchemaField newSchemaField = new SchemaField(
-          fieldName,
-          oldSchemaField.getType(),
-          propertiesModifier.applyAsInt(oldSchemaField.getProperties()),
-          oldSchemaField.getDefaultValue());
-      schema.getFields().put(fieldName, newSchemaField);
-    }
-  }
-  
-  private interface DirectoryReaderConsumer {
-    public void accept(DirectoryReader consumer) throws Exception;
-  }
-
-  private static void withNewRawReader(TestHarness h, DirectoryReaderConsumer consumer) {
-    try (SolrCore core = h.getCoreInc()) {
-      final RefCounted<SolrIndexSearcher> searcherRef = core.openNewSearcher(true, true);
-      final SolrIndexSearcher searcher = searcherRef.get();
-      try {
-        try {
-          consumer.accept(searcher.getRawReader());
-        } catch (Exception e) {
-          fail(e.toString());
-        }
-      } finally {
-        searcherRef.decref();
-      }
-    }
-  }
-}
diff --git a/solr/core/src/test/org/apache/solr/schema/TestHalfAndHalfDocValues.java b/solr/core/src/test/org/apache/solr/schema/TestHalfAndHalfDocValues.java
deleted file mode 100644
index ad1836c..0000000
--- a/solr/core/src/test/org/apache/solr/schema/TestHalfAndHalfDocValues.java
+++ /dev/null
@@ -1,131 +0,0 @@
-/*
- * 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.solr.schema;
-
-import org.apache.lucene.document.Document;
-import org.apache.lucene.index.DirectoryReader;
-import org.apache.lucene.index.DocValuesType;
-import org.apache.lucene.index.FieldInfos;
-import org.apache.lucene.index.LeafReader;
-import org.apache.lucene.index.LeafReaderContext;
-import org.apache.solr.SolrTestCaseJ4;
-import org.apache.solr.core.SolrCore;
-import org.apache.solr.index.NoMergePolicyFactory;
-import org.apache.solr.search.SolrIndexSearcher;
-import org.apache.solr.util.RefCounted;
-import org.junit.BeforeClass;
-
-/**
- * Added in SOLR-10047
- */
-public class TestHalfAndHalfDocValues extends SolrTestCaseJ4 {
-
-  @BeforeClass
-  public static void beforeTests() throws Exception {
-    // we need consistent segments that aren't merged because we want to have
-    // segments with and without docvalues
-    systemSetPropertySolrTestsMergePolicyFactory(NoMergePolicyFactory.class.getName());
-
-    initCore("solrconfig-basic.xml", "schema-docValues.xml");
-
-    // sanity check our schema meets our expectations
-    final IndexSchema schema = h.getCore().getLatestSchema();
-    for (String f : new String[]{"floatdv", "intdv", "doubledv", "longdv", "datedv", "stringdv", "booldv"}) {
-      final SchemaField sf = schema.getField(f);
-      assertFalse(f + " is multiValued, test is useless, who changed the schema?",
-          sf.multiValued());
-      assertFalse(f + " is indexed, test is useless, who changed the schema?",
-          sf.indexed());
-      assertTrue(f + " has no docValues, test is useless, who changed the schema?",
-          sf.hasDocValues());
-    }
-  }
-
-  public void setUp() throws Exception {
-    super.setUp();
-    assertU(delQ("*:*"));
-  }
-
-  public void testHalfAndHalfDocValues() throws Exception {
-    // Insert two docs without docvalues
-    String fieldname = "string_add_dv_later";
-    assertU(adoc("id", "3", fieldname, "c"));
-    assertU(commit());
-    assertU(adoc("id", "1", fieldname, "a"));
-    assertU(commit());
-
-
-    try (SolrCore core = h.getCoreInc()) {
-      assertFalse(core.getLatestSchema().getField(fieldname).hasDocValues());
-      // Add docvalues to the field type
-      IndexSchema schema = core.getLatestSchema();
-      SchemaField oldField = schema.getField(fieldname);
-      int newProperties = oldField.getProperties() | SchemaField.DOC_VALUES;
-
-      SchemaField sf = new SchemaField(fieldname, oldField.getType(), newProperties, null);
-      schema.getFields().put(fieldname, sf);
-
-      // Insert a new doc with docvalues
-      assertU(adoc("id", "2", fieldname, "b"));
-      assertU(commit());
-
-
-      // Check there are a mix of segments with and without docvalues
-      final RefCounted<SolrIndexSearcher> searcherRef = core.openNewSearcher(true, true);
-      final SolrIndexSearcher searcher = searcherRef.get();
-      try {
-        final DirectoryReader topReader = searcher.getRawReader();
-
-        //Assert no merges
-
-        assertEquals(3, topReader.numDocs());
-        assertEquals(3, topReader.leaves().size());
-
-        final FieldInfos infos = FieldInfos.getMergedFieldInfos(topReader);
-        //The global field type should have docValues because a document with dvs was added
-        assertEquals(DocValuesType.SORTED, infos.fieldInfo(fieldname).getDocValuesType());
-
-        for (LeafReaderContext ctx : topReader.leaves()) {
-          LeafReader r = ctx.reader();
-          //Make sure there were no merges
-          assertEquals(1, r.numDocs());
-          Document doc = r.document(0);
-          String id = doc.getField("id").stringValue();
-
-          if (id.equals("1") || id.equals("3")) {
-            assertEquals(DocValuesType.NONE, r.getFieldInfos().fieldInfo(fieldname).getDocValuesType());
-          } else {
-            assertEquals(DocValuesType.SORTED, r.getFieldInfos().fieldInfo(fieldname).getDocValuesType());
-          }
-
-        }
-      } finally {
-        searcherRef.decref();
-      }
-    }
-
-    // Assert sort order is correct
-    assertQ(req("q", "string_add_dv_later:*", "sort", "string_add_dv_later asc"),
-        "//*[@numFound='3']",
-        "//result/doc[1]/str[@name='id'][.=1]",
-        "//result/doc[2]/str[@name='id'][.=2]",
-        "//result/doc[3]/str[@name='id'][.=3]"
-    );
-  }
-
-}
diff --git a/solr/solr-ref-guide/src/indexconfig-in-solrconfig.adoc b/solr/solr-ref-guide/src/indexconfig-in-solrconfig.adoc
index 490273a..5d0f798 100644
--- a/solr/solr-ref-guide/src/indexconfig-in-solrconfig.adoc
+++ b/solr/solr-ref-guide/src/indexconfig-in-solrconfig.adoc
@@ -75,7 +75,8 @@ Defines how merging segments is done.
 
 The default in Solr is to use a `TieredMergePolicy`, which merges segments of approximately equal size, subject to an allowed number of segments per tier.
 
-Other policies available are the `LogByteSizeMergePolicy`, `LogDocMergePolicy`, and `UninvertDocValuesMergePolicy`. For more information on these policies, please see {lucene-javadocs}/core/org/apache/lucene/index/MergePolicy.html[the MergePolicy javadocs].
+Other policies available are the `LogByteSizeMergePolicy` and `LogDocMergePolicy`.
+For more information on these policies, please see {lucene-javadocs}/core/org/apache/lucene/index/MergePolicy.html[the MergePolicy javadocs].
 
 [source,xml]
 ----
diff --git a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
index 36f4bf6..85c0b05 100644
--- a/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
+++ b/solr/solr-ref-guide/src/major-changes-in-solr-9.adoc
@@ -175,6 +175,10 @@ SolrCloud doesn't support that but may sometime.
 
 === Reindexing After Upgrades in Solr 9
 
+In Solr 8, it's possible to add docValues to a schema without re-indexing via UninvertDocValuesMergePolicy, an advanced/expert utility.
+Due to changes in Lucene 9, that isn't possible any more; the component was removed.
+If re-indexing is too onerous, use this mechanism in Solr 8.
+
 == New Features & Enhancements in Solr 9
 
 == Configuration and Default Parameter Changes in Solr 9