You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by jp...@apache.org on 2024/09/10 21:08:30 UTC

(lucene) branch main updated: Convert more classes to record classes (#13328)

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

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


The following commit(s) were added to refs/heads/main by this push:
     new 942065cc3e7 Convert more classes to record classes (#13328)
942065cc3e7 is described below

commit 942065cc3e7e3941167ab1ffacbada225d612d79
Author: Shubham Chaudhary <36...@users.noreply.github.com>
AuthorDate: Wed Sep 11 02:38:24 2024 +0530

    Convert more classes to record classes (#13328)
---
 lucene/CHANGES.txt                                 |   2 +
 lucene/MIGRATE.md                                  |   1 +
 .../analysis/hunspell/CheckCompoundPattern.java    |   6 +-
 .../analysis/hunspell/GeneratingSuggester.java     |  41 ++----
 .../apache/lucene/analysis/hunspell/Hunspell.java  |   8 +-
 .../org/apache/lucene/analysis/hunspell/Root.java  |  25 +---
 .../analysis/pattern/PatternTypingFilter.java      |  30 +---
 .../analysis/synonym/SynonymGraphFilter.java       |  20 +--
 .../analysis/synonym/word2vec/TermAndBoost.java    |  20 ++-
 .../synonym/word2vec/Word2VecSynonymFilter.java    |   2 +-
 .../word2vec/TestWord2VecSynonymProvider.java      |   6 +-
 .../analysis/ja/JapaneseCompletionFilter.java      |  14 +-
 .../analysis/ja/completion/KatakanaRomanizer.java  |  10 +-
 .../org/apache/lucene/analysis/ko/Viterbi.java     |  14 +-
 .../lucene/analysis/ko/dict/KoMorphData.java       |  10 +-
 .../ko/dict/TokenInfoDictionaryEntryWriter.java    |   8 +-
 .../tokenattributes/PartOfSpeechAttributeImpl.java |   6 +-
 .../analysis/ko/dict/TestTokenInfoDictionary.java  |  12 +-
 .../analysis/ko/dict/TestUserDictionary.java       |   8 +-
 .../lucene/backward_codecs/lucene50/ForUtil.java   |  13 +-
 .../backward_codecs/lucene60/bkd/BKDWriter60.java  |  22 +--
 .../TestIndexSortBackwardsCompatibility.java       |   4 +-
 .../lucene/classification/BM25NBClassifier.java    |   8 +-
 .../BooleanPerceptronClassifier.java               |   2 +-
 .../CachingNaiveBayesClassifier.java               |   4 +-
 .../classification/ClassificationResult.java       |  39 +-----
 .../classification/KNearestFuzzyClassifier.java    |   6 +-
 .../classification/KNearestNeighborClassifier.java |   6 +-
 .../classification/SimpleNaiveBayesClassifier.java |  12 +-
 .../SimpleNaiveBayesDocumentClassifier.java        |   4 +-
 .../utils/ConfusionMatrixGenerator.java            |   2 +-
 .../classification/utils/DatasetSplitter.java      |   6 +-
 .../classification/ClassificationTestBase.java     |  17 ++-
 .../TestKNearestNeighborClassifier.java            |   6 +-
 .../document/DocumentClassificationTestBase.java   |   8 +-
 .../lucene/codecs/blockterms/BlockTermsWriter.java |  29 ++--
 .../blockterms/VariableGapTermsIndexWriter.java    |   2 +-
 .../codecs/blocktreeords/FSTOrdsOutputs.java       |  35 +----
 .../blocktreeords/OrdsBlockTreeTermsWriter.java    |  59 +++-----
 .../codecs/blocktreeords/OrdsFieldReader.java      |   3 +-
 .../blocktreeords/OrdsIntersectTermsEnumFrame.java |   4 +-
 .../codecs/blocktreeords/OrdsSegmentTermsEnum.java |  22 +--
 .../codecs/simpletext/SimpleTextBKDWriter.java     |  20 +--
 .../simpletext/SimpleTextLiveDocsFormat.java       |   9 +-
 .../sharedterms/FieldMetadataTermState.java        |  11 +-
 .../uniformsplit/sharedterms/STBlockLine.java      |  14 +-
 .../sharedterms/TestSTBlockReader.java             |  10 +-
 .../lucene/analysis/AutomatonToTokenStream.java    |  20 +--
 .../java/org/apache/lucene/codecs/TermStats.java   |  20 +--
 .../codecs/lucene90/Lucene90CompoundFormat.java    |  10 +-
 .../Lucene90CompressingTermVectorsReader.java      |  12 +-
 .../codecs/perfield/PerFieldKnnVectorsFormat.java  |   9 +-
 .../apache/lucene/document/NearestNeighbor.java    |  36 ++---
 .../document/SortedNumericDocValuesRangeQuery.java |   2 +-
 .../document/SortedSetDocValuesRangeQuery.java     |   2 +-
 .../java/org/apache/lucene/index/BitsSlice.java    |   4 +-
 .../apache/lucene/index/BufferedUpdatesStream.java |  18 +--
 .../java/org/apache/lucene/index/CheckIndex.java   |  11 +-
 .../java/org/apache/lucene/index/IndexWriter.java  |  23 ++-
 .../java/org/apache/lucene/index/LeafMetaData.java |  70 +++------
 .../org/apache/lucene/index/LogMergePolicy.java    |  10 +-
 .../lucene/index/MappingMultiPostingsEnum.java     |   2 +-
 .../java/org/apache/lucene/index/MergeState.java   |   2 +-
 .../org/apache/lucene/index/MultiPostingsEnum.java |   4 +-
 .../java/org/apache/lucene/index/MultiSorter.java  |   4 +-
 .../org/apache/lucene/index/MultiTermsEnum.java    |   2 +-
 .../apache/lucene/index/ParallelLeafReader.java    |  10 +-
 .../java/org/apache/lucene/index/ReaderSlice.java  |  26 +---
 .../org/apache/lucene/index/SegmentMerger.java     |   2 +-
 .../index/SlowCompositeCodecReaderWrapper.java     |  29 ++--
 .../src/java/org/apache/lucene/index/Sorter.java   |   4 +-
 .../apache/lucene/index/SortingCodecReader.java    |  19 +--
 .../apache/lucene/search/CollectionStatistics.java | 129 ++++-------------
 .../IndexSortSortedNumericDocValuesRangeQuery.java |   4 +-
 .../apache/lucene/search/MaxScoreAccumulator.java  |  15 +-
 .../java/org/apache/lucene/search/Scorable.java    |  23 +--
 .../org/apache/lucene/search/SynonymQuery.java     |  23 +--
 .../org/apache/lucene/search/TermStatistics.java   |  88 +++---------
 .../apache/lucene/search/TopFieldCollector.java    |   8 +-
 .../apache/lucene/search/TopScoreDocCollector.java |   2 +-
 .../search/comparators/TermOrdValComparator.java   |  10 +-
 .../java/org/apache/lucene/util/QueryBuilder.java  |  20 ++-
 .../apache/lucene/util/bkd/BKDRadixSelector.java   |  17 +--
 .../java/org/apache/lucene/util/bkd/BKDWriter.java |  18 +--
 .../src/java/org/apache/lucene/util/fst/Util.java  |  18 +--
 .../org/apache/lucene/util/packed/PackedInts.java  |  15 +-
 .../apache/lucene/util/packed/PagedMutable.java    |   2 +-
 .../lucene/util/quantization/ScalarQuantizer.java  |  16 +--
 .../apache/lucene/index/TestDocumentWriter.java    |  18 +--
 .../org/apache/lucene/index/TestIndexSorting.java  |   2 +-
 .../lucene/index/TestIndexWriterExceptions.java    |  10 +-
 .../lucene/index/TestSortingCodecReader.java       |   2 +-
 .../org/apache/lucene/index/TestTermsEnum.java     |  10 +-
 .../internal/vectorization/TestVectorScorer.java   |  12 +-
 .../search/TestBooleanQueryVisitSubscorers.java    |   6 +-
 .../apache/lucene/search/TestCollectorManager.java |   7 +-
 .../lucene/search/TestConstantScoreQuery.java      |   2 +-
 .../org/apache/lucene/search/TestFuzzyQuery.java   |  14 +-
 .../lucene/search/TestMaxScoreAccumulator.java     |  34 ++---
 .../org/apache/lucene/search/TestScorerPerf.java   |   2 +-
 .../apache/lucene/search/TestTopDocsCollector.java |  18 +--
 .../lucene/search/TestTopFieldCollector.java       |  18 +--
 .../org/apache/lucene/util/BaseSortTestCase.java   |  10 +-
 .../test/org/apache/lucene/util/TestArrayUtil.java |   8 +-
 .../util/automaton/MinimizationOperations.java     |  10 +-
 .../lucene/util/bkd/TestBKDRadixSelector.java      |  20 +--
 .../test/org/apache/lucene/util/fst/TestFSTs.java  |  54 ++++---
 .../lucene/demo/facet/CustomFacetSetExample.java   |   2 +-
 .../lucene/facet/FacetCountsWithFilterQuery.java   |   6 +-
 .../org/apache/lucene/facet/FacetsCollector.java   |  33 ++---
 .../apache/lucene/facet/LongValueFacetCounts.java  |  22 +--
 .../facet/RandomSamplingFacetsCollector.java       |  10 +-
 .../lucene/facet/StringValueFacetCounts.java       |  20 +--
 .../org/apache/lucene/facet/facetset/DimRange.java |  20 +--
 .../facet/facetset/MatchingFacetSetsCounts.java    |   2 +-
 .../facet/facetset/RangeFacetSetMatcher.java       |   4 +-
 .../lucene/facet/range/DoubleRangeFacetCounts.java |  10 +-
 .../facet/range/ExclusiveLongRangeCounter.java     |  10 +-
 .../lucene/facet/range/LongRangeFacetCounts.java   |  10 +-
 .../lucene/facet/range/RangeFacetCounts.java       |   7 +-
 .../rangeonrange/RangeOnRangeFacetCounts.java      |   4 +-
 .../AbstractSortedSetDocValueFacetCounts.java      |  14 +-
 .../ConcurrentSortedSetDocValuesFacetCounts.java   |  10 +-
 .../sortedset/SortedSetDocValuesFacetCounts.java   |  10 +-
 .../sortedset/SortedSetDocValuesReaderState.java   |  21 +--
 .../facet/taxonomy/FastTaxonomyFacetCounts.java    |   6 +-
 .../facet/taxonomy/SearcherTaxonomyManager.java    |  22 ++-
 .../taxonomy/TaxonomyFacetFloatAssociations.java   |  16 +--
 .../taxonomy/TaxonomyFacetIntAssociations.java     |   7 +-
 .../lucene/facet/taxonomy/TaxonomyFacets.java      |   4 +-
 .../org/apache/lucene/facet/FacetTestCase.java     |   4 +-
 .../org/apache/lucene/facet/TestDrillSideways.java |  15 +-
 .../org/apache/lucene/facet/TestFacetUtils.java    |   4 +-
 .../facet/TestRandomSamplingFacetsCollector.java   |   8 +-
 .../lucene/facet/taxonomy/TestOrdinalData.java     |   8 +-
 .../taxonomy/TestSearcherTaxonomyManager.java      |  16 +--
 .../facet/taxonomy/TestTaxonomyFacetLabels.java    |   4 +-
 .../TestAlwaysRefreshDirectoryTaxonomyReader.java  |   6 +-
 .../apache/lucene/search/grouping/GroupDocs.java   |  55 ++------
 .../search/grouping/GroupFacetCollector.java       |  44 +-----
 .../search/grouping/TermGroupFacetCollector.java   |  11 +-
 .../apache/lucene/search/grouping/TopGroups.java   |  21 +--
 .../search/grouping/BaseGroupSelectorTestCase.java |  29 ++--
 .../lucene/search/grouping/TestBlockGrouping.java  |  31 ++--
 .../grouping/TestDistinctValuesCollector.java      |  23 +--
 .../search/grouping/TestGroupFacetCollector.java   | 156 +++++++++------------
 .../lucene/search/grouping/TestGrouping.java       | 124 ++++++++--------
 .../lucene/search/grouping/TestGroupingSearch.java |  42 +++---
 .../lucene/search/grouping/TestTopGroups.java      |  16 +--
 .../search/uhighlight/FieldOffsetStrategy.java     |  20 +--
 .../uhighlight/MemoryIndexOffsetStrategy.java      |  15 +-
 .../uhighlight/TokenStreamOffsetStrategy.java      |   4 +-
 .../lucene/search/uhighlight/UHComponents.java     |  80 ++---------
 .../search/uhighlight/UnifiedHighlighter.java      |  18 ++-
 .../vectorhighlight/BaseFragmentsBuilder.java      |  17 ++-
 .../search/vectorhighlight/FieldFragList.java      |  40 ++----
 .../vectorhighlight/WeightedFieldFragList.java     |   7 +-
 .../uhighlight/TestUnifiedHighlighterRanking.java  |  18 +--
 .../TestUnifiedHighlighterExtensibility.java       |  14 +-
 .../TestSimpleFragmentsBuilder.java                |   9 +-
 .../TestWeightedFragListBuilder.java               |   2 +-
 .../DiversifyingNearestChildrenKnnCollector.java   |  11 +-
 .../lucene/luke/models/analysis/AnalysisImpl.java  |   6 +-
 .../luke/models/analysis/CustomAnalyzerConfig.java |  19 +--
 .../lucene/index/memory/TestMemoryIndex.java       |  18 +--
 .../misc/util/fst/UpToTwoPositiveIntOutputs.java   |  29 +---
 .../apache/lucene/misc/util/fst/TestFSTsMisc.java  |   6 +-
 .../org/apache/lucene/monitor/HighlightsMatch.java |  51 ++-----
 .../java/org/apache/lucene/monitor/Monitor.java    |  26 ++--
 .../org/apache/lucene/monitor/ParallelMatcher.java |  28 +---
 .../apache/lucene/monitor/PartitionMatcher.java    |  28 +---
 .../apache/lucene/monitor/WritableQueryIndex.java  |  10 +-
 .../apache/lucene/monitor/TestCachePurging.java    |  24 ++--
 .../intervals/DisjunctionIntervalsSource.java      |  13 +-
 .../queryparser/ext/ExtendableQueryParser.java     |   4 +-
 .../lucene/queryparser/ext/ExtensionQuery.java     |  49 +------
 .../apache/lucene/queryparser/ext/Extensions.java  |  17 +--
 .../classic/TestMultiPhraseQueryParsing.java       |  10 +-
 .../lucene/queryparser/ext/ExtensionStub.java      |   2 +-
 .../org/apache/lucene/replicator/nrt/CopyJob.java  |   4 +-
 .../apache/lucene/replicator/nrt/CopyOneFile.java  |   8 +-
 .../apache/lucene/replicator/nrt/CopyState.java    |  38 ++---
 .../apache/lucene/replicator/nrt/FileMetaData.java |  28 ++--
 .../apache/lucene/replicator/nrt/PrimaryNode.java  |  12 +-
 .../apache/lucene/replicator/nrt/ReplicaNode.java  |  37 ++---
 .../lucene/replicator/nrt/SimpleCopyJob.java       |  12 +-
 .../lucene/replicator/nrt/SimplePrimaryNode.java   |  20 +--
 .../lucene/replicator/nrt/SimpleReplicaNode.java   |   2 +-
 .../lucene/replicator/nrt/TestSimpleServer.java    |  12 +-
 .../idversion/VersionBlockTreeTermsWriter.java     |  17 ++-
 .../document/FloatPointNearestNeighbor.java        |  15 +-
 .../lucene/sandbox/search/CombinedFieldQuery.java  |  23 +--
 .../sandbox/search/MultiNormsLeafSimScorer.java    |   8 +-
 .../lucene/spatial3d/geom/GeoPolygonFactory.java   |  35 ++---
 .../lucene/spatial3d/geom/GeoStandardPath.java     |   9 +-
 .../lucene/search/spell/CombineSuggestion.java     |  25 ++--
 .../lucene/search/spell/WordBreakSpellChecker.java |  17 +--
 .../suggest/analyzing/AnalyzingSuggester.java      |  17 ++-
 .../lucene/search/suggest/analyzing/FSTUtil.java   |  32 ++---
 .../suggest/analyzing/FreeTextSuggester.java       |   4 +-
 .../suggest/document/CompletionFieldsConsumer.java |  14 +-
 .../search/suggest/document/ContextQuery.java      |  25 ++--
 .../search/suggest/document/NRTSuggester.java      |  17 +--
 .../suggest/document/NRTSuggesterBuilder.java      |   9 +-
 .../search/suggest/fst/WFSTCompletionLookup.java   |   4 +-
 .../search/spell/TestWordBreakSpellChecker.java    |  30 ++--
 .../org/apache/lucene/search/suggest/Average.java  |  20 ++-
 .../search/suggest/SuggestRebuildTestUtil.java     |  14 +-
 .../lucene/search/suggest/TestLookupBenchmark.java |   2 +-
 .../analyzing/TestAnalyzingInfixSuggester.java     |  20 ++-
 .../suggest/analyzing/TestAnalyzingSuggester.java  |  14 +-
 .../suggest/analyzing/TestFuzzySuggester.java      |  12 +-
 .../codecs/ramonly/RAMOnlyPostingsFormat.java      |   6 +-
 .../tests/search/ShardSearchingTestBase.java       |  42 +-----
 .../apache/lucene/tests/util/RamUsageTester.java   |  10 +-
 .../tests/util/automaton/AutomatonTestUtil.java    |  10 +-
 .../apache/lucene/tests/util/fst/FSTTester.java    |   9 +-
 217 files changed, 1166 insertions(+), 2585 deletions(-)

diff --git a/lucene/CHANGES.txt b/lucene/CHANGES.txt
index 10a4d8597d1..513a0d65c95 100644
--- a/lucene/CHANGES.txt
+++ b/lucene/CHANGES.txt
@@ -118,6 +118,8 @@ API Changes
   argument with a `FacetsCollectorManager` and update the return type to include both `TopDocs` results as well as
   facets results. (Luca Cavanna)
 
+* GITHUB#13328: Convert many basic Lucene classes to record classes, including CollectionStatistics, TermStatistics and LeafMetadata. (Shubham Chaudhary)
+
 New Features
 ---------------------
 
diff --git a/lucene/MIGRATE.md b/lucene/MIGRATE.md
index 2f4728f5667..0d673eca2f2 100644
--- a/lucene/MIGRATE.md
+++ b/lucene/MIGRATE.md
@@ -193,6 +193,7 @@ access the members using method calls instead of field accesses. Affected classe
 
 - `IOContext`, `MergeInfo`, and `FlushInfo` (GITHUB#13205)
 - `BooleanClause` (GITHUB#13261)
+- Many basic Lucene classes, including `CollectionStatistics`, `TermStatistics` and `LeafMetadata` (GITHUB#13328)
 
 ### Boolean flags on IOContext replaced with a new ReadAdvice enum.
 
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/CheckCompoundPattern.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/CheckCompoundPattern.java
index 9a779138a00..b5796bd1e57 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/CheckCompoundPattern.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/CheckCompoundPattern.java
@@ -52,7 +52,7 @@ class CheckCompoundPattern {
 
   boolean prohibitsCompounding(CharsRef word, int breakPos, Root<?> rootBefore, Root<?> rootAfter) {
     if (isNonAffixedPattern(endChars)) {
-      if (!charsMatch(word, breakPos - rootBefore.word.length(), rootBefore.word)) {
+      if (!charsMatch(word, breakPos - rootBefore.word().length(), rootBefore.word())) {
         return false;
       }
     } else if (!charsMatch(word, breakPos - endChars.length(), endChars)) {
@@ -60,7 +60,7 @@ class CheckCompoundPattern {
     }
 
     if (isNonAffixedPattern(beginChars)) {
-      if (!charsMatch(word, breakPos, rootAfter.word)) {
+      if (!charsMatch(word, breakPos, rootAfter.word())) {
         return false;
       }
     } else if (!charsMatch(word, breakPos, beginChars)) {
@@ -84,7 +84,7 @@ class CheckCompoundPattern {
 
   private boolean hasAllFlags(Root<?> root, char[] flags) {
     for (char flag : flags) {
-      if (!dictionary.hasFlag(root.entryId, flag)) {
+      if (!dictionary.hasFlag(root.entryId(), flag)) {
         return false;
       }
     }
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/GeneratingSuggester.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/GeneratingSuggester.java
index 49ebc784766..ca00ee87164 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/GeneratingSuggester.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/GeneratingSuggester.java
@@ -24,7 +24,6 @@ import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.LinkedHashSet;
 import java.util.List;
-import java.util.Objects;
 import java.util.PriorityQueue;
 import java.util.Set;
 import java.util.TreeSet;
@@ -111,7 +110,7 @@ class GeneratingSuggester {
 
   private static boolean isWorseThan(int score, CharsRef candidate, Weighted<Root<String>> root) {
     return score < root.score
-        || score == root.score && CharSequence.compare(candidate, root.word.word) > 0;
+        || score == root.score && CharSequence.compare(candidate, root.word.word()) > 0;
   }
 
   private void processSuggestibleWords(
@@ -162,11 +161,11 @@ class GeneratingSuggester {
     List<char[]> crossProducts = new ArrayList<>();
     Set<String> result = new LinkedHashSet<>();
 
-    if (!dictionary.hasFlag(root.entryId, dictionary.needaffix)) {
-      result.add(root.word);
+    if (!dictionary.hasFlag(root.entryId(), dictionary.needaffix)) {
+      result.add(root.word());
     }
 
-    char[] wordChars = root.word.toCharArray();
+    char[] wordChars = root.word().toCharArray();
 
     // suffixes
     processAffixes(
@@ -180,7 +179,7 @@ class GeneratingSuggester {
           }
 
           String suffix = misspelled.substring(misspelled.length() - suffixLength);
-          String withSuffix = root.word.substring(0, root.word.length() - stripLength) + suffix;
+          String withSuffix = root.word().substring(0, root.word().length() - stripLength) + suffix;
           result.add(withSuffix);
           if (dictionary.isCrossProduct(suffixId)) {
             crossProducts.add(withSuffix.toCharArray());
@@ -192,7 +191,7 @@ class GeneratingSuggester {
         true,
         misspelled,
         (prefixLength, prefixId) -> {
-          if (!dictionary.hasFlag(root.entryId, dictionary.affixData(prefixId, AFFIX_FLAG))
+          if (!dictionary.hasFlag(root.entryId(), dictionary.affixData(prefixId, AFFIX_FLAG))
               || !dictionary.isCrossProduct(prefixId)) {
             return;
           }
@@ -217,7 +216,7 @@ class GeneratingSuggester {
           if (hasCompatibleFlags(root, prefixId)
               && checkAffixCondition(prefixId, wordChars, stripLength, stemLength)) {
             String prefix = misspelled.substring(0, prefixLength);
-            result.add(prefix + root.word.substring(stripLength));
+            result.add(prefix + root.word().substring(stripLength));
           }
         });
 
@@ -263,7 +262,7 @@ class GeneratingSuggester {
   }
 
   private boolean hasCompatibleFlags(Root<?> root, int affixId) {
-    if (!dictionary.hasFlag(root.entryId, dictionary.affixData(affixId, AFFIX_FLAG))) {
+    if (!dictionary.hasFlag(root.entryId(), dictionary.affixData(affixId, AFFIX_FLAG))) {
       return false;
     }
 
@@ -447,28 +446,8 @@ class GeneratingSuggester {
     return commonScore;
   }
 
-  private static class Weighted<T extends Comparable<T>> implements Comparable<Weighted<T>> {
-    final T word;
-    final int score;
-
-    Weighted(T word, int score) {
-      this.word = word;
-      this.score = score;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (!(o instanceof Weighted)) return false;
-      @SuppressWarnings("unchecked")
-      Weighted<T> that = (Weighted<T>) o;
-      return score == that.score && word.equals(that.word);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(word, score);
-    }
+  private record Weighted<T extends Comparable<T>>(T word, int score)
+      implements Comparable<Weighted<T>> {
 
     @Override
     public String toString() {
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java
index f288ef90070..8adb82f79b2 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Hunspell.java
@@ -132,7 +132,7 @@ public class Hunspell {
   Boolean checkSimpleWord(char[] wordChars, int length, WordCase originalCase) {
     Root<CharsRef> entry = findStem(wordChars, 0, length, originalCase, SIMPLE_WORD);
     if (entry != null) {
-      return !dictionary.hasFlag(entry.entryId, dictionary.forbiddenword);
+      return !dictionary.hasFlag(entry.entryId(), dictionary.forbiddenword);
     }
 
     return null;
@@ -229,7 +229,7 @@ public class Hunspell {
           stem = findStem(word.chars, word.offset, breakPos + 1, originalCase, context);
         }
         if (stem != null
-            && !dictionary.hasFlag(stem.entryId, dictionary.forbiddenword)
+            && !dictionary.hasFlag(stem.entryId(), dictionary.forbiddenword)
             && (prev == null || prev.mayCompound(stem, breakPos, originalCase))) {
           CompoundPart part = new CompoundPart(prev, word, breakPos, stem, null);
           if (checkCompoundsAfter(originalCase, part)) {
@@ -274,7 +274,7 @@ public class Hunspell {
     Root<CharsRef> lastRoot =
         findStem(word.chars, breakOffset, remainingLength, originalCase, COMPOUND_END);
     if (lastRoot != null
-        && !dictionary.hasFlag(lastRoot.entryId, dictionary.forbiddenword)
+        && !dictionary.hasFlag(lastRoot.entryId(), dictionary.forbiddenword)
         && !(dictionary.checkCompoundDup && prev.root.equals(lastRoot))
         && !hasForceUCaseProblem(lastRoot, originalCase, word.chars)
         && prev.mayCompound(lastRoot, remainingLength, originalCase)) {
@@ -288,7 +288,7 @@ public class Hunspell {
   private boolean hasForceUCaseProblem(Root<?> root, WordCase originalCase, char[] wordChars) {
     if (originalCase == WordCase.TITLE || originalCase == WordCase.UPPER) return false;
     if (originalCase == null && Character.isUpperCase(wordChars[0])) return false;
-    return dictionary.hasFlag(root.entryId, dictionary.forceUCase);
+    return dictionary.hasFlag(root.entryId(), dictionary.forceUCase);
   }
 
   /**
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Root.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Root.java
index e65992e6f67..6c5ea7877c7 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Root.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/hunspell/Root.java
@@ -16,36 +16,13 @@
  */
 package org.apache.lucene.analysis.hunspell;
 
-import java.util.Objects;
-
-class Root<T extends CharSequence> implements Comparable<Root<T>> {
-  final T word;
-  final int entryId;
-
-  Root(T word, int entryId) {
-    this.word = word;
-    this.entryId = entryId;
-  }
+record Root<T extends CharSequence>(T word, int entryId) implements Comparable<Root<T>> {
 
   @Override
   public String toString() {
     return word.toString();
   }
 
-  @Override
-  public boolean equals(Object o) {
-    if (this == o) return true;
-    if (!(o instanceof Root)) return false;
-    @SuppressWarnings("unchecked")
-    Root<T> root = (Root<T>) o;
-    return entryId == root.entryId && word.equals(root.word);
-  }
-
-  @Override
-  public int hashCode() {
-    return Objects.hash(word, entryId);
-  }
-
   @Override
   public int compareTo(Root<T> o) {
     return CharSequence.compare(word, o.word);
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/pattern/PatternTypingFilter.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/pattern/PatternTypingFilter.java
index c0288ef7c89..565f605199c 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/pattern/PatternTypingFilter.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/pattern/PatternTypingFilter.java
@@ -59,12 +59,12 @@ public class PatternTypingFilter extends TokenFilter {
   public final boolean incrementToken() throws IOException {
     if (input.incrementToken()) {
       for (PatternTypingRule rule : replacementAndFlagByPattern) {
-        Matcher matcher = rule.getPattern().matcher(termAtt);
+        Matcher matcher = rule.pattern().matcher(termAtt);
         if (matcher.find()) {
           // allow 2nd reset() and find() that occurs inside replaceFirst to avoid excess string
           // creation
-          typeAtt.setType(matcher.replaceFirst(rule.getTypeTemplate()));
-          flagAtt.setFlags(rule.getFlags());
+          typeAtt.setType(matcher.replaceFirst(rule.typeTemplate()));
+          flagAtt.setFlags(rule.flags());
           return true;
         }
       }
@@ -74,27 +74,5 @@ public class PatternTypingFilter extends TokenFilter {
   }
 
   /** Value holding class for pattern typing rules. */
-  public static class PatternTypingRule {
-    private final Pattern pattern;
-    private final int flags;
-    private final String typeTemplate;
-
-    public PatternTypingRule(Pattern pattern, int flags, String typeTemplate) {
-      this.pattern = pattern;
-      this.flags = flags;
-      this.typeTemplate = typeTemplate;
-    }
-
-    public Pattern getPattern() {
-      return pattern;
-    }
-
-    public int getFlags() {
-      return flags;
-    }
-
-    public String getTypeTemplate() {
-      return typeTemplate;
-    }
-  }
+  public record PatternTypingRule(Pattern pattern, int flags, String typeTemplate) {}
 }
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/SynonymGraphFilter.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/SynonymGraphFilter.java
index e291d8de357..73a8aa9022e 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/SynonymGraphFilter.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/SynonymGraphFilter.java
@@ -142,22 +142,10 @@ public final class SynonymGraphFilter extends TokenFilter {
     }
   }
 
-  static class BufferedOutputToken {
-    final String term;
-
-    // Non-null if this was an incoming token:
-    final State state;
-
-    final int startNode;
-    final int endNode;
-
-    public BufferedOutputToken(State state, String term, int startNode, int endNode) {
-      this.state = state;
-      this.term = term;
-      this.startNode = startNode;
-      this.endNode = endNode;
-    }
-  }
+  /**
+   * @param state Non-null if this was an incoming token:
+   */
+  record BufferedOutputToken(State state, String term, int startNode, int endNode) {}
 
   /**
    * Apply previously built synonyms to incoming tokens.
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java
index 349fa57c34a..4688e57a3d0 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/TermAndBoost.java
@@ -18,17 +18,15 @@ package org.apache.lucene.analysis.synonym.word2vec;
 
 import org.apache.lucene.util.BytesRef;
 
-/** Wraps a term and boost */
-public class TermAndBoost {
-  /** the term */
-  public final BytesRef term;
-
-  /** the boost */
-  public final float boost;
-
+/**
+ * Wraps a term and boost
+ *
+ * @param term the term
+ * @param boost the boost
+ */
+public record TermAndBoost(BytesRef term, float boost) {
   /** Creates a new TermAndBoost */
-  public TermAndBoost(BytesRef term, float boost) {
-    this.term = BytesRef.deepCopyOf(term);
-    this.boost = boost;
+  public TermAndBoost {
+    term = BytesRef.deepCopyOf(term);
   }
 }
diff --git a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java
index a8db4c4c764..357e97480cd 100644
--- a/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java
+++ b/lucene/analysis/common/src/java/org/apache/lucene/analysis/synonym/word2vec/Word2VecSynonymFilter.java
@@ -80,7 +80,7 @@ public final class Word2VecSynonymFilter extends TokenFilter {
       clearAttributes();
       restoreState(this.lastState);
       termAtt.setEmpty();
-      termAtt.append(synonym.term.utf8ToString());
+      termAtt.append(synonym.term().utf8ToString());
       typeAtt.setType(SynonymGraphFilter.TYPE_SYNONYM);
       posLenAtt.setPositionLength(1);
       posIncrementAtt.setPositionIncrement(0);
diff --git a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java
index 3e7e6bce07a..228da4ede14 100644
--- a/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java
+++ b/lucene/analysis/common/src/test/org/apache/lucene/analysis/synonym/word2vec/TestWord2VecSynonymProvider.java
@@ -64,7 +64,7 @@ public class TestWord2VecSynonymProvider extends LuceneTestCase {
 
     assertEquals(4, actualSynonymsResults.size());
     for (int i = 0; i < expectedSynonyms.length; i++) {
-      assertEquals(new BytesRef(expectedSynonyms[i]), actualSynonymsResults.get(i).term);
+      assertEquals(new BytesRef(expectedSynonyms[i]), actualSynonymsResults.get(i).term());
     }
   }
 
@@ -83,8 +83,8 @@ public class TestWord2VecSynonymProvider extends LuceneTestCase {
 
     BytesRef expectedFirstSynonymTerm = new BytesRef("b");
     double expectedFirstSynonymBoost = 1.0;
-    assertEquals(expectedFirstSynonymTerm, actualSynonymsResults.get(0).term);
-    assertEquals(expectedFirstSynonymBoost, actualSynonymsResults.get(0).boost, 0.001f);
+    assertEquals(expectedFirstSynonymTerm, actualSynonymsResults.get(0).term());
+    assertEquals(expectedFirstSynonymBoost, actualSynonymsResults.get(0).boost(), 0.001f);
   }
 
   @Test
diff --git a/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/JapaneseCompletionFilter.java b/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/JapaneseCompletionFilter.java
index 4a22cce3f12..310a143a52e 100644
--- a/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/JapaneseCompletionFilter.java
+++ b/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/JapaneseCompletionFilter.java
@@ -139,19 +139,7 @@ public final class JapaneseCompletionFilter extends TokenFilter {
     }
   }
 
-  private static class CompletionToken {
-    final String term;
-    final boolean isFirst;
-    final int startOffset;
-    final int endOffset;
-
-    CompletionToken(String term, boolean isFirst, int startOffset, int endOffset) {
-      this.term = term;
-      this.isFirst = isFirst;
-      this.startOffset = startOffset;
-      this.endOffset = endOffset;
-    }
-  }
+  private record CompletionToken(String term, boolean isFirst, int startOffset, int endOffset) {}
 
   private static class CompletionTokenGenerator implements Iterator<CompletionToken> {
 
diff --git a/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/completion/KatakanaRomanizer.java b/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/completion/KatakanaRomanizer.java
index 8e137a8af3f..6e2e4f0268d 100644
--- a/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/completion/KatakanaRomanizer.java
+++ b/lucene/analysis/kuromoji/src/java/org/apache/lucene/analysis/ja/completion/KatakanaRomanizer.java
@@ -180,13 +180,5 @@ public class KatakanaRomanizer {
     return null;
   }
 
-  private static class MatchedKeystroke {
-    final int keystrokeLen;
-    final int keystrokeIndex;
-
-    MatchedKeystroke(int keystrokeLen, int keystrokeIndex) {
-      this.keystrokeLen = keystrokeLen;
-      this.keystrokeIndex = keystrokeIndex;
-    }
-  }
+  private record MatchedKeystroke(int keystrokeLen, int keystrokeIndex) {}
 }
diff --git a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/Viterbi.java b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/Viterbi.java
index 9f7765eaadf..8ba9cb36979 100644
--- a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/Viterbi.java
+++ b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/Viterbi.java
@@ -268,19 +268,19 @@ final class Viterbi
               final KoMorphData.Morpheme morpheme = morphemes[i];
               final Token compoundToken;
               if (token.getPOSType() == POS.Type.COMPOUND) {
-                assert endOffset - morpheme.surfaceForm.length() >= 0;
+                assert endOffset - morpheme.surfaceForm().length() >= 0;
                 compoundToken =
                     new DecompoundToken(
-                        morpheme.posTag,
-                        morpheme.surfaceForm,
-                        endOffset - morpheme.surfaceForm.length(),
+                        morpheme.posTag(),
+                        morpheme.surfaceForm(),
+                        endOffset - morpheme.surfaceForm().length(),
                         endOffset,
                         backType);
               } else {
                 compoundToken =
                     new DecompoundToken(
-                        morpheme.posTag,
-                        morpheme.surfaceForm,
+                        morpheme.posTag(),
+                        morpheme.surfaceForm(),
                         token.getStartOffset(),
                         token.getEndOffset(),
                         backType);
@@ -289,7 +289,7 @@ final class Viterbi
                 compoundToken.setPositionIncrement(0);
               }
               ++posLen;
-              endOffset -= morpheme.surfaceForm.length();
+              endOffset -= morpheme.surfaceForm().length();
               pending.add(compoundToken);
               if (VERBOSE) {
                 System.out.println("    add token=" + pending.get(pending.size() - 1));
diff --git a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/KoMorphData.java b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/KoMorphData.java
index 0887a7f0c42..2b2c53a4d6d 100644
--- a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/KoMorphData.java
+++ b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/KoMorphData.java
@@ -22,15 +22,7 @@ import org.apache.lucene.analysis.morph.MorphData;
 /** Represents Korean morphological information. */
 public interface KoMorphData extends MorphData {
   /** A morpheme extracted from a compound token. */
-  class Morpheme {
-    public final POS.Tag posTag;
-    public final String surfaceForm;
-
-    public Morpheme(POS.Tag posTag, String surfaceForm) {
-      this.posTag = posTag;
-      this.surfaceForm = surfaceForm;
-    }
-  }
+  record Morpheme(POS.Tag posTag, String surfaceForm) {}
 
   /**
    * Get the {@link org.apache.lucene.analysis.ko.POS.Type} of specified word (morpheme, compound,
diff --git a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/TokenInfoDictionaryEntryWriter.java b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/TokenInfoDictionaryEntryWriter.java
index 95ce0277a9d..8b1e91b132a 100644
--- a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/TokenInfoDictionaryEntryWriter.java
+++ b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/dict/TokenInfoDictionaryEntryWriter.java
@@ -150,13 +150,13 @@ class TokenInfoDictionaryEntryWriter extends DictionaryEntryWriter {
       int compoundOffset = 0;
       for (KoMorphData.Morpheme morpheme : morphemes) {
         if (hasSinglePOS == false) {
-          buffer.put((byte) morpheme.posTag.ordinal());
+          buffer.put((byte) morpheme.posTag().ordinal());
         }
         if (posType != POS.Type.INFLECT) {
-          buffer.put((byte) morpheme.surfaceForm.length());
-          compoundOffset += morpheme.surfaceForm.length();
+          buffer.put((byte) morpheme.surfaceForm().length());
+          compoundOffset += morpheme.surfaceForm().length();
         } else {
-          writeString(morpheme.surfaceForm);
+          writeString(morpheme.surfaceForm());
         }
         assert compoundOffset <= entry[0].length() : Arrays.toString(entry);
       }
diff --git a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/tokenattributes/PartOfSpeechAttributeImpl.java b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/tokenattributes/PartOfSpeechAttributeImpl.java
index a59999db557..8ca26387e0b 100644
--- a/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/tokenattributes/PartOfSpeechAttributeImpl.java
+++ b/lucene/analysis/nori/src/java/org/apache/lucene/analysis/ko/tokenattributes/PartOfSpeechAttributeImpl.java
@@ -86,11 +86,11 @@ public class PartOfSpeechAttributeImpl extends AttributeImpl implements PartOfSp
         builder.append("+");
       }
       builder
-          .append(morpheme.surfaceForm)
+          .append(morpheme.surfaceForm())
           .append('/')
-          .append(morpheme.posTag.name())
+          .append(morpheme.posTag().name())
           .append('(')
-          .append(morpheme.posTag.description())
+          .append(morpheme.posTag().description())
           .append(')');
     }
     return builder.toString();
diff --git a/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestTokenInfoDictionary.java b/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestTokenInfoDictionary.java
index 7c6b282eecf..0c574a70fde 100644
--- a/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestTokenInfoDictionary.java
+++ b/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestTokenInfoDictionary.java
@@ -170,14 +170,14 @@ public class TestTokenInfoDictionary extends LuceneTestCase {
           if (decompound != null) {
             int offset = 0;
             for (KoMorphData.Morpheme morph : decompound) {
-              assertTrue(UnicodeUtil.validUTF16String(morph.surfaceForm));
-              assertFalse(morph.surfaceForm.isEmpty());
-              assertEquals(morph.surfaceForm.trim(), morph.surfaceForm);
+              assertTrue(UnicodeUtil.validUTF16String(morph.surfaceForm()));
+              assertFalse(morph.surfaceForm().isEmpty());
+              assertEquals(morph.surfaceForm().trim(), morph.surfaceForm());
               if (type != POS.Type.INFLECT) {
                 assertEquals(
-                    morph.surfaceForm,
-                    surfaceForm.substring(offset, offset + morph.surfaceForm.length()));
-                offset += morph.surfaceForm.length();
+                    morph.surfaceForm(),
+                    surfaceForm.substring(offset, offset + morph.surfaceForm().length()));
+                offset += morph.surfaceForm().length();
               }
             }
             assertTrue(offset <= surfaceForm.length());
diff --git a/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestUserDictionary.java b/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestUserDictionary.java
index 8fb2827a336..7ce5dd80563 100644
--- a/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestUserDictionary.java
+++ b/lucene/analysis/nori/src/test/org/apache/lucene/analysis/ko/dict/TestUserDictionary.java
@@ -43,10 +43,10 @@ public class TestUserDictionary extends LuceneTestCase {
         dictionary.getMorphAttributes().getMorphemes(wordIds.get(1), sArray, 0, s.length());
     assertNotNull(decompound);
     assertEquals(2, decompound.length);
-    assertEquals(decompound[0].posTag, POS.Tag.NNG);
-    assertEquals(decompound[0].surfaceForm, "세종");
-    assertEquals(decompound[1].posTag, POS.Tag.NNG);
-    assertEquals(decompound[1].surfaceForm, "시");
+    assertEquals(decompound[0].posTag(), POS.Tag.NNG);
+    assertEquals(decompound[0].surfaceForm(), "세종");
+    assertEquals(decompound[1].posTag(), POS.Tag.NNG);
+    assertEquals(decompound[1].surfaceForm(), "시");
 
     s = "c++";
     sArray = s.toCharArray();
diff --git a/lucene/backward-codecs/src/java/org/apache/lucene/backward_codecs/lucene50/ForUtil.java b/lucene/backward-codecs/src/java/org/apache/lucene/backward_codecs/lucene50/ForUtil.java
index 2f1f24dcd49..b6131049694 100644
--- a/lucene/backward-codecs/src/java/org/apache/lucene/backward_codecs/lucene50/ForUtil.java
+++ b/lucene/backward-codecs/src/java/org/apache/lucene/backward_codecs/lucene50/ForUtil.java
@@ -103,19 +103,20 @@ final class ForUtil {
     for (int bpv = 1; bpv <= 32; ++bpv) {
       final FormatAndBits formatAndBits =
           PackedInts.fastestFormatAndBits(BLOCK_SIZE, bpv, acceptableOverheadRatio);
-      assert formatAndBits.format.isSupported(formatAndBits.bitsPerValue);
-      assert formatAndBits.bitsPerValue <= 32;
+      assert formatAndBits.format().isSupported(formatAndBits.bitsPerValue());
+      assert formatAndBits.bitsPerValue() <= 32;
       encodedSizes[bpv] =
-          encodedSize(formatAndBits.format, PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue);
+          encodedSize(
+              formatAndBits.format(), PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue());
       encoders[bpv] =
           PackedInts.getEncoder(
-              formatAndBits.format, PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue);
+              formatAndBits.format(), PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue());
       decoders[bpv] =
           PackedInts.getDecoder(
-              formatAndBits.format, PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue);
+              formatAndBits.format(), PackedInts.VERSION_CURRENT, formatAndBits.bitsPerValue());
       iterations[bpv] = computeIterations(decoders[bpv]);
 
-      out.writeVInt(formatAndBits.format.getId() << 5 | (formatAndBits.bitsPerValue - 1));
+      out.writeVInt(formatAndBits.format().getId() << 5 | (formatAndBits.bitsPerValue() - 1));
     }
   }
 
diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene60/bkd/BKDWriter60.java b/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene60/bkd/BKDWriter60.java
index 64ee7d7442b..a1e304a3149 100644
--- a/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene60/bkd/BKDWriter60.java
+++ b/lucene/backward-codecs/src/test/org/apache/lucene/backward_codecs/lucene60/bkd/BKDWriter60.java
@@ -1931,7 +1931,7 @@ public class BKDWriter60 implements Closeable {
   private void computePackedValueBounds(
       BKDRadixSelector.PathSlice slice, byte[] minPackedValue, byte[] maxPackedValue)
       throws IOException {
-    try (PointReader reader = slice.writer.getReader(slice.start, slice.count)) {
+    try (PointReader reader = slice.writer().getReader(slice.start(), slice.count())) {
       if (reader.next() == false) {
         return;
       }
@@ -1995,16 +1995,16 @@ public class BKDWriter60 implements Closeable {
       // least number of unique bytes at commonPrefixLengths[dim], which makes compression more
       // efficient
       HeapPointWriter heapSource;
-      if (points.writer instanceof HeapPointWriter == false) {
+      if (points.writer() instanceof HeapPointWriter == false) {
         // Adversarial cases can cause this, e.g. merging big segments with most of the points
         // deleted
-        heapSource = switchToHeap(points.writer);
+        heapSource = switchToHeap(points.writer());
       } else {
-        heapSource = (HeapPointWriter) points.writer;
+        heapSource = (HeapPointWriter) points.writer();
       }
 
-      int from = Math.toIntExact(points.start);
-      int to = Math.toIntExact(points.start + points.count);
+      int from = Math.toIntExact(points.start());
+      int to = Math.toIntExact(points.start() + points.count());
       // we store common prefix on scratch1
       computeCommonPrefixLength(heapSource, scratch1, from, to);
 
@@ -2107,8 +2107,8 @@ public class BKDWriter60 implements Closeable {
           : "nodeID=" + nodeID + " splitValues.length=" + splitPackedValues.length;
 
       // How many points will be in the left tree:
-      long rightCount = points.count / 2;
-      long leftCount = points.count - rightCount;
+      long rightCount = points.count() / 2;
+      long leftCount = points.count() - rightCount;
 
       BKDRadixSelector.PathSlice[] slices = new BKDRadixSelector.PathSlice[2];
 
@@ -2128,9 +2128,9 @@ public class BKDWriter60 implements Closeable {
           radixSelector.select(
               points,
               slices,
-              points.start,
-              points.start + points.count,
-              points.start + leftCount,
+              points.start(),
+              points.start() + points.count(),
+              points.start() + leftCount,
               splitDim,
               commonPrefixLen);
 
diff --git a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestIndexSortBackwardsCompatibility.java b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestIndexSortBackwardsCompatibility.java
index 82de070189c..0feeccb859d 100644
--- a/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestIndexSortBackwardsCompatibility.java
+++ b/lucene/backward-codecs/src/test/org/apache/lucene/backward_index/TestIndexSortBackwardsCompatibility.java
@@ -72,7 +72,7 @@ public class TestIndexSortBackwardsCompatibility extends BackwardsCompatibilityT
     final Sort sort;
     try (DirectoryReader reader = DirectoryReader.open(directory)) {
       assertEquals(1, reader.leaves().size());
-      sort = reader.leaves().get(0).reader().getMetaData().getSort();
+      sort = reader.leaves().get(0).reader().getMetaData().sort();
       assertNotNull(sort);
       searchExampleIndex(reader);
     }
@@ -140,7 +140,7 @@ public class TestIndexSortBackwardsCompatibility extends BackwardsCompatibilityT
   public void testSortedIndex() throws Exception {
     try (DirectoryReader reader = DirectoryReader.open(directory)) {
       assertEquals(1, reader.leaves().size());
-      Sort sort = reader.leaves().get(0).reader().getMetaData().getSort();
+      Sort sort = reader.leaves().get(0).reader().getMetaData().sort();
       assertNotNull(sort);
       assertEquals("<long: \"dateDV\">!", sort.toString());
       // This will confirm the docs are really sorted
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/BM25NBClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/BM25NBClassifier.java
index 40e77338192..e16d9b66ab9 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/BM25NBClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/BM25NBClassifier.java
@@ -151,13 +151,13 @@ public class BM25NBClassifier implements Classifier<BytesRef> {
     if (!assignedClasses.isEmpty()) {
       Collections.sort(assignedClasses);
       // this is a negative number closest to 0 = a
-      double smax = assignedClasses.get(0).getScore();
+      double smax = assignedClasses.get(0).score();
 
       double sumLog = 0;
       // log(sum(exp(x_n-a)))
       for (ClassificationResult<BytesRef> cr : assignedClasses) {
         // getScore-smax <=0 (both negative, smax is the smallest abs()
-        sumLog += Math.exp(cr.getScore() - smax);
+        sumLog += Math.exp(cr.score() - smax);
       }
       // loga=a+log(sum(exp(x_n-a))) = log(sum(exp(x_n)))
       double loga = smax;
@@ -165,8 +165,8 @@ public class BM25NBClassifier implements Classifier<BytesRef> {
 
       // 1/sum*x = exp(log(x))*1/sum = exp(log(x)-log(sum))
       for (ClassificationResult<BytesRef> cr : assignedClasses) {
-        double scoreDiff = cr.getScore() - loga;
-        returnList.add(new ClassificationResult<>(cr.getAssignedClass(), Math.exp(scoreDiff)));
+        double scoreDiff = cr.score() - loga;
+        returnList.add(new ClassificationResult<>(cr.assignedClass(), Math.exp(scoreDiff)));
       }
     }
     return returnList;
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/BooleanPerceptronClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/BooleanPerceptronClassifier.java
index e4c4ccb1a95..d45bcb1f813 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/BooleanPerceptronClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/BooleanPerceptronClassifier.java
@@ -148,7 +148,7 @@ public class BooleanPerceptronClassifier implements Classifier<Boolean> {
       if (textField != null && classField != null) {
         // assign class to the doc
         ClassificationResult<Boolean> classificationResult = assignClass(textField.stringValue());
-        Boolean assignedClass = classificationResult.getAssignedClass();
+        Boolean assignedClass = classificationResult.assignedClass();
 
         Boolean correctClass = Boolean.valueOf(classField.stringValue());
         double modifier = Math.signum(correctClass.compareTo(assignedClass));
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/CachingNaiveBayesClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/CachingNaiveBayesClassifier.java
index deff4202167..f251b4d61b0 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/CachingNaiveBayesClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/CachingNaiveBayesClassifier.java
@@ -126,7 +126,7 @@ public class CachingNaiveBayesClassifier extends SimpleNaiveBayesClassifier {
         int removeIdx = -1;
         int i = 0;
         for (ClassificationResult<BytesRef> cr : ret) {
-          if (cr.getAssignedClass().equals(cclass)) {
+          if (cr.assignedClass().equals(cclass)) {
             removeIdx = i;
             break;
           }
@@ -137,7 +137,7 @@ public class CachingNaiveBayesClassifier extends SimpleNaiveBayesClassifier {
           ClassificationResult<BytesRef> toRemove = ret.get(removeIdx);
           ret.add(
               new ClassificationResult<>(
-                  toRemove.getAssignedClass(), toRemove.getScore() + Math.log(wordProbability)));
+                  toRemove.assignedClass(), toRemove.score() + Math.log(wordProbability)));
           ret.remove(removeIdx);
         }
       }
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/ClassificationResult.java b/lucene/classification/src/java/org/apache/lucene/classification/ClassificationResult.java
index 87836d72dbd..c6acf47d7a7 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/ClassificationResult.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/ClassificationResult.java
@@ -20,44 +20,15 @@ package org.apache.lucene.classification;
  * The result of a call to {@link Classifier#assignClass(String)} holding an assigned class of type
  * <code>T</code> and a score.
  *
+ * @param assignedClass the class <code>T</code> assigned by a {@link Classifier}
+ * @param score score the score for the assignedClass as a <code>double</code>
  * @lucene.experimental
  */
-public class ClassificationResult<T> implements Comparable<ClassificationResult<T>> {
-
-  private final T assignedClass;
-  private final double score;
-
-  /**
-   * Constructor
-   *
-   * @param assignedClass the class <code>T</code> assigned by a {@link Classifier}
-   * @param score the score for the assignedClass as a <code>double</code>
-   */
-  public ClassificationResult(T assignedClass, double score) {
-    this.assignedClass = assignedClass;
-    this.score = score;
-  }
-
-  /**
-   * retrieve the result class
-   *
-   * @return a <code>T</code> representing an assigned class
-   */
-  public T getAssignedClass() {
-    return assignedClass;
-  }
-
-  /**
-   * retrieve the result score
-   *
-   * @return a <code>double</code> representing a result score
-   */
-  public double getScore() {
-    return score;
-  }
+public record ClassificationResult<T>(T assignedClass, double score)
+    implements Comparable<ClassificationResult<T>> {
 
   @Override
   public int compareTo(ClassificationResult<T> o) {
-    return Double.compare(o.getScore(), this.getScore());
+    return Double.compare(o.score(), this.score());
   }
 }
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/KNearestFuzzyClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/KNearestFuzzyClassifier.java
index 235ed2c0d6b..70e3a88593b 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/KNearestFuzzyClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/KNearestFuzzyClassifier.java
@@ -108,9 +108,9 @@ public class KNearestFuzzyClassifier implements Classifier<BytesRef> {
     ClassificationResult<BytesRef> assignedClass = null;
     double maxscore = -Double.MAX_VALUE;
     for (ClassificationResult<BytesRef> cl : assignedClasses) {
-      if (cl.getScore() > maxscore) {
+      if (cl.score() > maxscore) {
         assignedClass = cl;
-        maxscore = cl.getScore();
+        maxscore = cl.score();
       }
     }
     return assignedClass;
@@ -193,7 +193,7 @@ public class KNearestFuzzyClassifier implements Classifier<BytesRef> {
     if (sumdoc < k) {
       for (ClassificationResult<BytesRef> cr : temporaryList) {
         returnList.add(
-            new ClassificationResult<>(cr.getAssignedClass(), cr.getScore() * k / (double) sumdoc));
+            new ClassificationResult<>(cr.assignedClass(), cr.score() * k / (double) sumdoc));
       }
     } else {
       returnList = temporaryList;
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/KNearestNeighborClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/KNearestNeighborClassifier.java
index 48424d4f0ed..7ffb93ae124 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/KNearestNeighborClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/KNearestNeighborClassifier.java
@@ -129,9 +129,9 @@ public class KNearestNeighborClassifier implements Classifier<BytesRef> {
     ClassificationResult<BytesRef> assignedClass = null;
     double maxscore = -Double.MAX_VALUE;
     for (ClassificationResult<BytesRef> cl : assignedClasses) {
-      if (cl.getScore() > maxscore) {
+      if (cl.score() > maxscore) {
         assignedClass = cl;
-        maxscore = cl.getScore();
+        maxscore = cl.score();
       }
     }
     return assignedClass;
@@ -229,7 +229,7 @@ public class KNearestNeighborClassifier implements Classifier<BytesRef> {
     if (sumdoc < k) {
       for (ClassificationResult<BytesRef> cr : temporaryList) {
         returnList.add(
-            new ClassificationResult<>(cr.getAssignedClass(), cr.getScore() * k / (double) sumdoc));
+            new ClassificationResult<>(cr.assignedClass(), cr.score() * k / (double) sumdoc));
       }
     } else {
       returnList = temporaryList;
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/SimpleNaiveBayesClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/SimpleNaiveBayesClassifier.java
index 668c6499f41..9897f95c6a9 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/SimpleNaiveBayesClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/SimpleNaiveBayesClassifier.java
@@ -105,9 +105,9 @@ public class SimpleNaiveBayesClassifier implements Classifier<BytesRef> {
     ClassificationResult<BytesRef> assignedClass = null;
     double maxscore = -Double.MAX_VALUE;
     for (ClassificationResult<BytesRef> c : assignedClasses) {
-      if (c.getScore() > maxscore) {
+      if (c.score() > maxscore) {
         assignedClass = c;
-        maxscore = c.getScore();
+        maxscore = c.score();
       }
     }
     return assignedClass;
@@ -297,13 +297,13 @@ public class SimpleNaiveBayesClassifier implements Classifier<BytesRef> {
     if (!assignedClasses.isEmpty()) {
       Collections.sort(assignedClasses);
       // this is a negative number closest to 0 = a
-      double smax = assignedClasses.get(0).getScore();
+      double smax = assignedClasses.get(0).score();
 
       double sumLog = 0;
       // log(sum(exp(x_n-a)))
       for (ClassificationResult<BytesRef> cr : assignedClasses) {
         // getScore-smax <=0 (both negative, smax is the smallest abs()
-        sumLog += Math.exp(cr.getScore() - smax);
+        sumLog += Math.exp(cr.score() - smax);
       }
       // loga=a+log(sum(exp(x_n-a))) = log(sum(exp(x_n)))
       double loga = smax;
@@ -311,8 +311,8 @@ public class SimpleNaiveBayesClassifier implements Classifier<BytesRef> {
 
       // 1/sum*x = exp(log(x))*1/sum = exp(log(x)-log(sum))
       for (ClassificationResult<BytesRef> cr : assignedClasses) {
-        double scoreDiff = cr.getScore() - loga;
-        returnList.add(new ClassificationResult<>(cr.getAssignedClass(), Math.exp(scoreDiff)));
+        double scoreDiff = cr.score() - loga;
+        returnList.add(new ClassificationResult<>(cr.assignedClass(), Math.exp(scoreDiff)));
       }
     }
     return returnList;
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/document/SimpleNaiveBayesDocumentClassifier.java b/lucene/classification/src/java/org/apache/lucene/classification/document/SimpleNaiveBayesDocumentClassifier.java
index d8ff07d8fd7..1c34d870935 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/document/SimpleNaiveBayesDocumentClassifier.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/document/SimpleNaiveBayesDocumentClassifier.java
@@ -80,9 +80,9 @@ public class SimpleNaiveBayesDocumentClassifier extends SimpleNaiveBayesClassifi
     ClassificationResult<BytesRef> assignedClass = null;
     double maxscore = -Double.MAX_VALUE;
     for (ClassificationResult<BytesRef> c : assignedClasses) {
-      if (c.getScore() > maxscore) {
+      if (c.score() > maxscore) {
         assignedClass = c;
-        maxscore = c.getScore();
+        maxscore = c.score();
       }
     }
     return assignedClass;
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/utils/ConfusionMatrixGenerator.java b/lucene/classification/src/java/org/apache/lucene/classification/utils/ConfusionMatrixGenerator.java
index 4994115b0a3..fb9ff922296 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/utils/ConfusionMatrixGenerator.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/utils/ConfusionMatrixGenerator.java
@@ -107,7 +107,7 @@ public class ConfusionMatrixGenerator {
               time += end - start;
 
               if (result != null) {
-                T assignedClass = result.getAssignedClass();
+                T assignedClass = result.assignedClass();
                 if (assignedClass != null) {
                   counter++;
                   String classified =
diff --git a/lucene/classification/src/java/org/apache/lucene/classification/utils/DatasetSplitter.java b/lucene/classification/src/java/org/apache/lucene/classification/utils/DatasetSplitter.java
index ecc2d3cbd02..76a33b0239c 100644
--- a/lucene/classification/src/java/org/apache/lucene/classification/utils/DatasetSplitter.java
+++ b/lucene/classification/src/java/org/apache/lucene/classification/utils/DatasetSplitter.java
@@ -138,13 +138,13 @@ public class DatasetSplitter {
       // iterate over existing documents
       StoredFields storedFields = originalIndex.storedFields();
       for (GroupDocs<Object> group : topGroups.groups) {
-        assert group.totalHits.relation == TotalHits.Relation.EQUAL_TO;
-        long totalHits = group.totalHits.value;
+        assert group.totalHits().relation == TotalHits.Relation.EQUAL_TO;
+        long totalHits = group.totalHits().value;
         double testSize = totalHits * testRatio;
         int tc = 0;
         double cvSize = totalHits * crossValidationRatio;
         int cvc = 0;
-        for (ScoreDoc scoreDoc : group.scoreDocs) {
+        for (ScoreDoc scoreDoc : group.scoreDocs()) {
 
           // create a new document for indexing
           Document doc = createNewDoc(storedFields, ft, scoreDoc, fieldNames);
diff --git a/lucene/classification/src/test/org/apache/lucene/classification/ClassificationTestBase.java b/lucene/classification/src/test/org/apache/lucene/classification/ClassificationTestBase.java
index 988a6eada9f..410ef8874c9 100644
--- a/lucene/classification/src/test/org/apache/lucene/classification/ClassificationTestBase.java
+++ b/lucene/classification/src/test/org/apache/lucene/classification/ClassificationTestBase.java
@@ -91,7 +91,7 @@ public abstract class ClassificationTestBase<T> extends LuceneTestCase {
       Classifier<T> classifier, String inputDoc, T expectedResult) throws Exception {
     ClassificationResult<T> classificationResult = classifier.assignClass(inputDoc);
     assertNotNull(classificationResult);
-    T assignedClass = classificationResult.getAssignedClass();
+    T assignedClass = classificationResult.assignedClass();
     assertNotNull(assignedClass);
     assertEquals(
         "got an assigned class of " + assignedClass,
@@ -101,7 +101,7 @@ public abstract class ClassificationTestBase<T> extends LuceneTestCase {
         assignedClass instanceof BytesRef
             ? ((BytesRef) assignedClass).utf8ToString()
             : assignedClass);
-    double score = classificationResult.getScore();
+    double score = classificationResult.score();
     assertTrue("score should be between 0 and 1, got:" + score, score <= 1 && score >= 0);
     return classificationResult;
   }
@@ -130,18 +130,17 @@ public abstract class ClassificationTestBase<T> extends LuceneTestCase {
     getSampleIndex(analyzer);
 
     ClassificationResult<T> classificationResult = classifier.assignClass(inputDoc);
-    assertNotNull(classificationResult.getAssignedClass());
+    assertNotNull(classificationResult.assignedClass());
     assertEquals(
-        "got an assigned class of " + classificationResult.getAssignedClass(),
+        "got an assigned class of " + classificationResult.assignedClass(),
         expectedResult,
-        classificationResult.getAssignedClass());
-    double score = classificationResult.getScore();
+        classificationResult.assignedClass());
+    double score = classificationResult.score();
     assertTrue("score should be between 0 and 1, got: " + score, score <= 1 && score >= 0);
     updateSampleIndex();
     ClassificationResult<T> secondClassificationResult = classifier.assignClass(inputDoc);
-    assertEquals(
-        classificationResult.getAssignedClass(), secondClassificationResult.getAssignedClass());
-    assertEquals(Double.valueOf(score), Double.valueOf(secondClassificationResult.getScore()));
+    assertEquals(classificationResult.assignedClass(), secondClassificationResult.assignedClass());
+    assertEquals(Double.valueOf(score), Double.valueOf(secondClassificationResult.score()));
   }
 
   protected LeafReader getSampleIndex(Analyzer analyzer) throws IOException {
diff --git a/lucene/classification/src/test/org/apache/lucene/classification/TestKNearestNeighborClassifier.java b/lucene/classification/src/test/org/apache/lucene/classification/TestKNearestNeighborClassifier.java
index f437dc57556..073703ae61e 100644
--- a/lucene/classification/src/test/org/apache/lucene/classification/TestKNearestNeighborClassifier.java
+++ b/lucene/classification/src/test/org/apache/lucene/classification/TestKNearestNeighborClassifier.java
@@ -88,7 +88,7 @@ public class TestKNearestNeighborClassifier extends ClassificationTestBase<Bytes
                   textFieldName),
               TECHNOLOGY_INPUT,
               TECHNOLOGY_RESULT);
-      assertTrue(resultDS.getScore() != resultLMS.getScore());
+      assertTrue(resultDS.score() != resultLMS.score());
     } finally {
       IOUtils.close(leafReader);
     }
@@ -113,7 +113,7 @@ public class TestKNearestNeighborClassifier extends ClassificationTestBase<Bytes
               leafReader, null, analyzer, null, 6, 1, 1, categoryFieldName, textFieldName);
       List<ClassificationResult<BytesRef>> classes =
           knnClassifier.getClasses(STRONG_TECHNOLOGY_INPUT);
-      assertTrue(classes.get(0).getScore() > classes.get(1).getScore());
+      assertTrue(classes.get(0).score() > classes.get(1).score());
       checkCorrectClassification(knnClassifier, STRONG_TECHNOLOGY_INPUT, TECHNOLOGY_RESULT);
     } finally {
       IOUtils.close(leafReader);
@@ -139,7 +139,7 @@ public class TestKNearestNeighborClassifier extends ClassificationTestBase<Bytes
               leafReader, null, analyzer, null, 3, 1, 1, categoryFieldName, textFieldName);
       List<ClassificationResult<BytesRef>> classes =
           knnClassifier.getClasses(SUPER_STRONG_TECHNOLOGY_INPUT);
-      assertTrue(classes.get(0).getScore() > classes.get(1).getScore());
+      assertTrue(classes.get(0).score() > classes.get(1).score());
       checkCorrectClassification(knnClassifier, SUPER_STRONG_TECHNOLOGY_INPUT, TECHNOLOGY_RESULT);
     } finally {
       IOUtils.close(leafReader);
diff --git a/lucene/classification/src/test/org/apache/lucene/classification/document/DocumentClassificationTestBase.java b/lucene/classification/src/test/org/apache/lucene/classification/document/DocumentClassificationTestBase.java
index 7e9fa45282d..5e944af3454 100644
--- a/lucene/classification/src/test/org/apache/lucene/classification/document/DocumentClassificationTestBase.java
+++ b/lucene/classification/src/test/org/apache/lucene/classification/document/DocumentClassificationTestBase.java
@@ -58,12 +58,12 @@ public abstract class DocumentClassificationTestBase<T> extends ClassificationTe
   protected double checkCorrectDocumentClassification(
       DocumentClassifier<T> classifier, Document inputDoc, T expectedResult) throws Exception {
     ClassificationResult<T> classificationResult = classifier.assignClass(inputDoc);
-    assertNotNull(classificationResult.getAssignedClass());
+    assertNotNull(classificationResult.assignedClass());
     assertEquals(
-        "got an assigned class of " + classificationResult.getAssignedClass(),
+        "got an assigned class of " + classificationResult.assignedClass(),
         expectedResult,
-        classificationResult.getAssignedClass());
-    double score = classificationResult.getScore();
+        classificationResult.assignedClass());
+    double score = classificationResult.score();
     assertTrue("score should be between 0 and 1, got:" + score, score <= 1 && score >= 0);
     return score;
   }
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/BlockTermsWriter.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/BlockTermsWriter.java
index 3784f4113b6..9fbde960083 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/BlockTermsWriter.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/BlockTermsWriter.java
@@ -69,28 +69,15 @@ public class BlockTermsWriter extends FieldsConsumer {
   private final TermsIndexWriterBase termsIndexWriter;
   private final int maxDoc;
 
-  private static class FieldMetaData {
-    public final FieldInfo fieldInfo;
-    public final long numTerms;
-    public final long termsStartPointer;
-    public final long sumTotalTermFreq;
-    public final long sumDocFreq;
-    public final int docCount;
-
-    public FieldMetaData(
-        FieldInfo fieldInfo,
-        long numTerms,
-        long termsStartPointer,
-        long sumTotalTermFreq,
-        long sumDocFreq,
-        int docCount) {
+  private record FieldMetaData(
+      FieldInfo fieldInfo,
+      long numTerms,
+      long termsStartPointer,
+      long sumTotalTermFreq,
+      long sumDocFreq,
+      int docCount) {
+    private FieldMetaData {
       assert numTerms > 0;
-      this.fieldInfo = fieldInfo;
-      this.termsStartPointer = termsStartPointer;
-      this.numTerms = numTerms;
-      this.sumTotalTermFreq = sumTotalTermFreq;
-      this.sumDocFreq = sumDocFreq;
-      this.docCount = docCount;
     }
   }
 
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/VariableGapTermsIndexWriter.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/VariableGapTermsIndexWriter.java
index 97a58a9ff97..ab0ad75ca8a 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/VariableGapTermsIndexWriter.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blockterms/VariableGapTermsIndexWriter.java
@@ -127,7 +127,7 @@ public class VariableGapTermsIndexWriter extends TermsIndexWriterBase {
 
     @Override
     public boolean isIndexTerm(BytesRef term, TermStats stats) {
-      if (stats.docFreq >= docFreqThresh || count >= interval) {
+      if (stats.docFreq() >= docFreqThresh || count >= interval) {
         count = 1;
         return true;
       } else {
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/FSTOrdsOutputs.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/FSTOrdsOutputs.java
index 9e83f261b04..286db291b0a 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/FSTOrdsOutputs.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/FSTOrdsOutputs.java
@@ -34,19 +34,14 @@ final class FSTOrdsOutputs extends Outputs<FSTOrdsOutputs.Output> {
 
   private static final BytesRef NO_BYTES = new BytesRef();
 
-  public static final class Output {
-    public final BytesRef bytes;
-    // Inclusive:
-    public final long startOrd;
-    // Inclusive:
-    public final long endOrd;
-
-    public Output(BytesRef bytes, long startOrd, long endOrd) {
+  /**
+   * @param startOrd Inclusive:
+   * @param endOrd Inclusive:
+   */
+  public record Output(BytesRef bytes, long startOrd, long endOrd) {
+    public Output {
       assert startOrd >= 0 : "startOrd=" + startOrd;
       assert endOrd >= 0 : "endOrd=" + endOrd;
-      this.bytes = bytes;
-      this.startOrd = startOrd;
-      this.endOrd = endOrd;
     }
 
     @Override
@@ -60,24 +55,6 @@ final class FSTOrdsOutputs extends Outputs<FSTOrdsOutputs.Output> {
       }
       return startOrd + " to " + x;
     }
-
-    @Override
-    public int hashCode() {
-      int hash = bytes.hashCode();
-      hash = (int) (hash ^ startOrd);
-      hash = (int) (hash ^ endOrd);
-      return hash;
-    }
-
-    @Override
-    public boolean equals(Object _other) {
-      if (_other instanceof Output) {
-        Output other = (Output) _other;
-        return bytes.equals(other.bytes) && startOrd == other.startOrd && endOrd == other.endOrd;
-      } else {
-        return false;
-      }
-    }
   }
 
   @Override
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsBlockTreeTermsWriter.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsBlockTreeTermsWriter.java
index fb6b0de56b7..852c06ae5de 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsBlockTreeTermsWriter.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsBlockTreeTermsWriter.java
@@ -139,38 +139,19 @@ public final class OrdsBlockTreeTermsWriter extends FieldsConsumer {
   final PostingsWriterBase postingsWriter;
   final FieldInfos fieldInfos;
 
-  private static class FieldMetaData {
-    public final FieldInfo fieldInfo;
-    public final Output rootCode;
-    public final long numTerms;
-    public final long indexStartFP;
-    public final long sumTotalTermFreq;
-    public final long sumDocFreq;
-    public final int docCount;
-    public final BytesRef minTerm;
-    public final BytesRef maxTerm;
-
-    public FieldMetaData(
-        FieldInfo fieldInfo,
-        Output rootCode,
-        long numTerms,
-        long indexStartFP,
-        long sumTotalTermFreq,
-        long sumDocFreq,
-        int docCount,
-        BytesRef minTerm,
-        BytesRef maxTerm) {
+  private record FieldMetaData(
+      FieldInfo fieldInfo,
+      Output rootCode,
+      long numTerms,
+      long indexStartFP,
+      long sumTotalTermFreq,
+      long sumDocFreq,
+      int docCount,
+      BytesRef minTerm,
+      BytesRef maxTerm) {
+    private FieldMetaData {
       assert numTerms > 0;
-      this.fieldInfo = fieldInfo;
       assert rootCode != null : "field=" + fieldInfo.name + " numTerms=" + numTerms;
-      this.rootCode = rootCode;
-      this.indexStartFP = indexStartFP;
-      this.numTerms = numTerms;
-      this.sumTotalTermFreq = sumTotalTermFreq;
-      this.sumDocFreq = sumDocFreq;
-      this.docCount = docCount;
-      this.minTerm = minTerm;
-      this.maxTerm = maxTerm;
     }
   }
 
@@ -293,15 +274,7 @@ public final class OrdsBlockTreeTermsWriter extends FieldsConsumer {
     }
   }
 
-  private static final class SubIndex {
-    public final FST<Output> index;
-    public final long termOrdStart;
-
-    public SubIndex(FST<Output> index, long termOrdStart) {
-      this.index = index;
-      this.termOrdStart = termOrdStart;
-    }
-  }
+  private record SubIndex(FST<Output> index, long termOrdStart) {}
 
   private static final class PendingBlock extends PendingEntry {
     public final BytesRef prefix;
@@ -438,7 +411,7 @@ public final class OrdsBlockTreeTermsWriter extends FieldsConsumer {
         // long blockTermCount = output.endOrd - output.startOrd + 1;
         Output newOutput =
             FST_OUTPUTS.newOutput(
-                output.bytes, termOrdOffset + output.startOrd, output.endOrd - termOrdOffset);
+                output.bytes(), termOrdOffset + output.startOrd(), output.endOrd() - termOrdOffset);
         // System.out.println("  append sub=" + indexEnt.input + " output=" + indexEnt.output +
         // " termOrdOffset=" + termOrdOffset + " blockTermCount=" + blockTermCount  + " newOutput="
         // + newOutput  + " endOrd=" + (termOrdOffset+Long.MAX_VALUE-output.endOrd));
@@ -969,9 +942,11 @@ public final class OrdsBlockTreeTermsWriter extends FieldsConsumer {
         out.writeVInt(field.fieldInfo.number);
         assert field.numTerms > 0;
         out.writeVLong(field.numTerms);
-        out.writeVInt(field.rootCode.bytes.length);
+        out.writeVInt(field.rootCode.bytes().length);
         out.writeBytes(
-            field.rootCode.bytes.bytes, field.rootCode.bytes.offset, field.rootCode.bytes.length);
+            field.rootCode.bytes().bytes,
+            field.rootCode.bytes().offset,
+            field.rootCode.bytes().length);
         if (field.fieldInfo.getIndexOptions() != IndexOptions.DOCS) {
           out.writeVLong(field.sumTotalTermFreq);
         }
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsFieldReader.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsFieldReader.java
index c3e2b0362f4..5f83f9e12a5 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsFieldReader.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsFieldReader.java
@@ -79,7 +79,8 @@ final class OrdsFieldReader extends Terms {
     // }
 
     rootBlockFP =
-        (new ByteArrayDataInput(rootCode.bytes.bytes, rootCode.bytes.offset, rootCode.bytes.length))
+        (new ByteArrayDataInput(
+                    rootCode.bytes().bytes, rootCode.bytes().offset, rootCode.bytes().length))
                 .readVLong()
             >>> OrdsBlockTreeTermsWriter.OUTPUT_FLAGS_NUM_BITS;
 
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsIntersectTermsEnumFrame.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsIntersectTermsEnumFrame.java
index 88e55362591..c5a1bfa58f5 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsIntersectTermsEnumFrame.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsIntersectTermsEnumFrame.java
@@ -142,8 +142,8 @@ final class OrdsIntersectTermsEnumFrame {
     // + frameIndexData + " trans=" + (transitions.length != 0 ? transitions[0] : "n/a" + " state="
     // + state));
 
-    if (output != null && output.bytes != null && transitionCount != 0) {
-      BytesRef frameIndexData = output.bytes;
+    if (output != null && output.bytes() != null && transitionCount != 0) {
+      BytesRef frameIndexData = output.bytes();
 
       // Floor frame
       if (floorData.length < frameIndexData.length) {
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsSegmentTermsEnum.java b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsSegmentTermsEnum.java
index 5b6771e7856..e6c297befc0 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsSegmentTermsEnum.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/blocktreeords/OrdsSegmentTermsEnum.java
@@ -149,7 +149,8 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
   // Pushes a frame we seek'd to
   OrdsSegmentTermsEnumFrame pushFrame(FST.Arc<Output> arc, Output frameData, int length)
       throws IOException {
-    scratchReader.reset(frameData.bytes.bytes, frameData.bytes.offset, frameData.bytes.length);
+    scratchReader.reset(
+        frameData.bytes().bytes, frameData.bytes().offset, frameData.bytes().length);
     final long code = scratchReader.readVLong();
     final long fpSeek = code >>> OrdsBlockTreeTermsWriter.OUTPUT_FLAGS_NUM_BITS;
     // System.out.println("    fpSeek=" + fpSeek);
@@ -160,11 +161,11 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
 
     // Must setFloorData before pushFrame in case pushFrame tries to rewind:
     if (f.isFloor) {
-      f.termOrdOrig = frameData.startOrd;
-      f.setFloorData(scratchReader, frameData.bytes);
+      f.termOrdOrig = frameData.startOrd();
+      f.setFloorData(scratchReader, frameData.bytes());
     }
 
-    pushFrame(arc, fpSeek, length, frameData.startOrd);
+    pushFrame(arc, fpSeek, length, frameData.startOrd());
 
     return f;
   }
@@ -891,7 +892,7 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
           } else if (isSeekFrame && !f.isFloor) {
             final ByteArrayDataInput reader =
                 new ByteArrayDataInput(
-                    output.bytes.bytes, output.bytes.offset, output.bytes.length);
+                    output.bytes().bytes, output.bytes().offset, output.bytes().length);
             final long codeOrig = reader.readVLong();
             final long code =
                 (f.fp << OrdsBlockTreeTermsWriter.OUTPUT_FLAGS_NUM_BITS)
@@ -1210,7 +1211,8 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
             OrdsBlockTreeTermsWriter.FST_OUTPUTS.add(output, arc.nextFinalOutput());
         // System.out.println("  isFinal: " + finalOutput.startOrd + "-" +
         // (Long.MAX_VALUE-finalOutput.endOrd));
-        if (targetOrd >= finalOutput.startOrd && targetOrd <= Long.MAX_VALUE - finalOutput.endOrd) {
+        if (targetOrd >= finalOutput.startOrd()
+            && targetOrd <= Long.MAX_VALUE - finalOutput.endOrd()) {
           // Only one range should match across all arc leaving this node
           // assert bestOutput == null;
           bestOutput = finalOutput;
@@ -1247,9 +1249,9 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
             }
             // System.out.println("  cycle mid=" + mid + " targetOrd=" + targetOrd + " output=" +
             // minArcOutput.startOrd + "-" + (Long.MAX_VALUE-minArcOutput.endOrd));
-            if (targetOrd > Long.MAX_VALUE - minArcOutput.endOrd) {
+            if (targetOrd > Long.MAX_VALUE - minArcOutput.endOrd()) {
               low = mid + 1;
-            } else if (targetOrd < minArcOutput.startOrd) {
+            } else if (targetOrd < minArcOutput.startOrd()) {
               high = mid - 1;
             } else {
               // System.out.println("    found!!");
@@ -1282,10 +1284,10 @@ public final class OrdsSegmentTermsEnum extends BaseTermsEnum {
             // this arc:
             final Output minArcOutput =
                 OrdsBlockTreeTermsWriter.FST_OUTPUTS.add(output, arc.output());
-            long endOrd = Long.MAX_VALUE - minArcOutput.endOrd;
+            long endOrd = Long.MAX_VALUE - minArcOutput.endOrd();
             // System.out.println("    endOrd=" + endOrd + " targetOrd=" + targetOrd);
 
-            if (targetOrd >= minArcOutput.startOrd && targetOrd <= endOrd) {
+            if (targetOrd >= minArcOutput.startOrd() && targetOrd <= endOrd) {
               // Recurse on this arc:
               output = minArcOutput;
               result.setIntAt(upto++, arc.label());
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDWriter.java b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDWriter.java
index 3190b47be01..042d2b77116 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDWriter.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextBKDWriter.java
@@ -1124,16 +1124,16 @@ final class SimpleTextBKDWriter implements Closeable {
       // least number of unique bytes at commonPrefixLengths[dim], which makes compression more
       // efficient
       HeapPointWriter heapSource;
-      if (points.writer instanceof HeapPointWriter == false) {
+      if (points.writer() instanceof HeapPointWriter == false) {
         // Adversarial cases can cause this, e.g. merging big segments with most of the points
         // deleted
-        heapSource = switchToHeap(points.writer);
+        heapSource = switchToHeap(points.writer());
       } else {
-        heapSource = (HeapPointWriter) points.writer;
+        heapSource = (HeapPointWriter) points.writer();
       }
 
-      int from = Math.toIntExact(points.start);
-      int to = Math.toIntExact(points.start + points.count);
+      int from = Math.toIntExact(points.start());
+      int to = Math.toIntExact(points.start() + points.count());
 
       // we store common prefix on scratch1
       computeCommonPrefixLength(heapSource, scratch1);
@@ -1220,8 +1220,8 @@ final class SimpleTextBKDWriter implements Closeable {
           : "nodeID=" + nodeID + " splitValues.length=" + splitPackedValues.length;
 
       // How many points will be in the left tree:
-      long rightCount = points.count / 2;
-      long leftCount = points.count - rightCount;
+      long rightCount = points.count() / 2;
+      long leftCount = points.count() - rightCount;
 
       int commonPrefixLen =
           Arrays.mismatch(
@@ -1241,9 +1241,9 @@ final class SimpleTextBKDWriter implements Closeable {
           radixSelector.select(
               points,
               pathSlices,
-              points.start,
-              points.start + points.count,
-              points.start + leftCount,
+              points.start(),
+              points.start() + points.count(),
+              points.start() + leftCount,
               splitDim,
               commonPrefixLen);
 
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextLiveDocsFormat.java b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextLiveDocsFormat.java
index 40d14f3368b..50e9bcb0c7e 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextLiveDocsFormat.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/simpletext/SimpleTextLiveDocsFormat.java
@@ -144,14 +144,7 @@ public class SimpleTextLiveDocsFormat extends LiveDocsFormat {
   }
 
   // read-only
-  static class SimpleTextBits implements Bits {
-    final BitSet bits;
-    final int size;
-
-    SimpleTextBits(BitSet bits, int size) {
-      this.bits = bits;
-      this.size = size;
-    }
+  record SimpleTextBits(BitSet bits, int size) implements Bits {
 
     @Override
     public boolean get(int index) {
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/FieldMetadataTermState.java b/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/FieldMetadataTermState.java
index 36d618752c3..83887656bc9 100644
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/FieldMetadataTermState.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/FieldMetadataTermState.java
@@ -25,13 +25,4 @@ import org.apache.lucene.codecs.uniformsplit.FieldMetadata;
  *
  * @lucene.experimental
  */
-public class FieldMetadataTermState {
-
-  public final FieldMetadata fieldMetadata;
-  public final BlockTermState state;
-
-  public FieldMetadataTermState(FieldMetadata fieldMetadata, BlockTermState state) {
-    this.fieldMetadata = fieldMetadata;
-    this.state = state;
-  }
-}
+public record FieldMetadataTermState(FieldMetadata fieldMetadata, BlockTermState state) {}
diff --git a/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/STBlockLine.java b/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/STBlockLine.java
index 49352fd1c47..fad572177a0 100755
--- a/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/STBlockLine.java
+++ b/lucene/codecs/src/java/org/apache/lucene/codecs/uniformsplit/sharedterms/STBlockLine.java
@@ -57,7 +57,7 @@ public class STBlockLine extends BlockLine {
    */
   public void collectFields(Collection<FieldMetadata> collector) {
     for (FieldMetadataTermState fieldTermState : termStates) {
-      collector.add(fieldTermState.fieldMetadata);
+      collector.add(fieldTermState.fieldMetadata());
     }
   }
 
@@ -82,13 +82,13 @@ public class STBlockLine extends BlockLine {
       assert size > 0 : "not valid block line with :" + size + " lines.";
       if (size == 1) {
         // When there is only 1 field, write its id as negative, followed by the field TermState.
-        int fieldID = line.termStates.get(0).fieldMetadata.getFieldInfo().number;
+        int fieldID = line.termStates.get(0).fieldMetadata().getFieldInfo().number;
         termStatesOutput.writeZInt(-fieldID);
         fieldMetadataTermState = line.termStates.get(0);
         encoder.writeTermState(
             termStatesOutput,
-            fieldMetadataTermState.fieldMetadata.getFieldInfo(),
-            fieldMetadataTermState.state);
+            fieldMetadataTermState.fieldMetadata().getFieldInfo(),
+            fieldMetadataTermState.state());
         return;
       }
 
@@ -96,15 +96,15 @@ public class STBlockLine extends BlockLine {
       // First iteration writes the fields ids.
       for (int i = 0; i < size; i++) {
         fieldMetadataTermState = line.termStates.get(i);
-        termStatesOutput.writeVInt(fieldMetadataTermState.fieldMetadata.getFieldInfo().number);
+        termStatesOutput.writeVInt(fieldMetadataTermState.fieldMetadata().getFieldInfo().number);
       }
       // Second iteration writes the corresponding field TermStates.
       for (int i = 0; i < size; i++) {
         fieldMetadataTermState = line.termStates.get(i);
         encoder.writeTermState(
             termStatesOutput,
-            fieldMetadataTermState.fieldMetadata.getFieldInfo(),
-            fieldMetadataTermState.state);
+            fieldMetadataTermState.fieldMetadata().getFieldInfo(),
+            fieldMetadataTermState.state());
       }
     }
 
diff --git a/lucene/codecs/src/test/org/apache/lucene/codecs/uniformsplit/sharedterms/TestSTBlockReader.java b/lucene/codecs/src/test/org/apache/lucene/codecs/uniformsplit/sharedterms/TestSTBlockReader.java
index 7a6524d77cd..89bee90f3a8 100644
--- a/lucene/codecs/src/test/org/apache/lucene/codecs/uniformsplit/sharedterms/TestSTBlockReader.java
+++ b/lucene/codecs/src/test/org/apache/lucene/codecs/uniformsplit/sharedterms/TestSTBlockReader.java
@@ -225,15 +225,7 @@ public class TestSTBlockReader extends LuceneTestCase {
     return lines;
   }
 
-  private static class BlockLineDefinition {
-    final TermBytes termBytes;
-    final List<String> fields;
-
-    BlockLineDefinition(TermBytes termBytes, List<String> fields) {
-      this.termBytes = termBytes;
-      this.fields = fields;
-    }
-  }
+  private record BlockLineDefinition(TermBytes termBytes, List<String> fields) {}
 
   private static class MockSTBlockLine extends STBlockLine {
 
diff --git a/lucene/core/src/java/org/apache/lucene/analysis/AutomatonToTokenStream.java b/lucene/core/src/java/org/apache/lucene/analysis/AutomatonToTokenStream.java
index d60d386ec5b..28493c168bc 100644
--- a/lucene/core/src/java/org/apache/lucene/analysis/AutomatonToTokenStream.java
+++ b/lucene/core/src/java/org/apache/lucene/analysis/AutomatonToTokenStream.java
@@ -170,24 +170,8 @@ public class AutomatonToTokenStream {
   }
 
   /** Edge between position nodes. These edges will be output as tokens in the TokenStream */
-  private static class EdgeToken {
-    public final int destination;
-    public final int value;
-
-    public EdgeToken(int destination, int value) {
-      this.destination = destination;
-      this.value = value;
-    }
-  }
+  private record EdgeToken(int destination, int value) {}
 
   /** Node that contains original node id and position in TokenStream */
-  private static class RemapNode {
-    public final int id;
-    public final int pos;
-
-    public RemapNode(int id, int pos) {
-      this.id = id;
-      this.pos = pos;
-    }
-  }
+  private record RemapNode(int id, int pos) {}
 }
diff --git a/lucene/core/src/java/org/apache/lucene/codecs/TermStats.java b/lucene/core/src/java/org/apache/lucene/codecs/TermStats.java
index 60c522e6d69..306f4e24617 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/TermStats.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/TermStats.java
@@ -16,24 +16,10 @@
  */
 package org.apache.lucene.codecs;
 
-import org.apache.lucene.index.TermsEnum; // javadocs
-
 /**
  * Holder for per-term statistics.
  *
- * @see TermsEnum#docFreq
- * @see TermsEnum#totalTermFreq
+ * @param docFreq How many documents have at least one occurrence of this term.
+ * @param totalTermFreq Total number of times this term occurs across all documents in the field.
  */
-public class TermStats {
-  /** How many documents have at least one occurrence of this term. */
-  public final int docFreq;
-
-  /** Total number of times this term occurs across all documents in the field. */
-  public final long totalTermFreq;
-
-  /** Sole constructor. */
-  public TermStats(int docFreq, long totalTermFreq) {
-    this.docFreq = docFreq;
-    this.totalTermFreq = totalTermFreq;
-  }
-}
+public record TermStats(int docFreq, long totalTermFreq) {}
diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/Lucene90CompoundFormat.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/Lucene90CompoundFormat.java
index 9851b0326bf..fd9ec5f9c28 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/Lucene90CompoundFormat.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/Lucene90CompoundFormat.java
@@ -104,15 +104,7 @@ public final class Lucene90CompoundFormat extends CompoundFormat {
     }
   }
 
-  private static class SizedFile {
-    private final String name;
-    private final long length;
-
-    private SizedFile(String name, long length) {
-      this.name = name;
-      this.length = length;
-    }
-  }
+  private record SizedFile(String name, long length) {}
 
   private static class SizedFileQueue extends PriorityQueue<SizedFile> {
     SizedFileQueue(int maxSize) {
diff --git a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingTermVectorsReader.java b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingTermVectorsReader.java
index b06da63153c..e84ca079cb4 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingTermVectorsReader.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/lucene90/compressing/Lucene90CompressingTermVectorsReader.java
@@ -325,17 +325,7 @@ public final class Lucene90CompressingTermVectorsReader extends TermVectorsReade
     return blockState.docBase <= docID && docID < blockState.docBase + blockState.chunkDocs;
   }
 
-  private static class BlockState {
-    final long startPointer;
-    final int docBase;
-    final int chunkDocs;
-
-    BlockState(long startPointer, int docBase, int chunkDocs) {
-      this.startPointer = startPointer;
-      this.docBase = docBase;
-      this.chunkDocs = chunkDocs;
-    }
-  }
+  private record BlockState(long startPointer, int docBase, int chunkDocs) {}
 
   @Override
   public Fields get(int doc) throws IOException {
diff --git a/lucene/core/src/java/org/apache/lucene/codecs/perfield/PerFieldKnnVectorsFormat.java b/lucene/core/src/java/org/apache/lucene/codecs/perfield/PerFieldKnnVectorsFormat.java
index e665528652c..5dc4db8db6a 100644
--- a/lucene/core/src/java/org/apache/lucene/codecs/perfield/PerFieldKnnVectorsFormat.java
+++ b/lucene/core/src/java/org/apache/lucene/codecs/perfield/PerFieldKnnVectorsFormat.java
@@ -299,14 +299,7 @@ public abstract class PerFieldKnnVectorsFormat extends KnnVectorsFormat {
     }
   }
 
-  private static class WriterAndSuffix implements Closeable {
-    final KnnVectorsWriter writer;
-    final int suffix;
-
-    WriterAndSuffix(KnnVectorsWriter writer, int suffix) {
-      this.writer = writer;
-      this.suffix = suffix;
-    }
+  private record WriterAndSuffix(KnnVectorsWriter writer, int suffix) implements Closeable {
 
     @Override
     public void close() throws IOException {
diff --git a/lucene/core/src/java/org/apache/lucene/document/NearestNeighbor.java b/lucene/core/src/java/org/apache/lucene/document/NearestNeighbor.java
index 12f4afffd0d..47a7d314637 100644
--- a/lucene/core/src/java/org/apache/lucene/document/NearestNeighbor.java
+++ b/lucene/core/src/java/org/apache/lucene/document/NearestNeighbor.java
@@ -35,30 +35,18 @@ import org.apache.lucene.util.SloppyMath;
 /** KNN search on top of 2D lat/lon indexed points. */
 class NearestNeighbor {
 
-  static class Cell implements Comparable<Cell> {
-    final int readerIndex;
-    final byte[] minPacked;
-    final byte[] maxPacked;
-    final PointTree index;
-
-    /**
-     * The closest distance from a point in this cell to the query point, computed as a sort key
-     * through {@link SloppyMath#haversinSortKey}. Note that this is an approximation to the closest
-     * distance, and there could be a point in the cell that is closer.
-     */
-    final double distanceSortKey;
-
-    public Cell(
-        PointTree index,
-        int readerIndex,
-        byte[] minPacked,
-        byte[] maxPacked,
-        double distanceSortKey) {
-      this.index = index;
-      this.readerIndex = readerIndex;
-      this.minPacked = minPacked.clone();
-      this.maxPacked = maxPacked.clone();
-      this.distanceSortKey = distanceSortKey;
+  /**
+   * @param distanceSortKey The closest distance from a point in this cell to the query point,
+   *     computed as a sort key through {@link SloppyMath#haversinSortKey}. Note that this is an
+   *     approximation to the closest distance, and there could be a point in the cell that is
+   *     closer.
+   */
+  record Cell(
+      PointTree index, int readerIndex, byte[] minPacked, byte[] maxPacked, double distanceSortKey)
+      implements Comparable<Cell> {
+    Cell {
+      minPacked = minPacked.clone();
+      maxPacked = maxPacked.clone();
     }
 
     @Override
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
index 0f32fe3da9e..3d339b91a0e 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedNumericDocValuesRangeQuery.java
@@ -194,7 +194,7 @@ final class SortedNumericDocValuesRangeQuery extends Query {
     if (skipper.docCount() != reader.maxDoc()) {
       return null;
     }
-    final Sort indexSort = reader.getMetaData().getSort();
+    final Sort indexSort = reader.getMetaData().sort();
     if (indexSort == null
         || indexSort.getSort().length == 0
         || indexSort.getSort()[0].getField().equals(field) == false) {
diff --git a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
index fb7e64df931..0ad8b1593c9 100644
--- a/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/document/SortedSetDocValuesRangeQuery.java
@@ -247,7 +247,7 @@ final class SortedSetDocValuesRangeQuery extends Query {
     if (skipper.docCount() != reader.maxDoc()) {
       return null;
     }
-    final Sort indexSort = reader.getMetaData().getSort();
+    final Sort indexSort = reader.getMetaData().sort();
     if (indexSort == null
         || indexSort.getSort().length == 0
         || indexSort.getSort()[0].getField().equals(field) == false) {
diff --git a/lucene/core/src/java/org/apache/lucene/index/BitsSlice.java b/lucene/core/src/java/org/apache/lucene/index/BitsSlice.java
index cf09c058140..ec8ccdaeb6d 100644
--- a/lucene/core/src/java/org/apache/lucene/index/BitsSlice.java
+++ b/lucene/core/src/java/org/apache/lucene/index/BitsSlice.java
@@ -32,8 +32,8 @@ final class BitsSlice implements Bits {
   // start is inclusive; end is exclusive (length = end-start)
   public BitsSlice(Bits parent, ReaderSlice slice) {
     this.parent = parent;
-    this.start = slice.start;
-    this.length = slice.length;
+    this.start = slice.start();
+    this.length = slice.length();
     assert length >= 0 : "length=" + length;
   }
 
diff --git a/lucene/core/src/java/org/apache/lucene/index/BufferedUpdatesStream.java b/lucene/core/src/java/org/apache/lucene/index/BufferedUpdatesStream.java
index d0ed8df6c09..817b0d057d7 100644
--- a/lucene/core/src/java/org/apache/lucene/index/BufferedUpdatesStream.java
+++ b/lucene/core/src/java/org/apache/lucene/index/BufferedUpdatesStream.java
@@ -114,19 +114,11 @@ final class BufferedUpdatesStream implements Accountable {
     return bytesUsed.get();
   }
 
-  static class ApplyDeletesResult {
-
-    // True if any actual deletes took place:
-    final boolean anyDeletes;
-
-    // If non-null, contains segments that are 100% deleted
-    final List<SegmentCommitInfo> allDeleted;
-
-    ApplyDeletesResult(boolean anyDeletes, List<SegmentCommitInfo> allDeleted) {
-      this.anyDeletes = anyDeletes;
-      this.allDeleted = allDeleted;
-    }
-  }
+  /**
+   * @param anyDeletes True if any actual deletes took place:
+   * @param allDeleted If non-null, contains segments that are 100% deleted
+   */
+  record ApplyDeletesResult(boolean anyDeletes, List<SegmentCommitInfo> allDeleted) {}
 
   /**
    * Waits for all in-flight packets, which are already being resolved concurrently by indexing
diff --git a/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java b/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java
index 65ac2fcd260..951d819c5c5 100644
--- a/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java
+++ b/lucene/core/src/java/org/apache/lucene/index/CheckIndex.java
@@ -1188,10 +1188,10 @@ public final class CheckIndex implements Closeable {
         FieldInfos fieldInfos = reader.getFieldInfos();
         if (metaData.hasBlocks()
             && fieldInfos.getParentField() == null
-            && metaData.getCreatedVersionMajor() >= Version.LUCENE_10_0_0.major) {
+            && metaData.createdVersionMajor() >= Version.LUCENE_10_0_0.major) {
           throw new IllegalStateException(
               "parent field is not set but the index has document blocks and was created with version: "
-                  + metaData.getCreatedVersionMajor());
+                  + metaData.createdVersionMajor());
         }
         final DocIdSetIterator iter;
         if (metaData.hasBlocks() && fieldInfos.getParentField() != null) {
@@ -3143,12 +3143,7 @@ public final class CheckIndex implements Closeable {
     }
   }
 
-  private static class ConstantRelationIntersectVisitor implements IntersectVisitor {
-    private final Relation relation;
-
-    ConstantRelationIntersectVisitor(Relation relation) {
-      this.relation = relation;
-    }
+  private record ConstantRelationIntersectVisitor(Relation relation) implements IntersectVisitor {
 
     @Override
     public void visit(int docID) throws IOException {
diff --git a/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java b/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java
index 83c2cbdaf1f..c5f4590dacb 100644
--- a/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java
+++ b/lucene/core/src/java/org/apache/lucene/index/IndexWriter.java
@@ -3118,22 +3118,22 @@ public class IndexWriter
 
   private void validateMergeReader(CodecReader leaf) {
     LeafMetaData segmentMeta = leaf.getMetaData();
-    if (segmentInfos.getIndexCreatedVersionMajor() != segmentMeta.getCreatedVersionMajor()) {
+    if (segmentInfos.getIndexCreatedVersionMajor() != segmentMeta.createdVersionMajor()) {
       throw new IllegalArgumentException(
           "Cannot merge a segment that has been created with major version "
-              + segmentMeta.getCreatedVersionMajor()
+              + segmentMeta.createdVersionMajor()
               + " into this index which has been created by major version "
               + segmentInfos.getIndexCreatedVersionMajor());
     }
 
-    if (segmentInfos.getIndexCreatedVersionMajor() >= 7 && segmentMeta.getMinVersion() == null) {
+    if (segmentInfos.getIndexCreatedVersionMajor() >= 7 && segmentMeta.minVersion() == null) {
       throw new IllegalStateException(
           "Indexes created on or after Lucene 7 must record the created version major, but "
               + leaf
               + " hides it");
     }
 
-    Sort leafIndexSort = segmentMeta.getSort();
+    Sort leafIndexSort = segmentMeta.sort();
     if (config.getIndexSort() != null
         && (leafIndexSort == null
             || isCongruentSort(config.getIndexSort(), leafIndexSort) == false)) {
@@ -6396,16 +6396,16 @@ public class IndexWriter
         deleter.decRef(delFiles);
       }
 
-      if (result.anyDeletes) {
+      if (result.anyDeletes()) {
         maybeMerge.set(true);
         checkpoint();
       }
 
-      if (result.allDeleted != null) {
+      if (result.allDeleted() != null) {
         if (infoStream.isEnabled("IW")) {
-          infoStream.message("IW", "drop 100% deleted segments: " + segString(result.allDeleted));
+          infoStream.message("IW", "drop 100% deleted segments: " + segString(result.allDeleted()));
         }
-        for (SegmentCommitInfo info : result.allDeleted) {
+        for (SegmentCommitInfo info : result.allDeleted()) {
           dropDeletedSegment(info);
         }
         checkpoint();
@@ -6532,12 +6532,7 @@ public class IndexWriter
     }
   }
 
-  private static class IndexWriterMergeSource implements MergeScheduler.MergeSource {
-    private final IndexWriter writer;
-
-    private IndexWriterMergeSource(IndexWriter writer) {
-      this.writer = writer;
-    }
+  private record IndexWriterMergeSource(IndexWriter writer) implements MergeScheduler.MergeSource {
 
     @Override
     public MergePolicy.OneMerge getNextMerge() {
diff --git a/lucene/core/src/java/org/apache/lucene/index/LeafMetaData.java b/lucene/core/src/java/org/apache/lucene/index/LeafMetaData.java
index 77a9f2a84b6..4d9f753e2e3 100644
--- a/lucene/core/src/java/org/apache/lucene/index/LeafMetaData.java
+++ b/lucene/core/src/java/org/apache/lucene/index/LeafMetaData.java
@@ -24,18 +24,29 @@ import org.apache.lucene.util.Version;
 /**
  * Provides read-only metadata about a leaf.
  *
+ * @param createdVersionMajor the Lucene version that created this index. This can be used to
+ *     implement backward compatibility on top of the codec API. A return value of {@code 6}
+ *     indicates that the created version is unknown.
+ * @param minVersion the minimum Lucene version that contributed documents to this index, or {@code
+ *     null} if this information is not available.
+ * @param sort the order in which documents from this index are sorted, or {@code null} if documents
+ *     are in no particular order.
+ * @param hasBlocks Returns <code>true</code> iff this index contains blocks created with {@link
+ *     IndexWriter#addDocument(Iterable)} or it's corresponding update methods with at least 2 or
+ *     more documents per call. Note: This property was not recorded before {@link
+ *     Version#LUCENE_9_9_0} this method will return false for all leaves written before {@link
+ *     Version#LUCENE_9_9_0}
+ * @see IndexWriter#updateDocuments(Term, Iterable)
+ * @see IndexWriter#updateDocuments(Query, Iterable)
+ * @see IndexWriter#softUpdateDocuments(Term, Iterable, Field...)
+ * @see IndexWriter#addDocuments(Iterable)
  * @lucene.experimental
  */
-public final class LeafMetaData {
-
-  private final int createdVersionMajor;
-  private final Version minVersion;
-  private final Sort sort;
-  private final boolean hasBlocks;
+public record LeafMetaData(
+    int createdVersionMajor, Version minVersion, Sort sort, boolean hasBlocks) {
 
   /** Expert: Sole constructor. Public for use by custom {@link LeafReader} impls. */
-  public LeafMetaData(int createdVersionMajor, Version minVersion, Sort sort, boolean hasBlocks) {
-    this.createdVersionMajor = createdVersionMajor;
+  public LeafMetaData {
     if (createdVersionMajor > Version.LATEST.major) {
       throw new IllegalArgumentException(
           "createdVersionMajor is in the future: " + createdVersionMajor);
@@ -47,48 +58,5 @@ public final class LeafMetaData {
     if (createdVersionMajor >= 7 && minVersion == null) {
       throw new IllegalArgumentException("minVersion must be set when createdVersionMajor is >= 7");
     }
-    this.minVersion = minVersion;
-    this.sort = sort;
-    this.hasBlocks = hasBlocks;
-  }
-
-  /**
-   * Get the Lucene version that created this index. This can be used to implement backward
-   * compatibility on top of the codec API. A return value of {@code 6} indicates that the created
-   * version is unknown.
-   */
-  public int getCreatedVersionMajor() {
-    return createdVersionMajor;
-  }
-
-  /**
-   * Return the minimum Lucene version that contributed documents to this index, or {@code null} if
-   * this information is not available.
-   */
-  public Version getMinVersion() {
-    return minVersion;
-  }
-
-  /**
-   * Return the order in which documents from this index are sorted, or {@code null} if documents
-   * are in no particular order.
-   */
-  public Sort getSort() {
-    return sort;
-  }
-
-  /**
-   * Returns <code>true</code> iff this index contains blocks created with {@link
-   * IndexWriter#addDocument(Iterable)} or it's corresponding update methods with at least 2 or more
-   * documents per call. Note: This property was not recorded before {@link Version#LUCENE_9_9_0}
-   * this method will return false for all leaves written before {@link Version#LUCENE_9_9_0}
-   *
-   * @see IndexWriter#updateDocuments(Term, Iterable)
-   * @see IndexWriter#updateDocuments(Query, Iterable)
-   * @see IndexWriter#softUpdateDocuments(Term, Iterable, Field...)
-   * @see IndexWriter#addDocuments(Iterable)
-   */
-  public boolean hasBlocks() {
-    return hasBlocks;
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/index/LogMergePolicy.java b/lucene/core/src/java/org/apache/lucene/index/LogMergePolicy.java
index a86809a1fb1..881ae099d5f 100644
--- a/lucene/core/src/java/org/apache/lucene/index/LogMergePolicy.java
+++ b/lucene/core/src/java/org/apache/lucene/index/LogMergePolicy.java
@@ -474,14 +474,8 @@ public abstract class LogMergePolicy extends MergePolicy {
     return spec;
   }
 
-  private static class SegmentInfoAndLevel implements Comparable<SegmentInfoAndLevel> {
-    final SegmentCommitInfo info;
-    final float level;
-
-    public SegmentInfoAndLevel(SegmentCommitInfo info, float level) {
-      this.info = info;
-      this.level = level;
-    }
+  private record SegmentInfoAndLevel(SegmentCommitInfo info, float level)
+      implements Comparable<SegmentInfoAndLevel> {
 
     // Sorts largest to smallest
     @Override
diff --git a/lucene/core/src/java/org/apache/lucene/index/MappingMultiPostingsEnum.java b/lucene/core/src/java/org/apache/lucene/index/MappingMultiPostingsEnum.java
index fdde920c191..f112354db62 100644
--- a/lucene/core/src/java/org/apache/lucene/index/MappingMultiPostingsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/MappingMultiPostingsEnum.java
@@ -68,7 +68,7 @@ final class MappingMultiPostingsEnum extends PostingsEnum {
     int count = postingsEnum.getNumSubs();
     subs.clear();
     for (int i = 0; i < count; i++) {
-      MappingPostingsSub sub = allSubs[subsArray[i].slice.readerIndex];
+      MappingPostingsSub sub = allSubs[subsArray[i].slice.readerIndex()];
       sub.postings = subsArray[i].postingsEnum;
       subs.add(sub);
     }
diff --git a/lucene/core/src/java/org/apache/lucene/index/MergeState.java b/lucene/core/src/java/org/apache/lucene/index/MergeState.java
index 31bdf7ce8d3..838699215f0 100644
--- a/lucene/core/src/java/org/apache/lucene/index/MergeState.java
+++ b/lucene/core/src/java/org/apache/lucene/index/MergeState.java
@@ -236,7 +236,7 @@ public class MergeState {
       return;
     }
     for (CodecReader leaf : readers) {
-      Sort segmentSort = leaf.getMetaData().getSort();
+      Sort segmentSort = leaf.getMetaData().sort();
       if (segmentSort == null || isCongruentSort(indexSort, segmentSort) == false) {
         throw new IllegalArgumentException(
             "index sort mismatch: merged segment has sort="
diff --git a/lucene/core/src/java/org/apache/lucene/index/MultiPostingsEnum.java b/lucene/core/src/java/org/apache/lucene/index/MultiPostingsEnum.java
index 3fe19b84979..f463860c078 100644
--- a/lucene/core/src/java/org/apache/lucene/index/MultiPostingsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/MultiPostingsEnum.java
@@ -115,7 +115,7 @@ public final class MultiPostingsEnum extends PostingsEnum {
       } else {
         upto++;
         current = subs[upto].postingsEnum;
-        currentBase = subs[upto].slice.start;
+        currentBase = subs[upto].slice.start();
       }
     }
   }
@@ -129,7 +129,7 @@ public final class MultiPostingsEnum extends PostingsEnum {
         } else {
           upto++;
           current = subs[upto].postingsEnum;
-          currentBase = subs[upto].slice.start;
+          currentBase = subs[upto].slice.start();
         }
       }
 
diff --git a/lucene/core/src/java/org/apache/lucene/index/MultiSorter.java b/lucene/core/src/java/org/apache/lucene/index/MultiSorter.java
index 9a8e48e5d3e..5c3c25be55e 100644
--- a/lucene/core/src/java/org/apache/lucene/index/MultiSorter.java
+++ b/lucene/core/src/java/org/apache/lucene/index/MultiSorter.java
@@ -70,10 +70,10 @@ final class MultiSorter {
         }
         if (metaData.hasBlocks()
             && fieldInfos.getParentField() == null
-            && metaData.getCreatedVersionMajor() >= Version.LUCENE_10_0_0.major) {
+            && metaData.createdVersionMajor() >= Version.LUCENE_10_0_0.major) {
           throw new CorruptIndexException(
               "parent field is not set but the index has blocks and uses index sorting. indexCreatedVersionMajor: "
-                  + metaData.getCreatedVersionMajor(),
+                  + metaData.createdVersionMajor(),
               "IndexingChain");
         }
       }
diff --git a/lucene/core/src/java/org/apache/lucene/index/MultiTermsEnum.java b/lucene/core/src/java/org/apache/lucene/index/MultiTermsEnum.java
index f4cbb4cc1f5..cb2fb84b4e3 100644
--- a/lucene/core/src/java/org/apache/lucene/index/MultiTermsEnum.java
+++ b/lucene/core/src/java/org/apache/lucene/index/MultiTermsEnum.java
@@ -370,7 +370,7 @@ public final class MultiTermsEnum extends BaseTermsEnum {
     public TermsEnumWithSlice(int index, ReaderSlice subSlice) {
       super(null, index);
       this.subSlice = subSlice;
-      assert subSlice.length >= 0 : "length=" + subSlice.length;
+      assert subSlice.length() >= 0 : "length=" + subSlice.length();
     }
 
     @Override
diff --git a/lucene/core/src/java/org/apache/lucene/index/ParallelLeafReader.java b/lucene/core/src/java/org/apache/lucene/index/ParallelLeafReader.java
index 1f1e2dba9c1..2a76f9e6358 100644
--- a/lucene/core/src/java/org/apache/lucene/index/ParallelLeafReader.java
+++ b/lucene/core/src/java/org/apache/lucene/index/ParallelLeafReader.java
@@ -128,7 +128,7 @@ public class ParallelLeafReader extends LeafReader {
     for (final LeafReader reader : this.parallelReaders) {
       LeafMetaData leafMetaData = reader.getMetaData();
 
-      Sort leafIndexSort = leafMetaData.getSort();
+      Sort leafIndexSort = leafMetaData.sort();
       if (indexSort == null) {
         indexSort = leafIndexSort;
       } else if (leafIndexSort != null && indexSort.equals(leafIndexSort) == false) {
@@ -140,13 +140,13 @@ public class ParallelLeafReader extends LeafReader {
       }
 
       if (createdVersionMajor == -1) {
-        createdVersionMajor = leafMetaData.getCreatedVersionMajor();
-      } else if (createdVersionMajor != leafMetaData.getCreatedVersionMajor()) {
+        createdVersionMajor = leafMetaData.createdVersionMajor();
+      } else if (createdVersionMajor != leafMetaData.createdVersionMajor()) {
         throw new IllegalArgumentException(
             "cannot combine LeafReaders that have different creation versions: saw both version="
                 + createdVersionMajor
                 + " and "
-                + leafMetaData.getCreatedVersionMajor());
+                + leafMetaData.createdVersionMajor());
       }
 
       final FieldInfos readerFieldInfos = reader.getFieldInfos();
@@ -177,7 +177,7 @@ public class ParallelLeafReader extends LeafReader {
     Version minVersion = Version.LATEST;
     boolean hasBlocks = false;
     for (final LeafReader reader : this.parallelReaders) {
-      Version leafVersion = reader.getMetaData().getMinVersion();
+      Version leafVersion = reader.getMetaData().minVersion();
       hasBlocks |= reader.getMetaData().hasBlocks();
       if (leafVersion == null) {
         minVersion = null;
diff --git a/lucene/core/src/java/org/apache/lucene/index/ReaderSlice.java b/lucene/core/src/java/org/apache/lucene/index/ReaderSlice.java
index eec6fb76221..ff54c392f14 100644
--- a/lucene/core/src/java/org/apache/lucene/index/ReaderSlice.java
+++ b/lucene/core/src/java/org/apache/lucene/index/ReaderSlice.java
@@ -19,31 +19,13 @@ package org.apache.lucene.index;
 /**
  * Subreader slice from a parent composite reader.
  *
+ * @param start Document ID this slice starts from.
+ * @param length Number of documents in this slice.
+ * @param readerIndex Sub-reader index for this slice.
  * @lucene.internal
  */
-public final class ReaderSlice {
+public record ReaderSlice(int start, int length, int readerIndex) {
 
   /** Zero-length {@code ReaderSlice} array. */
   public static final ReaderSlice[] EMPTY_ARRAY = new ReaderSlice[0];
-
-  /** Document ID this slice starts from. */
-  public final int start;
-
-  /** Number of documents in this slice. */
-  public final int length;
-
-  /** Sub-reader index for this slice. */
-  public final int readerIndex;
-
-  /** Sole constructor. */
-  public ReaderSlice(int start, int length, int readerIndex) {
-    this.start = start;
-    this.length = length;
-    this.readerIndex = readerIndex;
-  }
-
-  @Override
-  public String toString() {
-    return "slice start=" + start + " length=" + length + " readerIndex=" + readerIndex;
-  }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java b/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java
index c2299427fa2..b8cb694a530 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SegmentMerger.java
@@ -74,7 +74,7 @@ final class SegmentMerger {
     this.fieldInfosBuilder = new FieldInfos.Builder(fieldNumbers);
     Version minVersion = Version.LATEST;
     for (CodecReader reader : readers) {
-      Version leafMinVersion = reader.getMetaData().getMinVersion();
+      Version leafMinVersion = reader.getMetaData().minVersion();
       if (leafMinVersion == null) {
         minVersion = null;
         break;
diff --git a/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java b/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java
index d4140343e6e..6d8342908ef 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SlowCompositeCodecReaderWrapper.java
@@ -80,15 +80,15 @@ final class SlowCompositeCodecReaderWrapper extends CodecReader {
     for (CodecReader reader : codecReaders) {
       LeafMetaData readerMeta = reader.getMetaData();
       if (majorVersion == -1) {
-        majorVersion = readerMeta.getCreatedVersionMajor();
-      } else if (majorVersion != readerMeta.getCreatedVersionMajor()) {
+        majorVersion = readerMeta.createdVersionMajor();
+      } else if (majorVersion != readerMeta.createdVersionMajor()) {
         throw new IllegalArgumentException(
             "Cannot combine leaf readers created with different major versions");
       }
       if (minVersion == null) {
-        minVersion = readerMeta.getMinVersion();
-      } else if (minVersion.onOrAfter(readerMeta.getMinVersion())) {
-        minVersion = readerMeta.getMinVersion();
+        minVersion = readerMeta.minVersion();
+      } else if (minVersion.onOrAfter(readerMeta.minVersion())) {
+        minVersion = readerMeta.minVersion();
       }
       hasBlocks |= readerMeta.hasBlocks();
     }
@@ -293,17 +293,7 @@ final class SlowCompositeCodecReaderWrapper extends CodecReader {
     }
   }
 
-  private static class DocValuesSub<T extends DocIdSetIterator> {
-    private final T sub;
-    private final int docStart;
-    private final int docEnd;
-
-    DocValuesSub(T sub, int docStart, int docEnd) {
-      this.sub = sub;
-      this.docStart = docStart;
-      this.docEnd = docEnd;
-    }
-  }
+  private record DocValuesSub<T extends DocIdSetIterator>(T sub, int docStart, int docEnd) {}
 
   private static class MergedDocIdSetIterator<T extends DocIdSetIterator> extends DocIdSetIterator {
 
@@ -564,11 +554,8 @@ final class SlowCompositeCodecReaderWrapper extends CodecReader {
     return new SlowCompositePointsReaderWrapper(codecReaders, docStarts);
   }
 
-  private static class PointValuesSub {
-    private final PointValues sub;
-    private final int docBase;
-
-    PointValuesSub(PointValues sub, int docBase) {
+  private record PointValuesSub(PointValues sub, int docBase) {
+    private PointValuesSub(PointValues sub, int docBase) {
       this.sub = Objects.requireNonNull(sub);
       this.docBase = docBase;
     }
diff --git a/lucene/core/src/java/org/apache/lucene/index/Sorter.java b/lucene/core/src/java/org/apache/lucene/index/Sorter.java
index 741dfc6944a..619496d108d 100644
--- a/lucene/core/src/java/org/apache/lucene/index/Sorter.java
+++ b/lucene/core/src/java/org/apache/lucene/index/Sorter.java
@@ -222,10 +222,10 @@ public final class Sorter {
     }
     if (metaData.hasBlocks()
         && fieldInfos.getParentField() == null
-        && metaData.getCreatedVersionMajor() >= Version.LUCENE_10_0_0.major) {
+        && metaData.createdVersionMajor() >= Version.LUCENE_10_0_0.major) {
       throw new CorruptIndexException(
           "parent field is not set but the index has blocks. indexCreatedVersionMajor: "
-              + metaData.getCreatedVersionMajor(),
+              + metaData.createdVersionMajor(),
           "Sorter");
     }
 
diff --git a/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java b/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java
index ff88e30de4a..191111c0ad3 100644
--- a/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java
+++ b/lucene/core/src/java/org/apache/lucene/index/SortingCodecReader.java
@@ -52,15 +52,7 @@ import org.apache.lucene.util.packed.PackedInts;
  */
 public final class SortingCodecReader extends FilterCodecReader {
 
-  private static class SortingBits implements Bits {
-
-    private final Bits in;
-    private final Sorter.DocMap docMap;
-
-    SortingBits(final Bits in, Sorter.DocMap docMap) {
-      this.in = in;
-      this.docMap = docMap;
-    }
+  private record SortingBits(Bits in, Sorter.DocMap docMap) implements Bits {
 
     @Override
     public boolean get(int index) {
@@ -349,10 +341,7 @@ public final class SortingCodecReader extends FilterCodecReader {
     LeafMetaData metaData = reader.getMetaData();
     LeafMetaData newMetaData =
         new LeafMetaData(
-            metaData.getCreatedVersionMajor(),
-            metaData.getMinVersion(),
-            sort,
-            metaData.hasBlocks());
+            metaData.createdVersionMajor(), metaData.minVersion(), sort, metaData.hasBlocks());
     if (docMap == null) {
       // the reader is already sorted
       return new FilterCodecReader(reader) {
@@ -744,8 +733,8 @@ public final class SortingCodecReader extends FilterCodecReader {
       boolean isSortField = false;
       // For things that aren't sort fields, it's possible for sort to be null here
       // In the event that we accidentally cache twice, its better not to throw an NPE
-      if (metaData.getSort() != null) {
-        for (SortField sf : metaData.getSort().getSort()) {
+      if (metaData.sort() != null) {
+        for (SortField sf : metaData.sort().getSort()) {
           if (field.equals(sf.getField())) {
             isSortField = true;
             break;
diff --git a/lucene/core/src/java/org/apache/lucene/search/CollectionStatistics.java b/lucene/core/src/java/org/apache/lucene/search/CollectionStatistics.java
index d424abca078..ba118fa5452 100644
--- a/lucene/core/src/java/org/apache/lucene/search/CollectionStatistics.java
+++ b/lucene/core/src/java/org/apache/lucene/search/CollectionStatistics.java
@@ -17,8 +17,6 @@
 package org.apache.lucene.search;
 
 import java.util.Objects;
-import org.apache.lucene.index.IndexReader; // javadocs
-import org.apache.lucene.index.Terms; // javadocs
 
 /**
  * Contains statistics for a collection (field).
@@ -45,31 +43,41 @@ import org.apache.lucene.index.Terms; // javadocs
  * <p>Be careful when performing calculations on these values because they are represented as 64-bit
  * integer values, you may need to cast to {@code double} for your use.
  *
+ * @param field Field's name.
+ *     <p>This value is never {@code null}.
+ * @param maxDoc The total number of documents in the range [1 .. {@link Long#MAX_VALUE}],
+ *     regardless of whether they all contain values for this field.
+ *     <p>This value is always a positive number. @see IndexReader#maxDoc()
+ * @param docCount The total number of documents that have at least one term for this field , in the
+ *     range [1 .. {@link #maxDoc()}].
+ *     <p>This value is always a positive number, and never exceeds {@link #maxDoc()}. @see
+ *     Terms#getDocCount()
+ * @param sumTotalTermFreq The total number of tokens for this field , in the range [{@link
+ *     #sumDocFreq()} .. {@link Long#MAX_VALUE}]. This is the "word count" for this field across all
+ *     documents. It is the sum of {@link TermStatistics#totalTermFreq()} across all terms. It is
+ *     also the sum of each document's field length across all documents.
+ *     <p>This value is always a positive number, and always at least {@link #sumDocFreq()}. @see
+ *     Terms#getSumTotalTermFreq()
+ * @param sumDocFreq The total number of posting list entries for this field, in the range [{@link
+ *     #docCount()} .. {@link #sumTotalTermFreq()}]. This is the sum of term-document pairs: the sum
+ *     of {@link TermStatistics#docFreq()} across all terms. It is also the sum of each document's
+ *     unique term count for this field across all documents.
+ *     <p>This value is always a positive number, always at least {@link #docCount()}, and never
+ *     exceeds {@link #sumTotalTermFreq()}. @see Terms#getSumDocFreq()
  * @lucene.experimental
  */
-public class CollectionStatistics {
-  private final String field;
-  private final long maxDoc;
-  private final long docCount;
-  private final long sumTotalTermFreq;
-  private final long sumDocFreq;
-
+public record CollectionStatistics(
+    String field, long maxDoc, long docCount, long sumTotalTermFreq, long sumDocFreq) {
   /**
    * Creates statistics instance for a collection (field).
    *
-   * @param field Field's name
-   * @param maxDoc total number of documents.
-   * @param docCount number of documents containing the field.
-   * @param sumTotalTermFreq number of tokens in the field.
-   * @param sumDocFreq number of postings list entries for the field.
    * @throws IllegalArgumentException if {@code maxDoc} is negative or zero.
    * @throws IllegalArgumentException if {@code docCount} is negative or zero.
    * @throws IllegalArgumentException if {@code docCount} is more than {@code maxDoc}.
    * @throws IllegalArgumentException if {@code sumDocFreq} is less than {@code docCount}.
    * @throws IllegalArgumentException if {@code sumTotalTermFreq} is less than {@code sumDocFreq}.
    */
-  public CollectionStatistics(
-      String field, long maxDoc, long docCount, long sumTotalTermFreq, long sumDocFreq) {
+  public CollectionStatistics {
     Objects.requireNonNull(field);
     if (maxDoc <= 0) {
       throw new IllegalArgumentException("maxDoc must be positive, maxDoc: " + maxDoc);
@@ -102,94 +110,5 @@ public class CollectionStatistics {
               + ", sumDocFreq: "
               + sumDocFreq);
     }
-    this.field = field;
-    this.maxDoc = maxDoc;
-    this.docCount = docCount;
-    this.sumTotalTermFreq = sumTotalTermFreq;
-    this.sumDocFreq = sumDocFreq;
-  }
-
-  /**
-   * The field's name.
-   *
-   * <p>This value is never {@code null}.
-   *
-   * @return field's name, not {@code null}
-   */
-  public final String field() {
-    return field;
-  }
-
-  /**
-   * The total number of documents, regardless of whether they all contain values for this field.
-   *
-   * <p>This value is always a positive number.
-   *
-   * @return total number of documents, in the range [1 .. {@link Long#MAX_VALUE}]
-   * @see IndexReader#maxDoc()
-   */
-  public final long maxDoc() {
-    return maxDoc;
-  }
-
-  /**
-   * The total number of documents that have at least one term for this field.
-   *
-   * <p>This value is always a positive number, and never exceeds {@link #maxDoc()}.
-   *
-   * @return total number of documents containing this field, in the range [1 .. {@link #maxDoc()}]
-   * @see Terms#getDocCount()
-   */
-  public final long docCount() {
-    return docCount;
-  }
-
-  /**
-   * The total number of tokens for this field. This is the "word count" for this field across all
-   * documents. It is the sum of {@link TermStatistics#totalTermFreq()} across all terms. It is also
-   * the sum of each document's field length across all documents.
-   *
-   * <p>This value is always a positive number, and always at least {@link #sumDocFreq()}.
-   *
-   * @return total number of tokens in the field, in the range [{@link #sumDocFreq()} .. {@link
-   *     Long#MAX_VALUE}]
-   * @see Terms#getSumTotalTermFreq()
-   */
-  public final long sumTotalTermFreq() {
-    return sumTotalTermFreq;
-  }
-
-  /**
-   * The total number of posting list entries for this field. This is the sum of term-document
-   * pairs: the sum of {@link TermStatistics#docFreq()} across all terms. It is also the sum of each
-   * document's unique term count for this field across all documents.
-   *
-   * <p>This value is always a positive number, always at least {@link #docCount()}, and never
-   * exceeds {@link #sumTotalTermFreq()}.
-   *
-   * @return number of posting list entries, in the range [{@link #docCount()} .. {@link
-   *     #sumTotalTermFreq()}]
-   * @see Terms#getSumDocFreq()
-   */
-  public final long sumDocFreq() {
-    return sumDocFreq;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder sb = new StringBuilder();
-    sb.append("field=");
-    sb.append('"');
-    sb.append(field());
-    sb.append('"');
-    sb.append(",maxDoc=");
-    sb.append(maxDoc());
-    sb.append(",docCount=");
-    sb.append(docCount());
-    sb.append(",sumTotalTermFreq=");
-    sb.append(sumTotalTermFreq());
-    sb.append(",sumDocFreq=");
-    sb.append(sumDocFreq);
-    return sb.toString();
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
index 0c27e4de83f..e8b341cdcfb 100644
--- a/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/IndexSortSortedNumericDocValuesRangeQuery.java
@@ -398,7 +398,7 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
 
   private IteratorAndCount getDocIdSetIteratorOrNullFromBkd(
       LeafReaderContext context, DocIdSetIterator delegate) throws IOException {
-    Sort indexSort = context.reader().getMetaData().getSort();
+    Sort indexSort = context.reader().getMetaData().sort();
     if (indexSort == null
         || indexSort.getSort().length == 0
         || indexSort.getSort()[0].getField().equals(field) == false) {
@@ -498,7 +498,7 @@ public class IndexSortSortedNumericDocValuesRangeQuery extends Query {
       if (itAndCount != null) {
         return itAndCount;
       }
-      Sort indexSort = context.reader().getMetaData().getSort();
+      Sort indexSort = context.reader().getMetaData().sort();
       if (indexSort != null
           && indexSort.getSort().length > 0
           && indexSort.getSort()[0].getField().equals(field)) {
diff --git a/lucene/core/src/java/org/apache/lucene/search/MaxScoreAccumulator.java b/lucene/core/src/java/org/apache/lucene/search/MaxScoreAccumulator.java
index b0f60f8113f..b61940ee67b 100644
--- a/lucene/core/src/java/org/apache/lucene/search/MaxScoreAccumulator.java
+++ b/lucene/core/src/java/org/apache/lucene/search/MaxScoreAccumulator.java
@@ -17,7 +17,6 @@
 
 package org.apache.lucene.search;
 
-import java.util.Objects;
 import java.util.concurrent.atomic.LongAccumulator;
 
 /** Maintains the maximum score and its corresponding document id concurrently */
@@ -68,14 +67,7 @@ final class MaxScoreAccumulator {
     return new DocAndScore(docBase, score);
   }
 
-  static class DocAndScore implements Comparable<DocAndScore> {
-    final int docBase;
-    final float score;
-
-    DocAndScore(int docBase, float score) {
-      this.docBase = docBase;
-      this.score = score;
-    }
+  record DocAndScore(int docBase, float score) implements Comparable<DocAndScore> {
 
     @Override
     public int compareTo(DocAndScore o) {
@@ -101,11 +93,6 @@ final class MaxScoreAccumulator {
       return docBase == result.docBase && Float.compare(result.score, score) == 0;
     }
 
-    @Override
-    public int hashCode() {
-      return Objects.hash(docBase, score);
-    }
-
     @Override
     public String toString() {
       return "DocAndScore{" + "docBase=" + docBase + ", score=" + score + '}';
diff --git a/lucene/core/src/java/org/apache/lucene/search/Scorable.java b/lucene/core/src/java/org/apache/lucene/search/Scorable.java
index 6fd531e7d84..cfa0f49b6ad 100644
--- a/lucene/core/src/java/org/apache/lucene/search/Scorable.java
+++ b/lucene/core/src/java/org/apache/lucene/search/Scorable.java
@@ -66,23 +66,12 @@ public abstract class Scorable {
    * A child Scorer and its relationship to its parent. The meaning of the relationship depends upon
    * the parent query.
    *
+   * <p>The relationship can be any string that makes sense to the parent Scorer.
+   *
+   * @param child Child Scorer. (note this is typically a direct child, and may itself also have
+   *     children).
+   * @param relationship An arbitrary string relating this scorer to the parent.
    * @lucene.experimental
    */
-  public static class ChildScorable {
-    /** Child Scorer. (note this is typically a direct child, and may itself also have children). */
-    public final Scorable child;
-
-    /** An arbitrary string relating this scorer to the parent. */
-    public final String relationship;
-
-    /**
-     * Creates a new ChildScorer node with the specified relationship.
-     *
-     * <p>The relationship can be any string that makes sense to the parent Scorer.
-     */
-    public ChildScorable(Scorable child, String relationship) {
-      this.child = child;
-      this.relationship = relationship;
-    }
-  }
+  public record ChildScorable(Scorable child, String relationship) {}
 }
diff --git a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
index 82a3b6e0148..360fc854140 100644
--- a/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
+++ b/lucene/core/src/java/org/apache/lucene/search/SynonymQuery.java
@@ -686,26 +686,5 @@ public final class SynonymQuery extends Query {
     }
   }
 
-  private static class TermAndBoost {
-    final BytesRef term;
-    final float boost;
-
-    TermAndBoost(BytesRef term, float boost) {
-      this.term = term;
-      this.boost = boost;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-      TermAndBoost that = (TermAndBoost) o;
-      return Float.compare(that.boost, boost) == 0 && Objects.equals(term, that.term);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(term, boost);
-    }
-  }
+  private record TermAndBoost(BytesRef term, float boost) {}
 }
diff --git a/lucene/core/src/java/org/apache/lucene/search/TermStatistics.java b/lucene/core/src/java/org/apache/lucene/search/TermStatistics.java
index 9f24ed23b5e..aeca533e9ba 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TermStatistics.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TermStatistics.java
@@ -17,8 +17,6 @@
 package org.apache.lucene.search;
 
 import java.util.Objects;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.index.TermsEnum; // javadocs
 import org.apache.lucene.util.BytesRef;
 
 /**
@@ -45,27 +43,34 @@ import org.apache.lucene.util.BytesRef;
  * <p>Be careful when performing calculations on these values because they are represented as 64-bit
  * integer values, you may need to cast to {@code double} for your use.
  *
+ * @param term Term bytes.
+ *     <p>This value is never {@code null}.
+ * @param docFreq number of documents containing the term in the collection, in the range [1 ..
+ *     {@link #totalTermFreq()}].
+ *     <p>This is the document-frequency for the term: the count of documents where the term appears
+ *     at least one time.
+ *     <p>This value is always a positive number, and never exceeds {@link #totalTermFreq}. It also
+ *     cannot exceed {@link CollectionStatistics#sumDocFreq()}. @see TermsEnum#docFreq()
+ * @param totalTermFreq number of occurrences of the term in the collection, in the range [{@link
+ *     #docFreq()} .. {@link CollectionStatistics#sumTotalTermFreq()}].
+ *     <p>This is the token count for the term: the number of times it appears in the field across
+ *     all documents.
+ *     <p>This value is always a positive number, always at least {@link #docFreq()}, and never
+ *     exceeds {@link CollectionStatistics#sumTotalTermFreq()}. @see TermsEnum#totalTermFreq()
  * @lucene.experimental
  */
 // TODO: actually add missing cross-checks to guarantee TermStatistics is in bounds of
 // CollectionStatistics,
 // otherwise many similarity functions will implode.
-public class TermStatistics {
-  private final BytesRef term;
-  private final long docFreq;
-  private final long totalTermFreq;
-
+public record TermStatistics(BytesRef term, long docFreq, long totalTermFreq) {
   /**
    * Creates statistics instance for a term.
    *
-   * @param term Term bytes
-   * @param docFreq number of documents containing the term in the collection.
-   * @param totalTermFreq number of occurrences of the term in the collection.
    * @throws NullPointerException if {@code term} is {@code null}.
    * @throws IllegalArgumentException if {@code docFreq} is negative or zero.
    * @throws IllegalArgumentException if {@code totalTermFreq} is less than {@code docFreq}.
    */
-  public TermStatistics(BytesRef term, long docFreq, long totalTermFreq) {
+  public TermStatistics {
     Objects.requireNonNull(term);
     if (docFreq <= 0) {
       throw new IllegalArgumentException("docFreq must be positive, docFreq: " + docFreq);
@@ -81,66 +86,5 @@ public class TermStatistics {
               + ", docFreq: "
               + docFreq);
     }
-    this.term = term;
-    this.docFreq = docFreq;
-    this.totalTermFreq = totalTermFreq;
-  }
-
-  /**
-   * The term text.
-   *
-   * <p>This value is never {@code null}.
-   *
-   * @return term's text, not {@code null}
-   */
-  public final BytesRef term() {
-    return term;
-  }
-
-  /**
-   * The number of documents this term occurs in.
-   *
-   * <p>This is the document-frequency for the term: the count of documents where the term appears
-   * at least one time.
-   *
-   * <p>This value is always a positive number, and never exceeds {@link #totalTermFreq}. It also
-   * cannot exceed {@link CollectionStatistics#sumDocFreq()}.
-   *
-   * @return document frequency, in the range [1 .. {@link #totalTermFreq()}]
-   * @see TermsEnum#docFreq()
-   */
-  public final long docFreq() {
-    return docFreq;
-  }
-
-  /**
-   * The total number of occurrences of this term.
-   *
-   * <p>This is the token count for the term: the number of times it appears in the field across all
-   * documents.
-   *
-   * <p>This value is always a positive number, always at least {@link #docFreq()}, and never
-   * exceeds {@link CollectionStatistics#sumTotalTermFreq()}.
-   *
-   * @return number of occurrences, in the range [{@link #docFreq()} .. {@link
-   *     CollectionStatistics#sumTotalTermFreq()}]
-   * @see TermsEnum#totalTermFreq()
-   */
-  public final long totalTermFreq() {
-    return totalTermFreq;
-  }
-
-  @Override
-  public String toString() {
-    StringBuilder sb = new StringBuilder();
-    sb.append("term=");
-    sb.append('"');
-    sb.append(Term.toString(term()));
-    sb.append('"');
-    sb.append(",docFreq=");
-    sb.append(docFreq());
-    sb.append(",totalTermFreq=");
-    sb.append(totalTermFreq());
-    return sb.toString();
   }
 }
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
index 7caf34c95f2..114797f44cb 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopFieldCollector.java
@@ -54,7 +54,7 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
       // as all segments are sorted in the same way, enough to check only the 1st segment for
       // indexSort
       if (searchSortPartOfIndexSort == null) {
-        final Sort indexSort = context.reader().getMetaData().getSort();
+        final Sort indexSort = context.reader().getMetaData().sort();
         searchSortPartOfIndexSort = canEarlyTerminate(sort, indexSort);
         if (searchSortPartOfIndexSort) {
           firstComparator.disableSkipping();
@@ -367,9 +367,9 @@ public abstract class TopFieldCollector extends TopDocsCollector<Entry> {
       // if the local queue is not full because the threshold
       // is reached.
       DocAndScore maxMinScore = minScoreAcc.get();
-      if (maxMinScore != null && maxMinScore.score > minCompetitiveScore) {
-        scorer.setMinCompetitiveScore(maxMinScore.score);
-        minCompetitiveScore = maxMinScore.score;
+      if (maxMinScore != null && maxMinScore.score() > minCompetitiveScore) {
+        scorer.setMinCompetitiveScore(maxMinScore.score());
+        minCompetitiveScore = maxMinScore.score();
         totalHitsRelation = TotalHits.Relation.GREATER_THAN_OR_EQUAL_TO;
       }
     }
diff --git a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
index f74f087b7d5..77cb21ec577 100644
--- a/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
+++ b/lucene/core/src/java/org/apache/lucene/search/TopScoreDocCollector.java
@@ -232,7 +232,7 @@ public abstract class TopScoreDocCollector extends TopDocsCollector<ScoreDoc> {
       // the next float if the global minimum score is set on a document id that is
       // smaller than the ids in the current leaf
       float score =
-          docBase >= maxMinScore.docBase ? Math.nextUp(maxMinScore.score) : maxMinScore.score;
+          docBase >= maxMinScore.docBase() ? Math.nextUp(maxMinScore.score()) : maxMinScore.score();
       if (score > minCompetitiveScore) {
         assert hitsThresholdChecker.isThresholdReached();
         scorer.setMinCompetitiveScore(score);
diff --git a/lucene/core/src/java/org/apache/lucene/search/comparators/TermOrdValComparator.java b/lucene/core/src/java/org/apache/lucene/search/comparators/TermOrdValComparator.java
index 31199c3cd2c..ebe4fb2f956 100644
--- a/lucene/core/src/java/org/apache/lucene/search/comparators/TermOrdValComparator.java
+++ b/lucene/core/src/java/org/apache/lucene/search/comparators/TermOrdValComparator.java
@@ -464,15 +464,7 @@ public class TermOrdValComparator extends FieldComparator<BytesRef> {
     }
   }
 
-  private static class PostingsEnumAndOrd {
-    private final PostingsEnum postings;
-    private final int ord;
-
-    PostingsEnumAndOrd(PostingsEnum postings, int ord) {
-      this.postings = postings;
-      this.ord = ord;
-    }
-  }
+  private record PostingsEnumAndOrd(PostingsEnum postings, int ord) {}
 
   private class CompetitiveIterator extends DocIdSetIterator {
 
diff --git a/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java b/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
index 5dcc3a6ee53..b95ba73f449 100644
--- a/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
+++ b/lucene/core/src/java/org/apache/lucene/util/QueryBuilder.java
@@ -62,18 +62,16 @@ public class QueryBuilder {
   protected boolean enableGraphQueries = true;
   protected boolean autoGenerateMultiTermSynonymsPhraseQuery = false;
 
-  /** Wraps a term and boost */
-  public static class TermAndBoost {
-    /** the term */
-    public final BytesRef term;
-
-    /** the boost */
-    public final float boost;
-
+  /**
+   * Wraps a term and boost
+   *
+   * @param term the term
+   * @param boost the boost
+   */
+  public record TermAndBoost(BytesRef term, float boost) {
     /** Creates a new TermAndBoost */
-    public TermAndBoost(BytesRef term, float boost) {
-      this.term = BytesRef.deepCopyOf(term);
-      this.boost = boost;
+    public TermAndBoost {
+      term = BytesRef.deepCopyOf(term);
     }
   }
 
diff --git a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDRadixSelector.java b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDRadixSelector.java
index 5dc6658b888..7d0bb3c6fd5 100644
--- a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDRadixSelector.java
+++ b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDRadixSelector.java
@@ -582,20 +582,5 @@ public final class BKDRadixSelector {
   }
 
   /** Sliced reference to points in an PointWriter. */
-  public static final class PathSlice {
-    public final PointWriter writer;
-    public final long start;
-    public final long count;
-
-    public PathSlice(PointWriter writer, long start, long count) {
-      this.writer = writer;
-      this.start = start;
-      this.count = count;
-    }
-
-    @Override
-    public String toString() {
-      return "PathSlice(start=" + start + " count=" + count + " writer=" + writer + ")";
-    }
-  }
+  public record PathSlice(PointWriter writer, long start, long count) {}
 }
diff --git a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDWriter.java b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDWriter.java
index a3bb7db8536..2af93ef5ca0 100644
--- a/lucene/core/src/java/org/apache/lucene/util/bkd/BKDWriter.java
+++ b/lucene/core/src/java/org/apache/lucene/util/bkd/BKDWriter.java
@@ -1823,7 +1823,7 @@ public class BKDWriter implements Closeable {
   private void computePackedValueBounds(
       BKDRadixSelector.PathSlice slice, byte[] minPackedValue, byte[] maxPackedValue)
       throws IOException {
-    try (PointReader reader = slice.writer.getReader(slice.start, slice.count)) {
+    try (PointReader reader = slice.writer().getReader(slice.start(), slice.count())) {
       if (reader.next() == false) {
         return;
       }
@@ -1887,16 +1887,16 @@ public class BKDWriter implements Closeable {
       // least number of unique bytes at commonPrefixLengths[dim], which makes compression more
       // efficient
       HeapPointWriter heapSource;
-      if (points.writer instanceof HeapPointWriter == false) {
+      if (points.writer() instanceof HeapPointWriter == false) {
         // Adversarial cases can cause this, e.g. merging big segments with most of the points
         // deleted
-        heapSource = switchToHeap(points.writer);
+        heapSource = switchToHeap(points.writer());
       } else {
-        heapSource = (HeapPointWriter) points.writer;
+        heapSource = (HeapPointWriter) points.writer();
       }
 
-      int from = Math.toIntExact(points.start);
-      int to = Math.toIntExact(points.start + points.count);
+      int from = Math.toIntExact(points.start());
+      int to = Math.toIntExact(points.start() + points.count());
       // we store common prefix on scratch
       computeCommonPrefixLength(heapSource, scratch, from, to);
 
@@ -2004,9 +2004,9 @@ public class BKDWriter implements Closeable {
           radixSelector.select(
               points,
               slices,
-              points.start,
-              points.start + points.count,
-              points.start + leftCount,
+              points.start(),
+              points.start() + points.count(),
+              points.start() + leftCount,
               splitDim,
               commonPrefixLen);
 
diff --git a/lucene/core/src/java/org/apache/lucene/util/fst/Util.java b/lucene/core/src/java/org/apache/lucene/util/fst/Util.java
index 15f763f62b2..a6df78eaab5 100644
--- a/lucene/core/src/java/org/apache/lucene/util/fst/Util.java
+++ b/lucene/core/src/java/org/apache/lucene/util/fst/Util.java
@@ -149,12 +149,8 @@ public final class Util {
   }
 
   /** Compares first by the provided comparator, and then tie breaks by path.input. */
-  private static class TieBreakByInputComparator<T> implements Comparator<FSTPath<T>> {
-    private final Comparator<T> comparator;
-
-    TieBreakByInputComparator(Comparator<T> comparator) {
-      this.comparator = comparator;
-    }
+  private record TieBreakByInputComparator<T>(Comparator<T> comparator)
+      implements Comparator<FSTPath<T>> {
 
     @Override
     public int compare(FSTPath<T> a, FSTPath<T> b) {
@@ -430,15 +426,7 @@ public final class Util {
   /**
    * Holds a single input (IntsRef) + output, returned by {@link #shortestPaths shortestPaths()}.
    */
-  public static final class Result<T> {
-    public final IntsRef input;
-    public final T output;
-
-    public Result(IntsRef input, T output) {
-      this.input = input;
-      this.output = output;
-    }
-  }
+  public record Result<T>(IntsRef input, T output) {}
 
   /** Holds the results for a top N search using {@link TopNSearcher} */
   public static final class TopResults<T> implements Iterable<Result<T>> {
diff --git a/lucene/core/src/java/org/apache/lucene/util/packed/PackedInts.java b/lucene/core/src/java/org/apache/lucene/util/packed/PackedInts.java
index dc9f22531dc..d5e112e0470 100644
--- a/lucene/core/src/java/org/apache/lucene/util/packed/PackedInts.java
+++ b/lucene/core/src/java/org/apache/lucene/util/packed/PackedInts.java
@@ -171,20 +171,7 @@ public class PackedInts {
   }
 
   /** Simple class that holds a format and a number of bits per value. */
-  public static class FormatAndBits {
-    public final Format format;
-    public final int bitsPerValue;
-
-    public FormatAndBits(Format format, int bitsPerValue) {
-      this.format = format;
-      this.bitsPerValue = bitsPerValue;
-    }
-
-    @Override
-    public String toString() {
-      return "FormatAndBits(format=" + format + " bitsPerValue=" + bitsPerValue + ")";
-    }
-  }
+  public record FormatAndBits(Format format, int bitsPerValue) {}
 
   /**
    * Try to find the {@link Format} and number of bits per value that would restore from disk the
diff --git a/lucene/core/src/java/org/apache/lucene/util/packed/PagedMutable.java b/lucene/core/src/java/org/apache/lucene/util/packed/PagedMutable.java
index 16a91de4e32..0653b025fe8 100644
--- a/lucene/core/src/java/org/apache/lucene/util/packed/PagedMutable.java
+++ b/lucene/core/src/java/org/apache/lucene/util/packed/PagedMutable.java
@@ -47,7 +47,7 @@ public final class PagedMutable extends AbstractPagedMutable<PagedMutable> {
   }
 
   PagedMutable(long size, int pageSize, PackedInts.FormatAndBits formatAndBits) {
-    this(size, pageSize, formatAndBits.bitsPerValue, formatAndBits.format);
+    this(size, pageSize, formatAndBits.bitsPerValue(), formatAndBits.format());
   }
 
   PagedMutable(long size, int pageSize, int bitsPerValue, PackedInts.Format format) {
diff --git a/lucene/core/src/java/org/apache/lucene/util/quantization/ScalarQuantizer.java b/lucene/core/src/java/org/apache/lucene/util/quantization/ScalarQuantizer.java
index 44c0ac5aca4..ab8a911ddfa 100644
--- a/lucene/core/src/java/org/apache/lucene/util/quantization/ScalarQuantizer.java
+++ b/lucene/core/src/java/org/apache/lucene/util/quantization/ScalarQuantizer.java
@@ -614,19 +614,7 @@ public class ScalarQuantizer {
     }
   }
 
-  private static class ScoreDocsAndScoreVariance {
-    private final ScoreDoc[] scoreDocs;
-    private final float scoreVariance;
-
-    public ScoreDocsAndScoreVariance(ScoreDoc[] scoreDocs, float scoreVariance) {
-      this.scoreDocs = scoreDocs;
-      this.scoreVariance = scoreVariance;
-    }
-
-    public ScoreDoc[] getScoreDocs() {
-      return scoreDocs;
-    }
-  }
+  private record ScoreDocsAndScoreVariance(ScoreDoc[] scoreDocs, float scoreVariance) {}
 
   private static class OnlineMeanAndVar {
     private double mean = 0.0;
@@ -687,7 +675,7 @@ public class ScalarQuantizer {
       for (int i = 0; i < nearestNeighbors.size(); i++) {
         float queryCorrection = quantizer.quantize(vectors.get(i), query, function);
         ScoreDocsAndScoreVariance scoreDocsAndScoreVariance = nearestNeighbors.get(i);
-        ScoreDoc[] scoreDocs = scoreDocsAndScoreVariance.getScoreDocs();
+        ScoreDoc[] scoreDocs = scoreDocsAndScoreVariance.scoreDocs();
         float scoreVariance = scoreDocsAndScoreVariance.scoreVariance;
         // calculate the score for the vector against its nearest neighbors but with quantized
         // scores now
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestDocumentWriter.java b/lucene/core/src/test/org/apache/lucene/index/TestDocumentWriter.java
index 7d8cdf95d23..af5b2938d59 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestDocumentWriter.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestDocumentWriter.java
@@ -388,28 +388,14 @@ public class TestDocumentWriter extends LuceneTestCase {
                 field, new float[] {1, 2, 3, 4}, VectorSimilarityFunction.EUCLIDEAN));
   }
 
-  private static class MockIndexableField implements IndexableField {
-
-    private final String field;
-    private final BytesRef value;
-    private final IndexableFieldType fieldType;
-
-    MockIndexableField(String field, BytesRef value, IndexableFieldType fieldType) {
-      this.field = field;
-      this.value = value;
-      this.fieldType = fieldType;
-    }
+  private record MockIndexableField(String field, BytesRef value, IndexableFieldType fieldType)
+      implements IndexableField {
 
     @Override
     public String name() {
       return field;
     }
 
-    @Override
-    public IndexableFieldType fieldType() {
-      return fieldType;
-    }
-
     @Override
     public TokenStream tokenStream(Analyzer analyzer, TokenStream reuse) {
       return null;
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
index 0432f05d94f..0d874b73c7f 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexSorting.java
@@ -2412,7 +2412,7 @@ public class TestIndexSorting extends LuceneTestCase {
     if (VERBOSE) {
       System.out.println("TEST: now compare r1=" + r1 + " r2=" + r2);
     }
-    assertEquals(sort, getOnlyLeafReader(r2).getMetaData().getSort());
+    assertEquals(sort, getOnlyLeafReader(r2).getMetaData().sort());
     assertReaderEquals("left: sorted by hand; right: sorted by Lucene", r1, r2);
     IOUtils.close(w1, w2, r1, r2, dir1, dir2);
   }
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
index 5757141b8f2..bfe6b0a60fa 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestIndexWriterExceptions.java
@@ -73,10 +73,7 @@ import org.apache.lucene.util.InfoStream;
 @SuppressCodecs("SimpleText") // too slow here
 public class TestIndexWriterExceptions extends LuceneTestCase {
 
-  private static class DocCopyIterator implements Iterable<Document> {
-    private final Document doc;
-    private final int count;
-
+  private record DocCopyIterator(Document doc, int count) implements Iterable<Document> {
     /* private field types */
     /* private field types */
 
@@ -105,11 +102,6 @@ public class TestIndexWriterExceptions extends LuceneTestCase {
       custom5.setStoreTermVectorOffsets(true);
     }
 
-    public DocCopyIterator(Document doc, int count) {
-      this.count = count;
-      this.doc = doc;
-    }
-
     @Override
     public Iterator<Document> iterator() {
       return new Iterator<Document>() {
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestSortingCodecReader.java b/lucene/core/src/test/org/apache/lucene/index/TestSortingCodecReader.java
index 10efbd881a2..58a0dc601e6 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestSortingCodecReader.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestSortingCodecReader.java
@@ -138,7 +138,7 @@ public class TestSortingCodecReader extends LuceneTestCase {
     assertEquals(7, values.longValue());
     assertEquals(2, values.nextDoc());
     assertEquals(18, values.longValue());
-    assertNotNull(leaf.getMetaData().getSort());
+    assertNotNull(leaf.getMetaData().sort());
     IOUtils.close(r, w, dir, tmpDir);
   }
 
diff --git a/lucene/core/src/test/org/apache/lucene/index/TestTermsEnum.java b/lucene/core/src/test/org/apache/lucene/index/TestTermsEnum.java
index 17d98e249f3..43c16d8ec15 100644
--- a/lucene/core/src/test/org/apache/lucene/index/TestTermsEnum.java
+++ b/lucene/core/src/test/org/apache/lucene/index/TestTermsEnum.java
@@ -625,15 +625,7 @@ public class TestTermsEnum extends LuceneTestCase {
     }
   }
 
-  private static class TermAndState {
-    public final BytesRef term;
-    public final TermState state;
-
-    public TermAndState(BytesRef term, TermState state) {
-      this.term = term;
-      this.state = state;
-    }
-  }
+  private record TermAndState(BytesRef term, TermState state) {}
 
   private void testRandomSeeks(IndexReader r, String... validTermStrings) throws IOException {
     final BytesRef[] validTerms = new BytesRef[validTermStrings.length];
diff --git a/lucene/core/src/test/org/apache/lucene/internal/vectorization/TestVectorScorer.java b/lucene/core/src/test/org/apache/lucene/internal/vectorization/TestVectorScorer.java
index ce2ad6854a2..da9c312ef96 100644
--- a/lucene/core/src/test/org/apache/lucene/internal/vectorization/TestVectorScorer.java
+++ b/lucene/core/src/test/org/apache/lucene/internal/vectorization/TestVectorScorer.java
@@ -269,16 +269,8 @@ public class TestVectorScorer extends LuceneTestCase {
   }
 
   // A callable that scores the given ord and scorer and asserts the expected result.
-  static class AssertingScoreCallable implements Callable<Optional<Throwable>> {
-    final RandomVectorScorer scorer;
-    final int ord;
-    final float expectedScore;
-
-    AssertingScoreCallable(RandomVectorScorer scorer, int ord, float expectedScore) {
-      this.scorer = scorer;
-      this.ord = ord;
-      this.expectedScore = expectedScore;
-    }
+  record AssertingScoreCallable(RandomVectorScorer scorer, int ord, float expectedScore)
+      implements Callable<Optional<Throwable>> {
 
     @Override
     public Optional<Throwable> call() throws Exception {
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java
index b291a96c802..933898348bf 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanQueryVisitSubscorers.java
@@ -190,7 +190,7 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase {
         set.add((Scorer) scorer);
       } else {
         for (Scorable.ChildScorable child : scorer.getChildren()) {
-          fillLeaves(child.child, set);
+          fillLeaves(child.child(), set);
         }
       }
     }
@@ -330,8 +330,8 @@ public class TestBooleanQueryVisitSubscorers extends LuceneTestCase {
         final StringBuilder builder, final Scorable scorer, final int indent) throws IOException {
       builder.append(scorer.getClass().getSimpleName());
       for (final Scorable.ChildScorable childScorer : scorer.getChildren()) {
-        indent(builder, indent + 1).append(childScorer.relationship).append(" ");
-        summarizeScorer(builder, childScorer.child, indent + 2);
+        indent(builder, indent + 1).append(childScorer.relationship()).append(" ");
+        summarizeScorer(builder, childScorer.child(), indent + 2);
       }
     }
 
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestCollectorManager.java b/lucene/core/src/test/org/apache/lucene/search/TestCollectorManager.java
index 3c7360f7d58..1e5826160f6 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestCollectorManager.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestCollectorManager.java
@@ -122,13 +122,8 @@ public class TestCollectorManager extends LuceneTestCase {
     return generated;
   }
 
-  private static final class CompositeCollectorManager
+  private record CompositeCollectorManager(List<Predicate<Integer>> predicates)
       implements CollectorManager<Collector, List<Integer>> {
-    private final List<Predicate<Integer>> predicates;
-
-    CompositeCollectorManager(List<Predicate<Integer>> predicates) {
-      this.predicates = predicates;
-    }
 
     @Override
     public Collector newCollector() throws IOException {
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java
index adef5e004f8..7ca3ee39b39 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestConstantScoreQuery.java
@@ -107,7 +107,7 @@ public class TestConstantScoreQuery extends LuceneTestCase {
       try {
         Collection<Scorable.ChildScorable> children = s.getChildren();
         if (children.size() == 0) return s;
-        s = children.stream().findFirst().get().child;
+        s = children.stream().findFirst().get().child();
       } catch (
           @SuppressWarnings("unused")
           Exception e) {
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestFuzzyQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestFuzzyQuery.java
index 6515417b3a8..d84fb7dbcec 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestFuzzyQuery.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestFuzzyQuery.java
@@ -705,14 +705,7 @@ public class TestFuzzyQuery extends LuceneTestCase {
     IOUtils.close(r, dir);
   }
 
-  private static class TermAndScore implements Comparable<TermAndScore> {
-    final String term;
-    final float score;
-
-    public TermAndScore(String term, float score) {
-      this.term = term;
-      this.score = score;
-    }
+  private record TermAndScore(String term, float score) implements Comparable<TermAndScore> {
 
     @Override
     public int compareTo(TermAndScore other) {
@@ -725,11 +718,6 @@ public class TestFuzzyQuery extends LuceneTestCase {
         return term.compareTo(other.term);
       }
     }
-
-    @Override
-    public String toString() {
-      return term + " score=" + score;
-    }
   }
 
   // Poached from LuceneLevenshteinDistance.java (from suggest module): it supports transpositions
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreAccumulator.java b/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreAccumulator.java
index 700fba697c5..2af3c3b33b4 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreAccumulator.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestMaxScoreAccumulator.java
@@ -23,29 +23,29 @@ public class TestMaxScoreAccumulator extends LuceneTestCase {
   public void testSimple() {
     MaxScoreAccumulator acc = new MaxScoreAccumulator();
     acc.accumulate(0, 0f);
-    assertEquals(0f, acc.get().score, 0);
-    assertEquals(0, acc.get().docBase, 0);
+    assertEquals(0f, acc.get().score(), 0);
+    assertEquals(0, acc.get().docBase(), 0);
     acc.accumulate(10, 0f);
-    assertEquals(0f, acc.get().score, 0);
-    assertEquals(0, acc.get().docBase, 0);
+    assertEquals(0f, acc.get().score(), 0);
+    assertEquals(0, acc.get().docBase(), 0);
     acc.accumulate(100, 1000f);
-    assertEquals(1000f, acc.get().score, 0);
-    assertEquals(100, acc.get().docBase, 0);
+    assertEquals(1000f, acc.get().score(), 0);
+    assertEquals(100, acc.get().docBase(), 0);
     acc.accumulate(1000, 5f);
-    assertEquals(1000f, acc.get().score, 0);
-    assertEquals(100, acc.get().docBase, 0);
+    assertEquals(1000f, acc.get().score(), 0);
+    assertEquals(100, acc.get().docBase(), 0);
     acc.accumulate(99, 1000f);
-    assertEquals(1000f, acc.get().score, 0);
-    assertEquals(99, acc.get().docBase, 0);
+    assertEquals(1000f, acc.get().score(), 0);
+    assertEquals(99, acc.get().docBase(), 0);
     acc.accumulate(1000, 1001f);
-    assertEquals(1001f, acc.get().score, 0);
-    assertEquals(1000, acc.get().docBase, 0);
+    assertEquals(1001f, acc.get().score(), 0);
+    assertEquals(1000, acc.get().docBase(), 0);
     acc.accumulate(10, 1001f);
-    assertEquals(1001f, acc.get().score, 0);
-    assertEquals(10, acc.get().docBase, 0);
+    assertEquals(1001f, acc.get().score(), 0);
+    assertEquals(10, acc.get().docBase(), 0);
     acc.accumulate(100, 1001f);
-    assertEquals(1001f, acc.get().score, 0);
-    assertEquals(10, acc.get().docBase, 0);
+    assertEquals(1001f, acc.get().score(), 0);
+    assertEquals(10, acc.get().docBase(), 0);
   }
 
   public void testRandom() {
@@ -56,7 +56,7 @@ public class TestMaxScoreAccumulator extends LuceneTestCase {
     for (int i = 0; i < numDocs; i++) {
       MaxScoreAccumulator.DocAndScore res =
           new MaxScoreAccumulator.DocAndScore(random().nextInt(maxDocs), random().nextFloat());
-      acc.accumulate(res.docBase, res.score);
+      acc.accumulate(res.docBase(), res.score());
       if (res.compareTo(max) > 0) {
         max = res;
       }
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java
index fa20d124b04..b50b352274b 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestScorerPerf.java
@@ -47,7 +47,7 @@ public class TestScorerPerf extends LuceneTestCase {
     return sets;
   }
 
-  private static final class CountingHitCollectorManager
+  private record CountingHitCollectorManager()
       implements CollectorManager<CountingHitCollector, CountingHitCollector> {
 
     @Override
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
index e91858800a2..df6fd881df9 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopDocsCollector.java
@@ -530,37 +530,37 @@ public class TestTopDocsCollector extends LuceneTestCase {
 
     scorer.score = 2;
     leafCollector.collect(1);
-    assertEquals(2f, minValueChecker.get().score, 0f);
+    assertEquals(2f, minValueChecker.get().score(), 0f);
     assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
     assertNull(scorer2.minCompetitiveScore);
 
     scorer2.score = 9;
     leafCollector2.collect(1);
-    assertEquals(6f, minValueChecker.get().score, 0f);
+    assertEquals(6f, minValueChecker.get().score(), 0f);
     assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(6f), scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 7;
     leafCollector2.collect(2);
-    assertEquals(minValueChecker.get().score, 7f, 0f);
+    assertEquals(minValueChecker.get().score(), 7f, 0f);
     assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 1;
     leafCollector2.collect(3);
-    assertEquals(minValueChecker.get().score, 7f, 0f);
+    assertEquals(minValueChecker.get().score(), 7f, 0f);
     assertEquals(Math.nextUp(2f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 10;
     leafCollector.collect(2);
-    assertEquals(minValueChecker.get().score, 7f, 0f);
+    assertEquals(minValueChecker.get().score(), 7f, 0f);
     assertEquals(7f, scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 11;
     leafCollector.collect(3);
-    assertEquals(minValueChecker.get().score, 10, 0f);
+    assertEquals(minValueChecker.get().score(), 10, 0f);
     assertEquals(Math.nextUp(10f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
 
@@ -572,19 +572,19 @@ public class TestTopDocsCollector extends LuceneTestCase {
 
     scorer3.score = 1f;
     leafCollector3.collect(0);
-    assertEquals(10f, minValueChecker.get().score, 0f);
+    assertEquals(10f, minValueChecker.get().score(), 0f);
     assertEquals(Math.nextUp(10f), scorer3.minCompetitiveScore, 0f);
 
     scorer.score = 11;
     leafCollector.collect(4);
-    assertEquals(11f, minValueChecker.get().score, 0f);
+    assertEquals(11f, minValueChecker.get().score(), 0f);
     assertEquals(Math.nextUp(11f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(10f), scorer3.minCompetitiveScore, 0f);
 
     scorer3.score = 2f;
     leafCollector3.collect(1);
-    assertEquals(minValueChecker.get().score, 11f, 0f);
+    assertEquals(minValueChecker.get().score(), 11f, 0f);
     assertEquals(Math.nextUp(11f), scorer.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(7f), scorer2.minCompetitiveScore, 0f);
     assertEquals(Math.nextUp(11f), scorer3.minCompetitiveScore, 0f);
diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
index 6662cf0c222..d56e17683a7 100644
--- a/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
+++ b/lucene/core/src/test/org/apache/lucene/search/TestTopFieldCollector.java
@@ -587,37 +587,37 @@ public class TestTopFieldCollector extends LuceneTestCase {
 
     scorer.score = 2;
     leafCollector.collect(1);
-    assertEquals(2f, minValueChecker.get().score, 0f);
+    assertEquals(2f, minValueChecker.get().score(), 0f);
     assertEquals(2f, scorer.minCompetitiveScore, 0f);
     assertNull(scorer2.minCompetitiveScore);
 
     scorer2.score = 9;
     leafCollector2.collect(1);
-    assertEquals(6f, minValueChecker.get().score, 0f);
+    assertEquals(6f, minValueChecker.get().score(), 0f);
     assertEquals(2f, scorer.minCompetitiveScore, 0f);
     assertEquals(6f, scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 7;
     leafCollector2.collect(2);
-    assertEquals(7f, minValueChecker.get().score, 0f);
+    assertEquals(7f, minValueChecker.get().score(), 0f);
     assertEquals(2f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
     scorer2.score = 1;
     leafCollector2.collect(3);
-    assertEquals(7f, minValueChecker.get().score, 0f);
+    assertEquals(7f, minValueChecker.get().score(), 0f);
     assertEquals(2f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 10;
     leafCollector.collect(2);
-    assertEquals(7f, minValueChecker.get().score, 0f);
+    assertEquals(7f, minValueChecker.get().score(), 0f);
     assertEquals(7f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
     scorer.score = 11;
     leafCollector.collect(3);
-    assertEquals(10f, minValueChecker.get().score, 0f);
+    assertEquals(10f, minValueChecker.get().score(), 0f);
     assertEquals(10f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
 
@@ -629,19 +629,19 @@ public class TestTopFieldCollector extends LuceneTestCase {
 
     scorer3.score = 1f;
     leafCollector3.collect(0);
-    assertEquals(10f, minValueChecker.get().score, 0f);
+    assertEquals(10f, minValueChecker.get().score(), 0f);
     assertEquals(10f, scorer3.minCompetitiveScore, 0f);
 
     scorer.score = 11;
     leafCollector.collect(4);
-    assertEquals(11f, minValueChecker.get().score, 0f);
+    assertEquals(11f, minValueChecker.get().score(), 0f);
     assertEquals(11f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
     assertEquals(10f, scorer3.minCompetitiveScore, 0f);
 
     scorer3.score = 2f;
     leafCollector3.collect(1);
-    assertEquals(11f, minValueChecker.get().score, 0f);
+    assertEquals(11f, minValueChecker.get().score(), 0f);
     assertEquals(11f, scorer.minCompetitiveScore, 0f);
     assertEquals(7f, scorer2.minCompetitiveScore, 0f);
     assertEquals(11f, scorer3.minCompetitiveScore, 0f);
diff --git a/lucene/core/src/test/org/apache/lucene/util/BaseSortTestCase.java b/lucene/core/src/test/org/apache/lucene/util/BaseSortTestCase.java
index ba4ed6fa82b..5a0382fe3d8 100644
--- a/lucene/core/src/test/org/apache/lucene/util/BaseSortTestCase.java
+++ b/lucene/core/src/test/org/apache/lucene/util/BaseSortTestCase.java
@@ -23,15 +23,7 @@ import org.apache.lucene.tests.util.TestUtil;
 
 public abstract class BaseSortTestCase extends LuceneTestCase {
 
-  public static class Entry implements java.lang.Comparable<Entry> {
-
-    public final int value;
-    public final int ord;
-
-    public Entry(int value, int ord) {
-      this.value = value;
-      this.ord = ord;
-    }
+  public record Entry(int value, int ord) implements Comparable<Entry> {
 
     @Override
     public int compareTo(Entry other) {
diff --git a/lucene/core/src/test/org/apache/lucene/util/TestArrayUtil.java b/lucene/core/src/test/org/apache/lucene/util/TestArrayUtil.java
index 972fd0c3c84..41f320ba007 100644
--- a/lucene/core/src/test/org/apache/lucene/util/TestArrayUtil.java
+++ b/lucene/core/src/test/org/apache/lucene/util/TestArrayUtil.java
@@ -197,13 +197,7 @@ public class TestArrayUtil extends LuceneTestCase {
     }
   }
 
-  static class Item implements Comparable<Item> {
-    final int val, order;
-
-    Item(int val, int order) {
-      this.val = val;
-      this.order = order;
-    }
+  record Item(int val, int order) implements Comparable<Item> {
 
     @Override
     public int compareTo(Item other) {
diff --git a/lucene/core/src/test/org/apache/lucene/util/automaton/MinimizationOperations.java b/lucene/core/src/test/org/apache/lucene/util/automaton/MinimizationOperations.java
index 820ae1881c6..ecf0beaa618 100644
--- a/lucene/core/src/test/org/apache/lucene/util/automaton/MinimizationOperations.java
+++ b/lucene/core/src/test/org/apache/lucene/util/automaton/MinimizationOperations.java
@@ -262,15 +262,7 @@ public final class MinimizationOperations {
     return Operations.removeDeadStates(result);
   }
 
-  static final class IntPair {
-
-    final int n1, n2;
-
-    IntPair(int n1, int n2) {
-      this.n1 = n1;
-      this.n2 = n2;
-    }
-  }
+  record IntPair(int n1, int n2) {}
 
   static final class StateList {
 
diff --git a/lucene/core/src/test/org/apache/lucene/util/bkd/TestBKDRadixSelector.java b/lucene/core/src/test/org/apache/lucene/util/bkd/TestBKDRadixSelector.java
index d8e2979de1e..977e68b7156 100644
--- a/lucene/core/src/test/org/apache/lucene/util/bkd/TestBKDRadixSelector.java
+++ b/lucene/core/src/test/org/apache/lucene/util/bkd/TestBKDRadixSelector.java
@@ -221,8 +221,8 @@ public class TestBKDRadixSelector extends LuceneTestCase {
       byte[] partitionPoint =
           radixSelector.select(
               inputSlice, slices, start, end, middle, splitDim, commonPrefixLengthInput);
-      assertEquals(middle - start, slices[0].count);
-      assertEquals(end - middle, slices[1].count);
+      assertEquals(middle - start, slices[0].count());
+      assertEquals(end - middle, slices[1].count());
       // check that left and right slices contain the correct points
       byte[] max = getMax(config, slices[0], splitDim);
       byte[] min = getMin(config, slices[1], splitDim);
@@ -247,8 +247,8 @@ public class TestBKDRadixSelector extends LuceneTestCase {
         }
       }
       assertTrue(Arrays.equals(partitionPoint, min));
-      slices[0].writer.destroy();
-      slices[1].writer.destroy();
+      slices[0].writer().destroy();
+      slices[1].writer().destroy();
     }
     points.destroy();
   }
@@ -302,7 +302,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
       throws IOException {
     byte[] min = new byte[config.bytesPerDim()];
     Arrays.fill(min, (byte) 0xff);
-    try (PointReader reader = pathSlice.writer.getReader(pathSlice.start, pathSlice.count)) {
+    try (PointReader reader = pathSlice.writer().getReader(pathSlice.start(), pathSlice.count())) {
       byte[] value = new byte[config.bytesPerDim()];
 
       while (reader.next()) {
@@ -331,7 +331,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
       byte[] dataDim)
       throws IOException {
     int docID = Integer.MAX_VALUE;
-    try (PointReader reader = p.writer.getReader(p.start, p.count)) {
+    try (PointReader reader = p.writer().getReader(p.start(), p.count())) {
       while (reader.next()) {
         PointValue pointValue = reader.pointValue();
         BytesRef packedValue = pointValue.packedValue();
@@ -371,7 +371,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
     byte[] min = new byte[numDataDims * config.bytesPerDim()];
     Arrays.fill(min, (byte) 0xff);
     int offset = splitDim * config.bytesPerDim();
-    try (PointReader reader = p.writer.getReader(p.start, p.count)) {
+    try (PointReader reader = p.writer().getReader(p.start(), p.count())) {
       byte[] value = new byte[numDataDims * config.bytesPerDim()];
       while (reader.next()) {
         PointValue pointValue = reader.pointValue();
@@ -410,7 +410,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
       throws IOException {
     byte[] max = new byte[config.bytesPerDim()];
     Arrays.fill(max, (byte) 0);
-    try (PointReader reader = p.writer.getReader(p.start, p.count)) {
+    try (PointReader reader = p.writer().getReader(p.start(), p.count())) {
       byte[] value = new byte[config.bytesPerDim()];
       while (reader.next()) {
         PointValue pointValue = reader.pointValue();
@@ -437,7 +437,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
     byte[] max = new byte[numDataDims * config.bytesPerDim()];
     Arrays.fill(max, (byte) 0);
     int offset = splitDim * config.bytesPerDim();
-    try (PointReader reader = p.writer.getReader(p.start, p.count)) {
+    try (PointReader reader = p.writer().getReader(p.start(), p.count())) {
       byte[] value = new byte[numDataDims * config.bytesPerDim()];
       while (reader.next()) {
         PointValue pointValue = reader.pointValue();
@@ -480,7 +480,7 @@ public class TestBKDRadixSelector extends LuceneTestCase {
       byte[] dataDim)
       throws IOException {
     int docID = Integer.MIN_VALUE;
-    try (PointReader reader = p.writer.getReader(p.start, p.count)) {
+    try (PointReader reader = p.writer().getReader(p.start(), p.count())) {
       while (reader.next()) {
         PointValue pointValue = reader.pointValue();
         BytesRef packedValue = pointValue.packedValue();
diff --git a/lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java b/lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java
index 9d09f075b72..e83e4f1ec04 100644
--- a/lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java
+++ b/lucene/core/src/test/org/apache/lucene/util/fst/TestFSTs.java
@@ -1350,14 +1350,14 @@ public class TestFSTs extends LuceneTestCase {
             true);
     assertTrue(res.isComplete);
     assertEquals(3, res.topN.size());
-    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input);
-    assertEquals(7L, res.topN.get(0).output.longValue());
+    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input());
+    assertEquals(7L, res.topN.get(0).output().longValue());
 
-    assertEquals(Util.toIntsRef(newBytesRef("ax"), scratch), res.topN.get(1).input);
-    assertEquals(17L, res.topN.get(1).output.longValue());
+    assertEquals(Util.toIntsRef(newBytesRef("ax"), scratch), res.topN.get(1).input());
+    assertEquals(17L, res.topN.get(1).output().longValue());
 
-    assertEquals(Util.toIntsRef(newBytesRef("aab"), scratch), res.topN.get(2).input);
-    assertEquals(22L, res.topN.get(2).output.longValue());
+    assertEquals(Util.toIntsRef(newBytesRef("aab"), scratch), res.topN.get(2).input());
+    assertEquals(22L, res.topN.get(2).output().longValue());
   }
 
   public void testRejectNoLimits() throws IOException {
@@ -1393,8 +1393,8 @@ public class TestFSTs extends LuceneTestCase {
     assertTrue(res.isComplete); // rejected(4) + topN(2) <= maxQueueSize(6)
 
     assertEquals(1, res.topN.size());
-    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input);
-    assertEquals(7L, res.topN.get(0).output.longValue());
+    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input());
+    assertEquals(7L, res.topN.get(0).output().longValue());
     rejectCount.set(0);
     searcher =
         new Util.TopNSearcher<>(fst, 2, 5, minLongComparator) {
@@ -1452,17 +1452,17 @@ public class TestFSTs extends LuceneTestCase {
     assertTrue(res.isComplete);
     assertEquals(3, res.topN.size());
 
-    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input);
-    assertEquals(7L, res.topN.get(0).output.output1.longValue()); // weight
-    assertEquals(36L, res.topN.get(0).output.output2.longValue()); // output
+    assertEquals(Util.toIntsRef(newBytesRef("aac"), scratch), res.topN.get(0).input());
+    assertEquals(7L, res.topN.get(0).output().output1.longValue()); // weight
+    assertEquals(36L, res.topN.get(0).output().output2.longValue()); // output
 
-    assertEquals(Util.toIntsRef(newBytesRef("ax"), scratch), res.topN.get(1).input);
-    assertEquals(17L, res.topN.get(1).output.output1.longValue()); // weight
-    assertEquals(85L, res.topN.get(1).output.output2.longValue()); // output
+    assertEquals(Util.toIntsRef(newBytesRef("ax"), scratch), res.topN.get(1).input());
+    assertEquals(17L, res.topN.get(1).output().output1.longValue()); // weight
+    assertEquals(85L, res.topN.get(1).output().output2.longValue()); // output
 
-    assertEquals(Util.toIntsRef(newBytesRef("aab"), scratch), res.topN.get(2).input);
-    assertEquals(22L, res.topN.get(2).output.output1.longValue()); // weight
-    assertEquals(57L, res.topN.get(2).output.output2.longValue()); // output
+    assertEquals(Util.toIntsRef(newBytesRef("aab"), scratch), res.topN.get(2).input());
+    assertEquals(22L, res.topN.get(2).output().output1.longValue()); // weight
+    assertEquals(57L, res.topN.get(2).output().output2.longValue()); // output
   }
 
   public void testShortestPathsRandom() throws Exception {
@@ -1548,24 +1548,20 @@ public class TestFSTs extends LuceneTestCase {
 
       for (int hit = 0; hit < r.topN.size(); hit++) {
         // System.out.println("  check hit " + hit);
-        assertEquals(matches.get(hit).input, r.topN.get(hit).input);
-        assertEquals(matches.get(hit).output, r.topN.get(hit).output);
+        assertEquals(matches.get(hit).input(), r.topN.get(hit).input());
+        assertEquals(matches.get(hit).output(), r.topN.get(hit).output());
       }
     }
   }
 
-  private static class TieBreakByInputComparator<T> implements Comparator<Result<T>> {
-    private final Comparator<T> comparator;
-
-    public TieBreakByInputComparator(Comparator<T> comparator) {
-      this.comparator = comparator;
-    }
+  private record TieBreakByInputComparator<T>(Comparator<T> comparator)
+      implements Comparator<Result<T>> {
 
     @Override
     public int compare(Result<T> a, Result<T> b) {
-      int cmp = comparator.compare(a.output, b.output);
+      int cmp = comparator.compare(a.output(), b.output());
       if (cmp == 0) {
-        return a.input.compareTo(b.input);
+        return a.input().compareTo(b.input());
       } else {
         return cmp;
       }
@@ -1678,8 +1674,8 @@ public class TestFSTs extends LuceneTestCase {
 
       for (int hit = 0; hit < r.topN.size(); hit++) {
         // System.out.println("  check hit " + hit);
-        assertEquals(matches.get(hit).input, r.topN.get(hit).input);
-        assertEquals(matches.get(hit).output, r.topN.get(hit).output);
+        assertEquals(matches.get(hit).input(), r.topN.get(hit).input());
+        assertEquals(matches.get(hit).output(), r.topN.get(hit).output());
       }
     }
   }
diff --git a/lucene/demo/src/java/org/apache/lucene/demo/facet/CustomFacetSetExample.java b/lucene/demo/src/java/org/apache/lucene/demo/facet/CustomFacetSetExample.java
index d3000b46037..ba157c6c8f9 100644
--- a/lucene/demo/src/java/org/apache/lucene/demo/facet/CustomFacetSetExample.java
+++ b/lucene/demo/src/java/org/apache/lucene/demo/facet/CustomFacetSetExample.java
@@ -379,7 +379,7 @@ public class CustomFacetSetExample {
 
     @Override
     public boolean matches(long[] dimValues) {
-      return temperatureRange.min <= dimValues[1] && temperatureRange.max >= dimValues[1];
+      return temperatureRange.min() <= dimValues[1] && temperatureRange.max() >= dimValues[1];
     }
   }
 }
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/FacetCountsWithFilterQuery.java b/lucene/facet/src/java/org/apache/lucene/facet/FacetCountsWithFilterQuery.java
index fafa0f33c4b..500e9a27616 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/FacetCountsWithFilterQuery.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetCountsWithFilterQuery.java
@@ -59,7 +59,7 @@ public abstract class FacetCountsWithFilterQuery extends Facets {
   protected DocIdSetIterator createIterator(
       FacetsCollector.MatchingDocs hits, DocIdSetIterator... iterators) throws IOException {
     List<DocIdSetIterator> allIterators = new ArrayList<>();
-    allIterators.add(hits.bits.iterator());
+    allIterators.add(hits.bits().iterator());
     allIterators.addAll(Arrays.asList(iterators));
     if (allIterators.stream().anyMatch(Objects::isNull)) {
       // if any of the iterators are null, there are no matching docs
@@ -67,12 +67,12 @@ public abstract class FacetCountsWithFilterQuery extends Facets {
     }
 
     if (fastMatchQuery != null) {
-      final IndexReaderContext topLevelContext = ReaderUtil.getTopLevelContext(hits.context);
+      final IndexReaderContext topLevelContext = ReaderUtil.getTopLevelContext(hits.context());
       final IndexSearcher searcher = new IndexSearcher(topLevelContext);
       searcher.setQueryCache(null);
       final Weight fastMatchWeight =
           searcher.createWeight(searcher.rewrite(fastMatchQuery), ScoreMode.COMPLETE_NO_SCORES, 1);
-      final Scorer s = fastMatchWeight.scorer(hits.context);
+      final Scorer s = fastMatchWeight.scorer(hits.context());
       if (s == null) {
         // no matching docs by the fast match query
         return null;
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
index 30a957b786d..a6348fbac56 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/FacetsCollector.java
@@ -44,31 +44,16 @@ public class FacetsCollector extends SimpleCollector {
   private DocIdSetBuilder docsBuilder;
 
   /**
-   * Holds the documents that were matched in the {@link org.apache.lucene.index.LeafReaderContext}.
-   * If scores were required, then {@code scores} is not null.
+   * Holds the documents that were matched in the {@link LeafReaderContext}. If scores were
+   * required, then {@code scores} is not null.
+   *
+   * @param context Context for this segment.
+   * @param bits Which documents were seen.
+   * @param scores Non-sparse scores array.
+   * @param totalHits Total number of hits
    */
-  public static final class MatchingDocs {
-
-    /** Context for this segment. */
-    public final LeafReaderContext context;
-
-    /** Which documents were seen. */
-    public final DocIdSet bits;
-
-    /** Non-sparse scores array. */
-    public final float[] scores;
-
-    /** Total number of hits */
-    public final int totalHits;
-
-    /** Sole constructor. */
-    public MatchingDocs(LeafReaderContext context, DocIdSet bits, int totalHits, float[] scores) {
-      this.context = context;
-      this.bits = bits;
-      this.scores = scores;
-      this.totalHits = totalHits;
-    }
-  }
+  public record MatchingDocs(
+      LeafReaderContext context, DocIdSet bits, int totalHits, float[] scores) {}
 
   /** Default constructor */
   public FacetsCollector() {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/LongValueFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/LongValueFacetCounts.java
index f83b64912a3..346c2dc369e 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/LongValueFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/LongValueFacetCounts.java
@@ -172,19 +172,19 @@ public class LongValueFacetCounts extends Facets {
       throws IOException {
 
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeCounters();
 
-      LongValues fv = valueSource.getValues(hits.context, null);
+      LongValues fv = valueSource.getValues(hits.context(), null);
 
       // NOTE: this is not as efficient as working directly with the doc values APIs in the sparse
       // case
       // because we are doing a linear scan across all hits, but this API is more flexible since a
       // LongValuesSource can compute interesting values at query time
 
-      DocIdSetIterator docs = hits.bits.iterator();
+      DocIdSetIterator docs = hits.bits().iterator();
       for (int doc = docs.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
         if (fv.advanceExact(doc)) {
@@ -201,14 +201,14 @@ public class LongValueFacetCounts extends Facets {
   private void count(MultiLongValuesSource valuesSource, List<MatchingDocs> matchingDocs)
       throws IOException {
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeCounters();
 
-      MultiLongValues multiValues = valuesSource.getValues(hits.context);
+      MultiLongValues multiValues = valuesSource.getValues(hits.context());
 
-      DocIdSetIterator docs = hits.bits.iterator();
+      DocIdSetIterator docs = hits.bits().iterator();
       for (int doc = docs.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
         if (multiValues.advanceExact(doc)) {
@@ -235,18 +235,20 @@ public class LongValueFacetCounts extends Facets {
   /** Counts from the field's indexed doc values. */
   private void count(String field, List<MatchingDocs> matchingDocs) throws IOException {
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeCounters();
 
-      SortedNumericDocValues multiValues = DocValues.getSortedNumeric(hits.context.reader(), field);
+      SortedNumericDocValues multiValues =
+          DocValues.getSortedNumeric(hits.context().reader(), field);
       NumericDocValues singleValues = DocValues.unwrapSingleton(multiValues);
 
       if (singleValues != null) {
 
         DocIdSetIterator it =
-            ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), singleValues));
+            ConjunctionUtils.intersectIterators(
+                Arrays.asList(hits.bits().iterator(), singleValues));
 
         for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
           increment(singleValues.longValue());
@@ -255,7 +257,7 @@ public class LongValueFacetCounts extends Facets {
       } else {
 
         DocIdSetIterator it =
-            ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), multiValues));
+            ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), multiValues));
 
         for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
           int limit = multiValues.docValueCount();
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/RandomSamplingFacetsCollector.java b/lucene/facet/src/java/org/apache/lucene/facet/RandomSamplingFacetsCollector.java
index de7c0e27323..de0676e0454 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/RandomSamplingFacetsCollector.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/RandomSamplingFacetsCollector.java
@@ -33,7 +33,7 @@ import org.apache.lucene.util.FixedBitSet;
  * Collects hits for subsequent faceting, using sampling if needed. Once you've run a search and
  * collect hits into this, instantiate one of the {@link Facets} subclasses to do the facet
  * counting. Note that this collector does not collect the scores of matching docs (i.e. {@link
- * FacetsCollector.MatchingDocs#scores}) is {@code null}.
+ * FacetsCollector.MatchingDocs#scores()}) is {@code null}.
  *
  * <p>If you require the original set of hits, you can call {@link #getOriginalMatchingDocs()}.
  * Also, since the counts of the top-facets is based on the sampled set, you can amortize the counts
@@ -125,7 +125,7 @@ public class RandomSamplingFacetsCollector extends FacetsCollector {
     if (totalHits == NOT_CALCULATED) {
       totalHits = 0;
       for (MatchingDocs md : matchingDocs) {
-        totalHits += md.totalHits;
+        totalHits += md.totalHits();
       }
     }
 
@@ -156,7 +156,7 @@ public class RandomSamplingFacetsCollector extends FacetsCollector {
 
   /** Create a sampled of the given hits. */
   private MatchingDocs createSample(MatchingDocs docs) {
-    int maxdoc = docs.context.reader().maxDoc();
+    int maxdoc = docs.context().reader().maxDoc();
 
     // TODO: we could try the WAH8DocIdSet here as well, as the results will be sparse
     FixedBitSet sampleDocs = new FixedBitSet(maxdoc);
@@ -175,7 +175,7 @@ public class RandomSamplingFacetsCollector extends FacetsCollector {
         limit = binSize;
         randomIndex = random.nextInt(binSize);
       }
-      final DocIdSetIterator it = docs.bits.iterator();
+      final DocIdSetIterator it = docs.bits().iterator();
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
         if (counter == randomIndex) {
           sampleDocs.set(doc);
@@ -206,7 +206,7 @@ public class RandomSamplingFacetsCollector extends FacetsCollector {
         }
       }
 
-      return new MatchingDocs(docs.context, new BitDocIdSet(sampleDocs), docs.totalHits, null);
+      return new MatchingDocs(docs.context(), new BitDocIdSet(sampleDocs), docs.totalHits(), null);
     } catch (IOException e) {
       throw new RuntimeException(e);
     }
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/StringValueFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/StringValueFacetCounts.java
index 655e80546f8..a3b6e85ad07 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/StringValueFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/StringValueFacetCounts.java
@@ -108,8 +108,8 @@ public class StringValueFacetCounts extends Facets {
         int totalHits = 0;
         int totalDocs = 0;
         for (FacetsCollector.MatchingDocs matchingDocs : facetsCollector.getMatchingDocs()) {
-          totalHits += matchingDocs.totalHits;
-          totalDocs += matchingDocs.context.reader().maxDoc();
+          totalHits += matchingDocs.totalHits();
+          totalDocs += matchingDocs.context().reader().maxDoc();
         }
 
         // No counting needed if there are no hits:
@@ -297,22 +297,22 @@ public class StringValueFacetCounts extends Facets {
     if (matchingDocs.size() == 1) {
 
       FacetsCollector.MatchingDocs hits = matchingDocs.get(0);
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         return;
       }
 
       // Validate state before doing anything else:
-      validateState(hits.context);
+      validateState(hits.context());
 
       // Assuming the state is valid, ordinalMap should be null since we have one segment:
       assert ordinalMap == null;
 
-      countOneSegment(docValues, hits.context.ord, hits, null);
+      countOneSegment(docValues, hits.context().ord, hits, null);
     } else {
 
       // Validate state before doing anything else. We only check the first segment since they
       // should all ladder up to the same top-level reader:
-      validateState(matchingDocs.get(0).context);
+      validateState(matchingDocs.get(0).context());
 
       for (FacetsCollector.MatchingDocs hits : matchingDocs) {
         // Assuming the state is valid, ordinalMap should be non-null and docValues should be
@@ -320,14 +320,14 @@ public class StringValueFacetCounts extends Facets {
         assert ordinalMap != null;
         assert docValues instanceof MultiDocValues.MultiSortedSetDocValues;
 
-        if (hits.totalHits == 0) {
+        if (hits.totalHits() == 0) {
           continue;
         }
 
         MultiDocValues.MultiSortedSetDocValues multiValues =
             (MultiDocValues.MultiSortedSetDocValues) docValues;
 
-        countOneSegment(multiValues.values[hits.context.ord], hits.context.ord, hits, null);
+        countOneSegment(multiValues.values[hits.context().ord], hits.context().ord, hits, null);
       }
     }
   }
@@ -398,7 +398,7 @@ public class StringValueFacetCounts extends Facets {
       assert liveDocs != null;
       it = FacetUtils.liveDocsDISI(valuesIt, liveDocs);
     } else {
-      it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), valuesIt));
+      it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), valuesIt));
     }
 
     // TODO: yet another option is to count all segs
@@ -438,7 +438,7 @@ public class StringValueFacetCounts extends Facets {
       final LongValues ordMap = ordinalMap.getGlobalOrds(segmentOrd);
       int segmentCardinality = (int) multiValues.getValueCount();
 
-      if (hits != null && hits.totalHits < segmentCardinality / 10) {
+      if (hits != null && hits.totalHits() < segmentCardinality / 10) {
         // Remap every ord to global ord as we iterate:
         if (singleValues != null) {
           for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/facetset/DimRange.java b/lucene/facet/src/java/org/apache/lucene/facet/facetset/DimRange.java
index 777e91ad6c2..c4f0599b24c 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/facetset/DimRange.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/facetset/DimRange.java
@@ -21,25 +21,11 @@ import org.apache.lucene.util.NumericUtils;
 /**
  * Defines a single range in a {@link FacetSet} dimension.
  *
+ * @param min Inclusive min
+ * @param max Inclusive max
  * @lucene.experimental
  */
-public class DimRange {
-  /** Inclusive min */
-  public final long min;
-
-  /** Inclusive max */
-  public final long max;
-
-  /**
-   * Creates a LongRange.
-   *
-   * @param min inclusive min value in range
-   * @param max inclusive max value in range
-   */
-  public DimRange(long min, long max) {
-    this.min = min;
-    this.max = max;
-  }
+public record DimRange(long min, long max) {
 
   /**
    * Creates a {@link DimRange} for the given min and max long values. This method is also suitable
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/facetset/MatchingFacetSetsCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/facetset/MatchingFacetSetsCounts.java
index c8151ab471e..b17730e7e42 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/facetset/MatchingFacetSetsCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/facetset/MatchingFacetSetsCounts.java
@@ -91,7 +91,7 @@ public class MatchingFacetSetsCounts extends FacetCountsWithFilterQuery {
     int totCount = 0;
     for (FacetsCollector.MatchingDocs hits : matchingDocs) {
 
-      BinaryDocValues binaryDocValues = DocValues.getBinary(hits.context.reader(), field);
+      BinaryDocValues binaryDocValues = DocValues.getBinary(hits.context().reader(), field);
 
       final DocIdSetIterator it = createIterator(hits, binaryDocValues);
       if (it == null) {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/facetset/RangeFacetSetMatcher.java b/lucene/facet/src/java/org/apache/lucene/facet/facetset/RangeFacetSetMatcher.java
index 9ed12e0b6b2..926237a5327 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/facetset/RangeFacetSetMatcher.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/facetset/RangeFacetSetMatcher.java
@@ -34,8 +34,8 @@ public class RangeFacetSetMatcher extends FacetSetMatcher {
    */
   public RangeFacetSetMatcher(String label, DimRange... dimRanges) {
     super(label, getDims(dimRanges));
-    this.lowerRanges = Arrays.stream(dimRanges).mapToLong(range -> range.min).toArray();
-    this.upperRanges = Arrays.stream(dimRanges).mapToLong(range -> range.max).toArray();
+    this.lowerRanges = Arrays.stream(dimRanges).mapToLong(DimRange::min).toArray();
+    this.upperRanges = Arrays.stream(dimRanges).mapToLong(DimRange::max).toArray();
   }
 
   @Override
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java
index 701d2471bb4..d2d9d95480a 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/DoubleRangeFacetCounts.java
@@ -160,7 +160,7 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
     LongRangeCounter counter = null;
     int missingCount = 0;
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
 
@@ -173,8 +173,8 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
         counter = setupCounter();
       }
 
-      DoubleValues fv = valueSource.getValues(hits.context, null);
-      totCount += hits.totalHits;
+      DoubleValues fv = valueSource.getValues(hits.context(), null);
+      totCount += hits.totalHits();
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
@@ -201,7 +201,7 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
     LongRangeCounter counter = null; // LongRangeCounter.create(longRanges, counts);
     int missingCount = 0;
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
 
@@ -214,7 +214,7 @@ public class DoubleRangeFacetCounts extends RangeFacetCounts {
         counter = setupCounter();
       }
 
-      MultiDoubleValues multiValues = valueSource.getValues(hits.context);
+      MultiDoubleValues multiValues = valueSource.getValues(hits.context());
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/ExclusiveLongRangeCounter.java b/lucene/facet/src/java/org/apache/lucene/facet/range/ExclusiveLongRangeCounter.java
index f8c4d7e763f..e6f852b6b10 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/ExclusiveLongRangeCounter.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/ExclusiveLongRangeCounter.java
@@ -161,13 +161,5 @@ class ExclusiveLongRangeCounter extends LongRangeCounter {
   }
 
   /** Simple container for a requested range and its original position */
-  private static final class LongRangeAndPos {
-    final LongRange range;
-    final int pos;
-
-    LongRangeAndPos(LongRange range, int pos) {
-      this.range = range;
-      this.pos = pos;
-    }
-  }
+  private record LongRangeAndPos(LongRange range, int pos) {}
 }
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java
index 34aa3fcd062..adb06006931 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/LongRangeFacetCounts.java
@@ -133,7 +133,7 @@ public class LongRangeFacetCounts extends RangeFacetCounts {
     int missingCount = 0;
 
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
 
@@ -146,8 +146,8 @@ public class LongRangeFacetCounts extends RangeFacetCounts {
         counter = setupCounter();
       }
 
-      LongValues fv = valueSource.getValues(hits.context, null);
-      totCount += hits.totalHits;
+      LongValues fv = valueSource.getValues(hits.context(), null);
+      totCount += hits.totalHits();
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
@@ -174,7 +174,7 @@ public class LongRangeFacetCounts extends RangeFacetCounts {
     LongRangeCounter counter = null;
 
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
 
@@ -187,7 +187,7 @@ public class LongRangeFacetCounts extends RangeFacetCounts {
         counter = setupCounter();
       }
 
-      MultiLongValues multiValues = valueSource.getValues(hits.context);
+      MultiLongValues multiValues = valueSource.getValues(hits.context());
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         // Skip missing docs:
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/range/RangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/range/RangeFacetCounts.java
index 8bf9c352e34..8ab9a5f3648 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/range/RangeFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/range/RangeFacetCounts.java
@@ -80,11 +80,12 @@ abstract class RangeFacetCounts extends FacetCountsWithFilterQuery {
 
     for (int i = 0; i < matchingDocs.size(); i++) {
       FacetsCollector.MatchingDocs hits = matchingDocs.get(i);
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
 
-      SortedNumericDocValues multiValues = DocValues.getSortedNumeric(hits.context.reader(), field);
+      SortedNumericDocValues multiValues =
+          DocValues.getSortedNumeric(hits.context().reader(), field);
       if (multiValuedDocVals == null) {
         multiValuedDocVals = new SortedNumericDocValues[matchingDocs.size()];
       }
@@ -135,7 +136,7 @@ abstract class RangeFacetCounts extends FacetCountsWithFilterQuery {
         assert singleValuedDocVals != null;
         NumericDocValues singleValues = singleValuedDocVals[i];
 
-        totCount += hits.totalHits;
+        totCount += hits.totalHits();
         for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
           if (singleValues.advanceExact(doc)) {
             counter.addSingleValued(mapDocValue(singleValues.longValue()));
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/rangeonrange/RangeOnRangeFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/rangeonrange/RangeOnRangeFacetCounts.java
index 86c665d6e84..7aee5bfdda2 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/rangeonrange/RangeOnRangeFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/rangeonrange/RangeOnRangeFacetCounts.java
@@ -89,14 +89,14 @@ abstract class RangeOnRangeFacetCounts extends FacetCountsWithFilterQuery {
 
       BinaryRangeDocValues binaryRangeDocValues =
           new BinaryRangeDocValues(
-              DocValues.getBinary(hits.context.reader(), field), dims, numEncodedValueBytes);
+              DocValues.getBinary(hits.context().reader(), field), dims, numEncodedValueBytes);
 
       final DocIdSetIterator it = createIterator(hits);
       if (it == null) {
         continue;
       }
 
-      totCount += hits.totalHits;
+      totCount += hits.totalHits();
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; ) {
         if (binaryRangeDocValues.advanceExact(doc)) {
           boolean hasValidRange = false;
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/AbstractSortedSetDocValueFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/AbstractSortedSetDocValueFacetCounts.java
index 03a0ce72190..c67f41fe1fa 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/AbstractSortedSetDocValueFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/AbstractSortedSetDocValueFacetCounts.java
@@ -183,7 +183,7 @@ abstract class AbstractSortedSetDocValueFacetCounts extends Facets {
         dimCount = getCount(dimOrd);
       } else {
         OrdRange ordRange = state.getOrdRange(dim);
-        int dimOrd = ordRange.start;
+        int dimOrd = ordRange.start();
         if (dimConfig.multiValued) {
           if (dimConfig.requireDimCount) {
             // If a dim is configured as multi-valued and requires dim count, we index dim counts
@@ -284,7 +284,7 @@ abstract class AbstractSortedSetDocValueFacetCounts extends Facets {
         // means dimension was never indexed
         return null;
       }
-      pathOrd = ordRange.start;
+      pathOrd = ordRange.start();
       childIterator = ordRange.iterator();
       if (dimConfig.multiValued && dimConfig.requireDimCount) {
         // If the dim is multi-valued and requires dim counts, we know we've explicitly indexed
@@ -412,13 +412,5 @@ abstract class AbstractSortedSetDocValueFacetCounts extends Facets {
     }
   }
 
-  static final class ChildIterationCursor {
-    final int pathOrd;
-    final PrimitiveIterator.OfInt childIterator;
-
-    ChildIterationCursor(int pathOrd, PrimitiveIterator.OfInt childIterator) {
-      this.pathOrd = pathOrd;
-      this.childIterator = childIterator;
-    }
-  }
+  record ChildIterationCursor(int pathOrd, PrimitiveIterator.OfInt childIterator) {}
 }
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/ConcurrentSortedSetDocValuesFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/ConcurrentSortedSetDocValuesFacetCounts.java
index 0b03da9135b..3a74805a8d8 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/ConcurrentSortedSetDocValuesFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/ConcurrentSortedSetDocValuesFacetCounts.java
@@ -107,7 +107,7 @@ public class ConcurrentSortedSetDocValuesFacetCounts extends AbstractSortedSetDo
     @Override
     public Void call() throws IOException {
       // If we're counting collected hits but there were none, short-circuit:
-      if (hits != null && hits.totalHits == 0) {
+      if (hits != null && hits.totalHits() == 0) {
         return null;
       }
 
@@ -140,7 +140,7 @@ public class ConcurrentSortedSetDocValuesFacetCounts extends AbstractSortedSetDo
         final Bits liveDocs = leafReader.getLiveDocs();
         it = (liveDocs != null) ? FacetUtils.liveDocsDISI(valuesIt, liveDocs) : valuesIt;
       } else {
-        it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), valuesIt));
+        it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), valuesIt));
       }
 
       if (ordinalMap != null) {
@@ -148,7 +148,7 @@ public class ConcurrentSortedSetDocValuesFacetCounts extends AbstractSortedSetDo
 
         int numSegOrds = (int) multiValues.getValueCount();
 
-        if (hits != null && hits.totalHits < numSegOrds / 10) {
+        if (hits != null && hits.totalHits() < numSegOrds / 10) {
           // Remap every ord to global ord as we iterate:
           if (singleValues != null) {
             if (singleValues == it) {
@@ -295,14 +295,14 @@ public class ConcurrentSortedSetDocValuesFacetCounts extends AbstractSortedSetDo
       // the top-level reader passed to the
       // SortedSetDocValuesReaderState, else cryptic
       // AIOOBE can happen:
-      if (ReaderUtil.getTopLevelContext(hits.context).reader() != reader) {
+      if (ReaderUtil.getTopLevelContext(hits.context()).reader() != reader) {
         throw new IllegalStateException(
             "the SortedSetDocValuesReaderState provided to this class does not match the reader being searched; you must create a new SortedSetDocValuesReaderState every time you open a new IndexReader");
       }
 
       results.add(
           exec.submit(
-              new CountOneSegment(hits.context.reader(), hits, ordinalMap, hits.context.ord)));
+              new CountOneSegment(hits.context().reader(), hits, ordinalMap, hits.context().ord)));
     }
 
     for (Future<Void> result : results) {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesFacetCounts.java
index 0d0cf460bfd..2bb6704bc44 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesFacetCounts.java
@@ -174,7 +174,7 @@ public class SortedSetDocValuesFacetCounts extends AbstractSortedSetDocValueFace
   private void countOneSegment(
       OrdinalMap ordinalMap, LeafReader reader, int segOrd, MatchingDocs hits, Bits liveDocs)
       throws IOException {
-    if (hits != null && hits.totalHits == 0) {
+    if (hits != null && hits.totalHits() == 0) {
       return;
     }
 
@@ -197,7 +197,7 @@ public class SortedSetDocValuesFacetCounts extends AbstractSortedSetDocValueFace
       assert liveDocs != null;
       it = FacetUtils.liveDocsDISI(valuesIt, liveDocs);
     } else {
-      it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), valuesIt));
+      it = ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), valuesIt));
     }
 
     // TODO: yet another option is to count all segs
@@ -214,7 +214,7 @@ public class SortedSetDocValuesFacetCounts extends AbstractSortedSetDocValueFace
 
       int numSegOrds = (int) multiValues.getValueCount();
 
-      if (hits != null && hits.totalHits < numSegOrds / 10) {
+      if (hits != null && hits.totalHits() < numSegOrds / 10) {
         // Remap every ord to global ord as we iterate:
         if (singleValues != null) {
           for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
@@ -293,12 +293,12 @@ public class SortedSetDocValuesFacetCounts extends AbstractSortedSetDocValueFace
       // the top-level reader passed to the
       // SortedSetDocValuesReaderState, else cryptic
       // AIOOBE can happen:
-      if (ReaderUtil.getTopLevelContext(hits.context).reader() != reader) {
+      if (ReaderUtil.getTopLevelContext(hits.context()).reader() != reader) {
         throw new IllegalStateException(
             "the SortedSetDocValuesReaderState provided to this class does not match the reader being searched; you must create a new SortedSetDocValuesReaderState every time you open a new IndexReader");
       }
 
-      countOneSegment(ordinalMap, hits.context.reader(), hits.context.ord, hits, null);
+      countOneSegment(ordinalMap, hits.context().reader(), hits.context().ord, hits, null);
     }
   }
 
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java
index 31de3678db2..3f387faec7b 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/sortedset/SortedSetDocValuesReaderState.java
@@ -38,20 +38,13 @@ import org.apache.lucene.util.FixedBitSet;
  */
 public abstract class SortedSetDocValuesReaderState implements Accountable {
 
-  /** Holds start/end range of ords, which maps to one dimension. Only used for flat hierarchies. */
-  public static final class OrdRange {
-    /** Start of range, inclusive: */
-    public final int start;
-
-    /** End of range, inclusive: */
-    public final int end;
-
-    /** Start and end are inclusive. */
-    public OrdRange(int start, int end) {
-      this.start = start;
-      this.end = end;
-    }
-
+  /**
+   * Holds start/end range of ords, which maps to one dimension. Only used for flat hierarchies.
+   *
+   * @param start Start of range, inclusive:
+   * @param end End of range, inclusive:
+   */
+  public record OrdRange(int start, int end) {
     /** Iterates from start to end ord (inclusive) */
     public PrimitiveIterator.OfInt iterator() {
       return new PrimitiveIterator.OfInt() {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java
index 86ba905ab71..b47000368a9 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/FastTaxonomyFacetCounts.java
@@ -71,11 +71,11 @@ public class FastTaxonomyFacetCounts extends TaxonomyFacets {
 
   private void count(List<MatchingDocs> matchingDocs) throws IOException {
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       SortedNumericDocValues multiValued =
-          hits.context.reader().getSortedNumericDocValues(indexFieldName);
+          hits.context().reader().getSortedNumericDocValues(indexFieldName);
       if (multiValued == null) {
         continue;
       }
@@ -85,7 +85,7 @@ public class FastTaxonomyFacetCounts extends TaxonomyFacets {
 
       DocIdSetIterator valuesIt = singleValued != null ? singleValued : multiValued;
       DocIdSetIterator it =
-          ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), valuesIt));
+          ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), valuesIt));
 
       if (singleValued != null) {
         if (counts != null) {
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/SearcherTaxonomyManager.java b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/SearcherTaxonomyManager.java
index 68abc6930ae..5b768f48a05 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/SearcherTaxonomyManager.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/SearcherTaxonomyManager.java
@@ -38,20 +38,14 @@ import org.apache.lucene.util.IOUtils;
 public class SearcherTaxonomyManager
     extends ReferenceManager<SearcherTaxonomyManager.SearcherAndTaxonomy> {
 
-  /** Holds a matched pair of {@link IndexSearcher} and {@link TaxonomyReader} */
-  public static class SearcherAndTaxonomy {
-    /** Point-in-time {@link IndexSearcher}. */
-    public final IndexSearcher searcher;
-
-    /** Matching point-in-time {@link DirectoryTaxonomyReader}. */
-    public final DirectoryTaxonomyReader taxonomyReader;
-
-    /** Create a SearcherAndTaxonomy */
-    public SearcherAndTaxonomy(IndexSearcher searcher, DirectoryTaxonomyReader taxonomyReader) {
-      this.searcher = searcher;
-      this.taxonomyReader = taxonomyReader;
-    }
-  }
+  /**
+   * Holds a matched pair of {@link IndexSearcher} and {@link TaxonomyReader}
+   *
+   * @param searcher Point-in-time {@link IndexSearcher}.
+   * @param taxonomyReader Matching point-in-time {@link DirectoryTaxonomyReader}.
+   */
+  public record SearcherAndTaxonomy(
+      IndexSearcher searcher, DirectoryTaxonomyReader taxonomyReader) {}
 
   private final SearcherFactory searcherFactory;
   private final long taxoEpoch;
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetFloatAssociations.java b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetFloatAssociations.java
index 879d7fdf0c0..067db343b5d 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetFloatAssociations.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetFloatAssociations.java
@@ -115,7 +115,7 @@ public class TaxonomyFacetFloatAssociations extends FloatTaxonomyFacets {
 
       @Override
       public double doubleValue() throws IOException {
-        return hits.scores[index];
+        return hits.scores()[index];
       }
 
       @Override
@@ -134,17 +134,17 @@ public class TaxonomyFacetFloatAssociations extends FloatTaxonomyFacets {
       DoubleValuesSource valueSource)
       throws IOException {
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeValueCounters();
 
       SortedNumericDocValues ordinalValues =
-          DocValues.getSortedNumeric(hits.context.reader(), indexFieldName);
+          DocValues.getSortedNumeric(hits.context().reader(), indexFieldName);
       DoubleValues scores = keepScores ? scores(hits) : null;
-      DoubleValues functionValues = valueSource.getValues(hits.context, scores);
+      DoubleValues functionValues = valueSource.getValues(hits.context(), scores);
       DocIdSetIterator it =
-          ConjunctionUtils.intersectIterators(List.of(hits.bits.iterator(), ordinalValues));
+          ConjunctionUtils.intersectIterators(List.of(hits.bits().iterator(), ordinalValues));
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
         if (functionValues.advanceExact(doc)) {
@@ -171,14 +171,14 @@ public class TaxonomyFacetFloatAssociations extends FloatTaxonomyFacets {
       throws IOException {
 
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeValueCounters();
 
-      BinaryDocValues dv = DocValues.getBinary(hits.context.reader(), indexFieldName);
+      BinaryDocValues dv = DocValues.getBinary(hits.context().reader(), indexFieldName);
       DocIdSetIterator it =
-          ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits.iterator(), dv));
+          ConjunctionUtils.intersectIterators(Arrays.asList(hits.bits().iterator(), dv));
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
         final BytesRef bytesRef = dv.binaryValue();
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetIntAssociations.java b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetIntAssociations.java
index 86cc3d1f714..363d6f6c24c 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetIntAssociations.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacetIntAssociations.java
@@ -63,13 +63,14 @@ public class TaxonomyFacetIntAssociations extends IntTaxonomyFacets {
       AssociationAggregationFunction aggregationFunction, List<MatchingDocs> matchingDocs)
       throws IOException {
     for (MatchingDocs hits : matchingDocs) {
-      if (hits.totalHits == 0) {
+      if (hits.totalHits() == 0) {
         continue;
       }
       initializeValueCounters();
 
-      BinaryDocValues dv = DocValues.getBinary(hits.context.reader(), indexFieldName);
-      DocIdSetIterator it = ConjunctionUtils.intersectIterators(List.of(hits.bits.iterator(), dv));
+      BinaryDocValues dv = DocValues.getBinary(hits.context().reader(), indexFieldName);
+      DocIdSetIterator it =
+          ConjunctionUtils.intersectIterators(List.of(hits.bits().iterator(), dv));
 
       for (int doc = it.nextDoc(); doc != DocIdSetIterator.NO_MORE_DOCS; doc = it.nextDoc()) {
         final BytesRef bytesRef = dv.binaryValue();
diff --git a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java
index 8c0b1ddb6aa..49bc0b95439 100644
--- a/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java
+++ b/lucene/facet/src/java/org/apache/lucene/facet/taxonomy/TaxonomyFacets.java
@@ -128,8 +128,8 @@ abstract class TaxonomyFacets extends Facets {
     int maxDoc = 0;
     int sumTotalHits = 0;
     for (FacetsCollector.MatchingDocs docs : fc.getMatchingDocs()) {
-      sumTotalHits += docs.totalHits;
-      maxDoc += docs.context.reader().maxDoc();
+      sumTotalHits += docs.totalHits();
+      maxDoc += docs.context().reader().maxDoc();
     }
 
     // if our result set is < 10% of the index, we collect sparsely (use hash map):
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/FacetTestCase.java b/lucene/facet/src/test/org/apache/lucene/facet/FacetTestCase.java
index 1023bb4cce3..ea6c06b87a5 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/FacetTestCase.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/FacetTestCase.java
@@ -68,8 +68,8 @@ public abstract class FacetTestCase extends LuceneTestCase {
     TaxonomyFacetLabels taxoLabels =
         new TaxonomyFacetLabels(taxoReader, FacetsConfig.DEFAULT_INDEX_FIELD_NAME);
     for (MatchingDocs m : fc.getMatchingDocs()) {
-      FacetLabelReader facetLabelReader = taxoLabels.getFacetLabelReader(m.context);
-      DocIdSetIterator disi = m.bits.iterator();
+      FacetLabelReader facetLabelReader = taxoLabels.getFacetLabelReader(m.context());
+      DocIdSetIterator disi = m.bits().iterator();
       while (disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
         actualLabels.add(allFacetLabels(disi.docID(), dimension, facetLabelReader));
       }
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
index fa82e921eb8..9a8bc0913a1 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestDrillSideways.java
@@ -1485,7 +1485,8 @@ public class TestDrillSideways extends FacetTestCase {
         // context, which happens as part of #finish getting called:
         assertEquals(1, result.drillDownFacetsCollector.getMatchingDocs().size());
         assertEquals(
-            1, result.drillDownFacetsCollector.getMatchingDocs().get(0).context.reader().maxDoc());
+            1,
+            result.drillDownFacetsCollector.getMatchingDocs().get(0).context().reader().maxDoc());
         assertEquals(1, result.drillSidewaysFacetsCollector.length);
         assertEquals(1, result.drillSidewaysFacetsCollector[0].getMatchingDocs().size());
         assertEquals(
@@ -1494,7 +1495,7 @@ public class TestDrillSideways extends FacetTestCase {
                 .drillSidewaysFacetsCollector[0]
                 .getMatchingDocs()
                 .get(0)
-                .context
+                .context()
                 .reader()
                 .maxDoc());
       }
@@ -1560,15 +1561,7 @@ public class TestDrillSideways extends FacetTestCase {
     Facets facets;
   }
 
-  private static class CollectedResult {
-    final DocAndScore docAndScore;
-    final String id;
-
-    CollectedResult(DocAndScore docAndScore, String id) {
-      this.docAndScore = docAndScore;
-      this.id = id;
-    }
-  }
+  private record CollectedResult(DocAndScore docAndScore, String id) {}
 
   private abstract static class SimpleLeafCollector implements LeafCollector {
     protected Scorable scorer;
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestFacetUtils.java b/lucene/facet/src/test/org/apache/lucene/facet/TestFacetUtils.java
index 8c78d9b01fd..0f018ea9a8f 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestFacetUtils.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestFacetUtils.java
@@ -79,8 +79,8 @@ public class TestFacetUtils extends LuceneTestCase {
     DocIdSetIterator disi;
 
     for (FacetsCollector.MatchingDocs m : fc.getMatchingDocs()) {
-      NumericDocValues numericDV = DocValues.getNumeric(m.context.reader(), "val");
-      Bits liveDocs = m.context.reader().getLiveDocs();
+      NumericDocValues numericDV = DocValues.getNumeric(m.context().reader(), "val");
+      Bits liveDocs = m.context().reader().getLiveDocs();
       // Only use the liveDocsDISI if liveDocs is not null
       disi = (liveDocs == null) ? numericDV : FacetUtils.liveDocsDISI(numericDV, liveDocs);
 
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/TestRandomSamplingFacetsCollector.java b/lucene/facet/src/test/org/apache/lucene/facet/TestRandomSamplingFacetsCollector.java
index 9eb45ba2c3a..93b7963ff5e 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/TestRandomSamplingFacetsCollector.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/TestRandomSamplingFacetsCollector.java
@@ -85,7 +85,7 @@ public class TestRandomSamplingFacetsCollector extends FacetTestCase {
 
     // There should be no results at all
     for (MatchingDocs doc : collectRandomZeroResults.getMatchingDocs()) {
-      assertEquals(0, doc.totalHits);
+      assertEquals(0, doc.totalHits());
     }
 
     // Now start searching and retrieve results.
@@ -106,17 +106,17 @@ public class TestRandomSamplingFacetsCollector extends FacetTestCase {
     //    System.out.println("numSegments=" + numSampledDocs.length);
     for (int i = 0; i < numSampledDocs.length; i++) {
       MatchingDocs md = matchingDocs.get(i);
-      final DocIdSetIterator iter = md.bits.iterator();
+      final DocIdSetIterator iter = md.bits().iterator();
       while (iter.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) ++numSampledDocs[i];
       totalSampledDocs += numSampledDocs[i];
-      totalHits += md.totalHits;
+      totalHits += md.totalHits();
     }
 
     // compute the chi-square value for the sampled documents' distribution
     float chi_square = 0;
     for (int i = 0; i < numSampledDocs.length; i++) {
       MatchingDocs md = matchingDocs.get(i);
-      float ei = (float) md.totalHits / totalHits;
+      float ei = (float) md.totalHits() / totalHits;
       if (ei > 0.0f) {
         float oi = (float) numSampledDocs[i] / totalSampledDocs;
         chi_square += (float) (Math.pow(ei - oi, 2) / ei);
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestOrdinalData.java b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestOrdinalData.java
index 47750b773b2..5b8556c1f88 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestOrdinalData.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestOrdinalData.java
@@ -57,12 +57,8 @@ public class TestOrdinalData extends FacetTestCase {
           "Bob", 42L,
           "Lisa", 35L);
 
-  private static class OrdinalDataAppender implements BiConsumer<FacetLabel, Document> {
-    private final Map<String, Long> scores;
-
-    private OrdinalDataAppender(Map<String, Long> scores) {
-      this.scores = scores;
-    }
+  private record OrdinalDataAppender(Map<String, Long> scores)
+      implements BiConsumer<FacetLabel, Document> {
 
     @Override
     public void accept(FacetLabel facetLabel, Document doc) {
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestSearcherTaxonomyManager.java b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestSearcherTaxonomyManager.java
index 10f56e63ad8..3f319acdb78 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestSearcherTaxonomyManager.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestSearcherTaxonomyManager.java
@@ -189,10 +189,10 @@ public class TestSearcherTaxonomyManager extends FacetTestCase {
         try {
           // System.out.println("search maxOrd=" + pair.taxonomyReader.getSize());
           FacetsCollector sfc =
-              pair.searcher.search(new MatchAllDocsQuery(), new FacetsCollectorManager());
-          Facets facets = getTaxonomyFacetCounts(pair.taxonomyReader, config, sfc);
+              pair.searcher().search(new MatchAllDocsQuery(), new FacetsCollectorManager());
+          Facets facets = getTaxonomyFacetCounts(pair.taxonomyReader(), config, sfc);
           FacetResult result = facets.getTopChildren(10, "field");
-          if (pair.searcher.getIndexReader().numDocs() > 0) {
+          if (pair.searcher().getIndexReader().numDocs() > 0) {
             // System.out.println(pair.taxonomyReader.getSize());
             assertTrue(result.childCount > 0);
             assertTrue(result.labelValues.length > 0);
@@ -244,10 +244,10 @@ public class TestSearcherTaxonomyManager extends FacetTestCase {
         try {
           // System.out.println("search maxOrd=" + pair.taxonomyReader.getSize());
           FacetsCollector sfc =
-              pair.searcher.search(new MatchAllDocsQuery(), new FacetsCollectorManager());
-          Facets facets = getTaxonomyFacetCounts(pair.taxonomyReader, config, sfc);
+              pair.searcher().search(new MatchAllDocsQuery(), new FacetsCollectorManager());
+          Facets facets = getTaxonomyFacetCounts(pair.taxonomyReader(), config, sfc);
           FacetResult result = facets.getTopChildren(10, "field");
-          if (pair.searcher.getIndexReader().numDocs() > 0) {
+          if (pair.searcher().getIndexReader().numDocs() > 0) {
             // System.out.println(pair.taxonomyReader.getSize());
             assertTrue(result.childCount > 0);
             assertTrue(result.labelValues.length > 0);
@@ -309,7 +309,7 @@ public class TestSearcherTaxonomyManager extends FacetTestCase {
     SearcherTaxonomyManager mgr = new SearcherTaxonomyManager(indexDir, taxoDir, null);
     SearcherAndTaxonomy pair = mgr.acquire();
     try {
-      assertEquals(1, pair.taxonomyReader.getSize());
+      assertEquals(1, pair.taxonomyReader().getSize());
     } finally {
       mgr.release(pair);
     }
@@ -323,7 +323,7 @@ public class TestSearcherTaxonomyManager extends FacetTestCase {
     mgr.maybeRefresh();
     pair = mgr.acquire();
     try {
-      assertEquals(3, pair.taxonomyReader.getSize());
+      assertEquals(3, pair.taxonomyReader().getSize());
     } finally {
       mgr.release(pair);
     }
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestTaxonomyFacetLabels.java b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestTaxonomyFacetLabels.java
index cdc583eaa4e..e452abc1748 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestTaxonomyFacetLabels.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/TestTaxonomyFacetLabels.java
@@ -73,7 +73,7 @@ public class TestTaxonomyFacetLabels extends FacetTestCase {
   }
 
   private List<Integer> allDocIds(MatchingDocs m, boolean decreasingDocIds) throws IOException {
-    DocIdSetIterator disi = m.bits.iterator();
+    DocIdSetIterator disi = m.bits().iterator();
     List<Integer> docIds = new ArrayList<>();
     while (disi.nextDoc() != DocIdSetIterator.NO_MORE_DOCS) {
       docIds.add(disi.docID());
@@ -106,7 +106,7 @@ public class TestTaxonomyFacetLabels extends FacetTestCase {
 
     for (MatchingDocs m : matchingDocs) {
       TaxonomyFacetLabels.FacetLabelReader facetLabelReader =
-          taxoLabels.getFacetLabelReader(m.context);
+          taxoLabels.getFacetLabelReader(m.context());
       List<Integer> docIds = allDocIds(m, decreasingDocIds);
       FacetLabel facetLabel;
       for (Integer docId : docIds) {
diff --git a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestAlwaysRefreshDirectoryTaxonomyReader.java b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestAlwaysRefreshDirectoryTaxonomyReader.java
index aedd0764751..64de01fa0c6 100644
--- a/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestAlwaysRefreshDirectoryTaxonomyReader.java
+++ b/lucene/facet/src/test/org/apache/lucene/facet/taxonomy/directory/TestAlwaysRefreshDirectoryTaxonomyReader.java
@@ -86,7 +86,7 @@ public class TestAlwaysRefreshDirectoryTaxonomyReader extends FacetTestCase {
      * the call flow here initializes {@link DirectoryTaxonomyReader#taxoArrays}. These reused
      * `taxoArrays` form the basis of the inconsistency *
      */
-    getTaxonomyFacetCounts(pair.taxonomyReader, config, sfc);
+    getTaxonomyFacetCounts(pair.taxonomyReader(), config, sfc);
 
     // now try to go back to checkpoint 1 and refresh the SearcherTaxonomyManager
 
@@ -112,8 +112,8 @@ public class TestAlwaysRefreshDirectoryTaxonomyReader extends FacetTestCase {
     } else {
       mgr.maybeRefresh();
       pair = mgr.acquire();
-      assertEquals(new FacetLabel("a"), pair.taxonomyReader.getPath(1));
-      assertEquals(-1, pair.taxonomyReader.getOrdinal(new FacetLabel("b")));
+      assertEquals(new FacetLabel("a"), pair.taxonomyReader().getPath(1));
+      assertEquals(-1, pair.taxonomyReader().getOrdinal(new FacetLabel("b")));
     }
 
     mgr.release(pair);
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupDocs.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupDocs.java
index 9c0eccf9512..ea0dbab8529 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupDocs.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupDocs.java
@@ -22,45 +22,20 @@ import org.apache.lucene.search.TotalHits;
 /**
  * Represents one group in the results.
  *
+ * @param groupValue The groupField value for all docs in this group; this may be null if hits did
+ *     not have the groupField.
+ * @param maxScore Max score in this group
+ * @param score Overall aggregated score of this group (currently only set by join queries).
+ * @param scoreDocs Hits; this may be {@link org.apache.lucene.search.FieldDoc} instances if the
+ *     withinGroupSort sorted by fields.
+ * @param totalHits Total hits within this group
+ * @param groupSortValues Matches the groupSort passed to {@link FirstPassGroupingCollector}.
  * @lucene.experimental
  */
-public class GroupDocs<T> {
-  /**
-   * The groupField value for all docs in this group; this may be null if hits did not have the
-   * groupField.
-   */
-  public final T groupValue;
-
-  /** Max score in this group */
-  public final float maxScore;
-
-  /** Overall aggregated score of this group (currently only set by join queries). */
-  public final float score;
-
-  /**
-   * Hits; this may be {@link org.apache.lucene.search.FieldDoc} instances if the withinGroupSort
-   * sorted by fields.
-   */
-  public final ScoreDoc[] scoreDocs;
-
-  /** Total hits within this group */
-  public final TotalHits totalHits;
-
-  /** Matches the groupSort passed to {@link FirstPassGroupingCollector}. */
-  public final Object[] groupSortValues;
-
-  public GroupDocs(
-      float score,
-      float maxScore,
-      TotalHits totalHits,
-      ScoreDoc[] scoreDocs,
-      T groupValue,
-      Object[] groupSortValues) {
-    this.score = score;
-    this.maxScore = maxScore;
-    this.totalHits = totalHits;
-    this.scoreDocs = scoreDocs;
-    this.groupValue = groupValue;
-    this.groupSortValues = groupSortValues;
-  }
-}
+public record GroupDocs<T>(
+    float score,
+    float maxScore,
+    TotalHits totalHits,
+    ScoreDoc[] scoreDocs,
+    T groupValue,
+    Object[] groupSortValues) {}
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java
index 4e56a12c902..275493c4709 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/GroupFacetCollector.java
@@ -229,54 +229,12 @@ public abstract class GroupFacetCollector extends SimpleCollector {
   }
 
   /** Represents a facet entry with a value and a count. */
-  public static class FacetEntry {
-
-    private final BytesRef value;
-    private final int count;
-
-    public FacetEntry(BytesRef value, int count) {
-      this.value = value;
-      this.count = count;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-
-      FacetEntry that = (FacetEntry) o;
-
-      if (count != that.count) return false;
-      if (!value.equals(that.value)) return false;
-
-      return true;
-    }
-
-    @Override
-    public int hashCode() {
-      int result = value.hashCode();
-      result = 31 * result + count;
-      return result;
-    }
+  public record FacetEntry(BytesRef value, int count) {
 
     @Override
     public String toString() {
       return "FacetEntry{" + "value=" + value.utf8ToString() + ", count=" + count + '}';
     }
-
-    /**
-     * @return The value of this facet entry
-     */
-    public BytesRef getValue() {
-      return value;
-    }
-
-    /**
-     * @return The count (number of groups) of this facet entry.
-     */
-    public int getCount() {
-      return count;
-    }
   }
 
   /**
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TermGroupFacetCollector.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TermGroupFacetCollector.java
index e49e517faa8..33052db4390 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TermGroupFacetCollector.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TermGroupFacetCollector.java
@@ -431,14 +431,5 @@ public abstract class TermGroupFacetCollector extends GroupFacetCollector {
     }
   }
 
-  private static class GroupedFacetHit {
-
-    final BytesRef groupValue;
-    final BytesRef facetValue;
-
-    GroupedFacetHit(BytesRef groupValue, BytesRef facetValue) {
-      this.groupValue = groupValue;
-      this.facetValue = facetValue;
-    }
-  }
+  private record GroupedFacetHit(BytesRef groupValue, BytesRef facetValue) {}
 }
diff --git a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java
index 3ceb388ca80..1f5e107f5f8 100644
--- a/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java
+++ b/lucene/grouping/src/java/org/apache/lucene/search/grouping/TopGroups.java
@@ -161,7 +161,7 @@ public class TopGroups<T> {
     float totalMaxScore = Float.NaN;
 
     for (int groupIDX = 0; groupIDX < numGroups; groupIDX++) {
-      final T groupValue = shardGroups[0].groups[groupIDX].groupValue;
+      final T groupValue = shardGroups[0].groups[groupIDX].groupValue();
       // System.out.println("  merge groupValue=" + groupValue + " sortValues=" +
       // Arrays.toString(shardGroups[0].groups[groupIDX].groupSortValues));
       float maxScore = Float.NaN;
@@ -172,11 +172,11 @@ public class TopGroups<T> {
         final TopGroups<T> shard = shardGroups[shardIDX];
         final GroupDocs<?> shardGroupDocs = shard.groups[groupIDX];
         if (groupValue == null) {
-          if (shardGroupDocs.groupValue != null) {
+          if (shardGroupDocs.groupValue() != null) {
             throw new IllegalArgumentException(
                 "group values differ across shards; you must pass same top groups to all shards' second-pass collector");
           }
-        } else if (!groupValue.equals(shardGroupDocs.groupValue)) {
+        } else if (!groupValue.equals(shardGroupDocs.groupValue())) {
           throw new IllegalArgumentException(
               "group values differ across shards; you must pass same top groups to all shards' second-pass collector");
         }
@@ -188,21 +188,22 @@ public class TopGroups<T> {
         */
 
         if (docSort.equals(Sort.RELEVANCE)) {
-          shardTopDocs[shardIDX] = new TopDocs(shardGroupDocs.totalHits, shardGroupDocs.scoreDocs);
+          shardTopDocs[shardIDX] =
+              new TopDocs(shardGroupDocs.totalHits(), shardGroupDocs.scoreDocs());
         } else {
           shardTopDocs[shardIDX] =
               new TopFieldDocs(
-                  shardGroupDocs.totalHits, shardGroupDocs.scoreDocs, docSort.getSort());
+                  shardGroupDocs.totalHits(), shardGroupDocs.scoreDocs(), docSort.getSort());
         }
 
         for (int i = 0; i < shardTopDocs[shardIDX].scoreDocs.length; i++) {
           shardTopDocs[shardIDX].scoreDocs[i].shardIndex = shardIDX;
         }
 
-        maxScore = nonNANmax(maxScore, shardGroupDocs.maxScore);
-        assert shardGroupDocs.totalHits.relation == Relation.EQUAL_TO;
-        totalHits += shardGroupDocs.totalHits.value;
-        scoreSum += shardGroupDocs.score;
+        maxScore = nonNANmax(maxScore, shardGroupDocs.maxScore());
+        assert shardGroupDocs.totalHits().relation == Relation.EQUAL_TO;
+        totalHits += shardGroupDocs.totalHits().value;
+        scoreSum += shardGroupDocs.score();
       }
 
       final TopDocs mergedTopDocs;
@@ -255,7 +256,7 @@ public class TopGroups<T> {
               new TotalHits(totalHits, TotalHits.Relation.EQUAL_TO),
               mergedScoreDocs,
               groupValue,
-              shardGroups[0].groups[groupIDX].groupSortValues);
+              shardGroups[0].groups[groupIDX].groupSortValues());
       totalMaxScore = nonNANmax(totalMaxScore, maxScore);
     }
 
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/BaseGroupSelectorTestCase.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/BaseGroupSelectorTestCase.java
index 5aa0c4b0bfe..c64ffbf52f0 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/BaseGroupSelectorTestCase.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/BaseGroupSelectorTestCase.java
@@ -67,10 +67,10 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
       Query filtered =
           new BooleanQuery.Builder()
               .add(topLevel, BooleanClause.Occur.MUST)
-              .add(filterQuery(topGroups.groups[i].groupValue), BooleanClause.Occur.FILTER)
+              .add(filterQuery(topGroups.groups[i].groupValue()), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10);
-      assertScoreDocsEquals(topGroups.groups[i].scoreDocs, td.scoreDocs);
+      assertScoreDocsEquals(topGroups.groups[i].scoreDocs(), td.scoreDocs);
       if (i == 0) {
         assertEquals(td.scoreDocs[0].doc, topDoc.scoreDocs[0].doc);
         assertEquals(td.scoreDocs[0].score, topDoc.scoreDocs[0].score, 0);
@@ -105,10 +105,10 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
       Query filtered =
           new BooleanQuery.Builder()
               .add(topLevel, BooleanClause.Occur.MUST)
-              .add(filterQuery(topGroups.groups[i].groupValue), BooleanClause.Occur.FILTER)
+              .add(filterQuery(topGroups.groups[i].groupValue()), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10);
-      assertScoreDocsEquals(topGroups.groups[i].scoreDocs, td.scoreDocs);
+      assertScoreDocsEquals(topGroups.groups[i].scoreDocs(), td.scoreDocs);
       // The top group should have sort values equal to the sort values of the top doc of
       // a top-level search sorted by the same Sort; subsequent groups should have sort values
       // that compare lower than their predecessor.
@@ -116,7 +116,7 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
         assertSortsBefore(topGroups.groups[i - 1], topGroups.groups[i]);
       } else {
         assertArrayEquals(
-            ((FieldDoc) topDoc.scoreDocs[0]).fields, topGroups.groups[0].groupSortValues);
+            ((FieldDoc) topDoc.scoreDocs[0]).fields, topGroups.groups[0].groupSortValues());
       }
     }
 
@@ -148,19 +148,19 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
       // top score returned by a simple search with no grouping; subsequent groups should
       // all have equal or lower maxScores
       if (i == 0) {
-        assertEquals(topDoc.scoreDocs[0].score, topGroups.groups[0].maxScore, 0);
+        assertEquals(topDoc.scoreDocs[0].score, topGroups.groups[0].maxScore(), 0);
       } else {
-        assertTrue(topGroups.groups[i].maxScore <= topGroups.groups[i - 1].maxScore);
+        assertTrue(topGroups.groups[i].maxScore() <= topGroups.groups[i - 1].maxScore());
       }
       // Groups themselves are ordered by a defined Sort, and each should give the same result as
       // the top-level query, filtered by the group value, with the same Sort
       Query filtered =
           new BooleanQuery.Builder()
               .add(topLevel, BooleanClause.Occur.MUST)
-              .add(filterQuery(topGroups.groups[i].groupValue), BooleanClause.Occur.FILTER)
+              .add(filterQuery(topGroups.groups[i].groupValue()), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10, sort);
-      assertScoreDocsEquals(td.scoreDocs, topGroups.groups[i].scoreDocs);
+      assertScoreDocsEquals(td.scoreDocs, topGroups.groups[i].scoreDocs());
     }
 
     shard.close();
@@ -350,10 +350,11 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
     assertEquals(singletonTopGroups.totalGroupCount, mergedTopGroups.totalGroupCount);
     assertEquals(singletonTopGroups.groups.length, mergedTopGroups.groups.length);
     for (int i = 0; i < singletonTopGroups.groups.length; i++) {
-      assertEquals(singletonTopGroups.groups[i].groupValue, mergedTopGroups.groups[i].groupValue);
       assertEquals(
-          singletonTopGroups.groups[i].scoreDocs.length,
-          mergedTopGroups.groups[i].scoreDocs.length);
+          singletonTopGroups.groups[i].groupValue(), mergedTopGroups.groups[i].groupValue());
+      assertEquals(
+          singletonTopGroups.groups[i].scoreDocs().length,
+          mergedTopGroups.groups[i].scoreDocs().length);
     }
 
     control.close();
@@ -379,8 +380,8 @@ public abstract class BaseGroupSelectorTestCase<T> extends AbstractGroupingTestC
   }
 
   private void assertSortsBefore(GroupDocs<T> first, GroupDocs<T> second) {
-    Object[] groupSortValues = second.groupSortValues;
-    Object[] prevSortValues = first.groupSortValues;
+    Object[] groupSortValues = second.groupSortValues();
+    Object[] prevSortValues = first.groupSortValues();
     assertTrue(((BytesRef) prevSortValues[0]).compareTo((BytesRef) groupSortValues[0]) <= 0);
     if (prevSortValues[0].equals(groupSortValues[0])) {
       assertTrue((long) prevSortValues[1] <= (long) groupSortValues[1]);
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestBlockGrouping.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestBlockGrouping.java
index 0ef44610145..18c02422f84 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestBlockGrouping.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestBlockGrouping.java
@@ -57,11 +57,12 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
     // We're sorting by score, so the score of the top group should be the same as the
     // score of the top document from the same query with no grouping
     TopDocs topDoc = searcher.search(topLevel, 1);
-    assertEquals(topDoc.scoreDocs[0].score, tg.groups[0].scoreDocs[0].score, 0);
-    assertEquals(topDoc.scoreDocs[0].doc, tg.groups[0].scoreDocs[0].doc);
+    assertEquals(topDoc.scoreDocs[0].score, tg.groups[0].scoreDocs()[0].score, 0);
+    assertEquals(topDoc.scoreDocs[0].doc, tg.groups[0].scoreDocs()[0].doc);
 
     for (int i = 0; i < tg.groups.length; i++) {
-      String bookName = searcher.storedFields().document(tg.groups[i].scoreDocs[0].doc).get("book");
+      String bookName =
+          searcher.storedFields().document(tg.groups[i].scoreDocs()[0].doc).get("book");
       // The contents of each group should be equal to the results of a search for
       // that group alone
       Query filtered =
@@ -70,7 +71,7 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
               .add(new TermQuery(new Term("book", bookName)), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10);
-      assertScoreDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs);
+      assertScoreDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs());
     }
 
     shard.close();
@@ -96,10 +97,11 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
     // The sort value of the top doc in the top group should be the same as the sort value
     // of the top result from the same search done with no grouping
     TopDocs topDoc = searcher.search(topLevel, 1, sort);
-    assertEquals(((FieldDoc) topDoc.scoreDocs[0]).fields[0], tg.groups[0].groupSortValues[0]);
+    assertEquals(((FieldDoc) topDoc.scoreDocs[0]).fields[0], tg.groups[0].groupSortValues()[0]);
 
     for (int i = 0; i < tg.groups.length; i++) {
-      String bookName = searcher.storedFields().document(tg.groups[i].scoreDocs[0].doc).get("book");
+      String bookName =
+          searcher.storedFields().document(tg.groups[i].scoreDocs()[0].doc).get("book");
       // The contents of each group should be equal to the results of a search for
       // that group alone, sorted by score
       Query filtered =
@@ -108,7 +110,7 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
               .add(new TermQuery(new Term("book", bookName)), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10);
-      assertScoreDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs);
+      assertScoreDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs());
       if (i > 1) {
         assertSortsBefore(tg.groups[i - 1], tg.groups[i]);
       }
@@ -137,10 +139,11 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
     // We're sorting by score, so the score of the top group should be the same as the
     // score of the top document from the same query with no grouping
     TopDocs topDoc = searcher.search(topLevel, 1);
-    assertEquals(topDoc.scoreDocs[0].score, (float) tg.groups[0].groupSortValues[0], 0);
+    assertEquals(topDoc.scoreDocs[0].score, (float) tg.groups[0].groupSortValues()[0], 0);
 
     for (int i = 0; i < tg.groups.length; i++) {
-      String bookName = searcher.storedFields().document(tg.groups[i].scoreDocs[0].doc).get("book");
+      String bookName =
+          searcher.storedFields().document(tg.groups[i].scoreDocs()[0].doc).get("book");
       // The contents of each group should be equal to the results of a search for
       // that group alone, sorted by length
       Query filtered =
@@ -149,12 +152,12 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
               .add(new TermQuery(new Term("book", bookName)), BooleanClause.Occur.FILTER)
               .build();
       TopDocs td = searcher.search(filtered, 10, sort);
-      assertFieldDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs);
+      assertFieldDocsEquals(td.scoreDocs, tg.groups[i].scoreDocs());
       // We're sorting by score, so the group sort value for each group should be a float,
       // and the value for the previous group should be higher or equal to the value for this one
       if (i > 0) {
-        float prevScore = (float) tg.groups[i - 1].groupSortValues[0];
-        float thisScore = (float) tg.groups[i].groupSortValues[0];
+        float prevScore = (float) tg.groups[i - 1].groupSortValues()[0];
+        float thisScore = (float) tg.groups[i].groupSortValues()[0];
         assertTrue(prevScore >= thisScore);
       }
     }
@@ -210,8 +213,8 @@ public class TestBlockGrouping extends AbstractGroupingTestCase {
   }
 
   private void assertSortsBefore(GroupDocs<?> first, GroupDocs<?> second) {
-    Object[] groupSortValues = second.groupSortValues;
-    Object[] prevSortValues = first.groupSortValues;
+    Object[] groupSortValues = second.groupSortValues();
+    Object[] prevSortValues = first.groupSortValues();
     assertTrue(((Long) prevSortValues[0]).compareTo((Long) groupSortValues[0]) <= 0);
   }
 
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestDistinctValuesCollector.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestDistinctValuesCollector.java
index 012c09cb087..3bf1a4024b4 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestDistinctValuesCollector.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestDistinctValuesCollector.java
@@ -485,24 +485,11 @@ public class TestDistinctValuesCollector extends AbstractGroupingTestCase {
         contentStrings.toArray(new String[contentStrings.size()]));
   }
 
-  private static class IndexContext {
-
-    final Directory directory;
-    final DirectoryReader indexReader;
-    final Map<String, Map<String, Set<String>>> searchTermToGroupCounts;
-    final String[] contentStrings;
-
-    IndexContext(
-        Directory directory,
-        DirectoryReader indexReader,
-        Map<String, Map<String, Set<String>>> searchTermToGroupCounts,
-        String[] contentStrings) {
-      this.directory = directory;
-      this.indexReader = indexReader;
-      this.searchTermToGroupCounts = searchTermToGroupCounts;
-      this.contentStrings = contentStrings;
-    }
-  }
+  private record IndexContext(
+      Directory directory,
+      DirectoryReader indexReader,
+      Map<String, Map<String, Set<String>>> searchTermToGroupCounts,
+      String[] contentStrings) {}
 
   private static class NullComparator implements Comparator<Comparable<?>> {
 
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupFacetCollector.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupFacetCollector.java
index 52e896bb6ec..96aa92c4a9b 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupFacetCollector.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupFacetCollector.java
@@ -123,15 +123,15 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
 
       entries = airportResult.getFacetEntries(0, limit);
       assertEquals(2, entries.size());
-      assertEquals("ams", entries.get(0).getValue().utf8ToString());
-      assertEquals(2, entries.get(0).getCount());
-      assertEquals("dus", entries.get(1).getValue().utf8ToString());
-      assertEquals(1, entries.get(1).getCount());
+      assertEquals("ams", entries.get(0).value().utf8ToString());
+      assertEquals(2, entries.get(0).count());
+      assertEquals("dus", entries.get(1).value().utf8ToString());
+      assertEquals(1, entries.get(1).count());
 
       entries = airportResult.getFacetEntries(1, limit);
       assertEquals(1, entries.size());
-      assertEquals("dus", entries.get(0).getValue().utf8ToString());
-      assertEquals(1, entries.get(0).getCount());
+      assertEquals("dus", entries.get(0).value().utf8ToString());
+      assertEquals(1, entries.get(0).count());
     }
 
     GroupFacetCollector groupedDurationFacetCollector =
@@ -145,10 +145,10 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
 
     entries = durationResult.getFacetEntries(0, 10);
     assertEquals(2, entries.size());
-    assertEquals("10", entries.get(0).getValue().utf8ToString());
-    assertEquals(2, entries.get(0).getCount());
-    assertEquals("5", entries.get(1).getValue().utf8ToString());
-    assertEquals(2, entries.get(1).getCount());
+    assertEquals("10", entries.get(0).value().utf8ToString());
+    assertEquals(2, entries.get(0).count());
+    assertEquals("5", entries.get(1).value().utf8ToString());
+    assertEquals(2, entries.get(1).count());
 
     // 5
     doc = new Document();
@@ -193,17 +193,17 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
     if (useDv) {
       assertEquals(6, airportResult.getTotalCount());
       assertEquals(0, airportResult.getTotalMissingCount());
-      assertEquals("bru", entries.get(0).getValue().utf8ToString());
-      assertEquals(2, entries.get(0).getCount());
-      assertEquals("", entries.get(1).getValue().utf8ToString());
-      assertEquals(1, entries.get(1).getCount());
+      assertEquals("bru", entries.get(0).value().utf8ToString());
+      assertEquals(2, entries.get(0).count());
+      assertEquals("", entries.get(1).value().utf8ToString());
+      assertEquals(1, entries.get(1).count());
     } else {
       assertEquals(5, airportResult.getTotalCount());
       assertEquals(1, airportResult.getTotalMissingCount());
-      assertEquals("bru", entries.get(0).getValue().utf8ToString());
-      assertEquals(2, entries.get(0).getCount());
-      assertEquals("dus", entries.get(1).getValue().utf8ToString());
-      assertEquals(1, entries.get(1).getCount());
+      assertEquals("bru", entries.get(0).value().utf8ToString());
+      assertEquals(2, entries.get(0).count());
+      assertEquals("dus", entries.get(1).value().utf8ToString());
+      assertEquals(1, entries.get(1).count());
     }
 
     groupedDurationFacetCollector =
@@ -216,8 +216,8 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
 
     entries = durationResult.getFacetEntries(1, 1);
     assertEquals(1, entries.size());
-    assertEquals("5", entries.get(0).getValue().utf8ToString());
-    assertEquals(2, entries.get(0).getCount());
+    assertEquals("5", entries.get(0).value().utf8ToString());
+    assertEquals(2, entries.get(0).count());
 
     // 9
     doc = new Document();
@@ -245,24 +245,24 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
       assertEquals(8, airportResult.getTotalCount());
       assertEquals(0, airportResult.getTotalMissingCount());
       assertEquals(4, entries.size());
-      assertEquals("", entries.get(0).getValue().utf8ToString());
-      assertEquals(1, entries.get(0).getCount());
-      assertEquals("ams", entries.get(1).getValue().utf8ToString());
-      assertEquals(2, entries.get(1).getCount());
-      assertEquals("bru", entries.get(2).getValue().utf8ToString());
-      assertEquals(3, entries.get(2).getCount());
-      assertEquals("dus", entries.get(3).getValue().utf8ToString());
-      assertEquals(2, entries.get(3).getCount());
+      assertEquals("", entries.get(0).value().utf8ToString());
+      assertEquals(1, entries.get(0).count());
+      assertEquals("ams", entries.get(1).value().utf8ToString());
+      assertEquals(2, entries.get(1).count());
+      assertEquals("bru", entries.get(2).value().utf8ToString());
+      assertEquals(3, entries.get(2).count());
+      assertEquals("dus", entries.get(3).value().utf8ToString());
+      assertEquals(2, entries.get(3).count());
     } else {
       assertEquals(7, airportResult.getTotalCount());
       assertEquals(1, airportResult.getTotalMissingCount());
       assertEquals(3, entries.size());
-      assertEquals("ams", entries.get(0).getValue().utf8ToString());
-      assertEquals(2, entries.get(0).getCount());
-      assertEquals("bru", entries.get(1).getValue().utf8ToString());
-      assertEquals(3, entries.get(1).getCount());
-      assertEquals("dus", entries.get(2).getValue().utf8ToString());
-      assertEquals(2, entries.get(2).getCount());
+      assertEquals("ams", entries.get(0).value().utf8ToString());
+      assertEquals(2, entries.get(0).count());
+      assertEquals("bru", entries.get(1).value().utf8ToString());
+      assertEquals(3, entries.get(1).count());
+      assertEquals("dus", entries.get(2).value().utf8ToString());
+      assertEquals(2, entries.get(2).count());
     }
 
     groupedDurationFacetCollector =
@@ -275,10 +275,10 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
 
     entries = durationResult.getFacetEntries(0, 10);
     assertEquals(2, entries.size());
-    assertEquals("10", entries.get(0).getValue().utf8ToString());
-    assertEquals(3, entries.get(0).getCount());
-    assertEquals("15", entries.get(1).getValue().utf8ToString());
-    assertEquals(2, entries.get(1).getCount());
+    assertEquals("10", entries.get(0).value().utf8ToString());
+    assertEquals(3, entries.get(0).count());
+    assertEquals("15", entries.get(1).value().utf8ToString());
+    assertEquals(2, entries.get(1).count());
 
     w.close();
     indexSearcher.getIndexReader().close();
@@ -365,10 +365,10 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
 
     List<TermGroupFacetCollector.FacetEntry> entries = airportResult.getFacetEntries(0, 10);
     assertEquals(2, entries.size());
-    assertEquals("ams", entries.get(0).getValue().utf8ToString());
-    assertEquals(2, entries.get(0).getCount());
-    assertEquals("dus", entries.get(1).getValue().utf8ToString());
-    assertEquals(1, entries.get(1).getCount());
+    assertEquals("ams", entries.get(0).value().utf8ToString());
+    assertEquals(2, entries.get(0).count());
+    assertEquals("dus", entries.get(1).value().utf8ToString());
+    assertEquals(1, entries.get(1).count());
 
     indexSearcher.getIndexReader().close();
     dir.close();
@@ -428,7 +428,7 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
             groupFacetCollector.mergeSegmentResults(size, minCount, orderByCount);
 
         List<TermGroupFacetCollector.FacetEntry> expectedFacetEntries =
-            expectedFacetResult.getFacetEntries();
+            expectedFacetResult.facetEntries();
         List<TermGroupFacetCollector.FacetEntry> actualFacetEntries =
             actualFacetResult.getFacetEntries(offset, limit);
 
@@ -448,16 +448,16 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
           System.out.println("Order by count: " + orderByCount);
 
           System.out.println("\n=== Expected: \n");
-          System.out.println("Total count " + expectedFacetResult.getTotalCount());
-          System.out.println("Total missing count " + expectedFacetResult.getTotalMissingCount());
+          System.out.println("Total count " + expectedFacetResult.totalCount());
+          System.out.println("Total missing count " + expectedFacetResult.totalMissingCount());
           int counter = 0;
           for (TermGroupFacetCollector.FacetEntry expectedFacetEntry : expectedFacetEntries) {
             System.out.printf(
                 Locale.ROOT,
                 "%d. Expected facet value %s with count %d%n",
                 counter++,
-                expectedFacetEntry.getValue().utf8ToString(),
-                expectedFacetEntry.getCount());
+                expectedFacetEntry.value().utf8ToString(),
+                expectedFacetEntry.count());
           }
 
           System.out.println("\n=== Actual: \n");
@@ -469,16 +469,16 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
                 Locale.ROOT,
                 "%d. Actual facet value %s with count %d%n",
                 counter++,
-                actualFacetEntry.getValue().utf8ToString(),
-                actualFacetEntry.getCount());
+                actualFacetEntry.value().utf8ToString(),
+                actualFacetEntry.count());
           }
           System.out.println(
               "\n===================================================================================");
         }
 
-        assertEquals(expectedFacetResult.getTotalCount(), actualFacetResult.getTotalCount());
+        assertEquals(expectedFacetResult.totalCount(), actualFacetResult.getTotalCount());
         assertEquals(
-            expectedFacetResult.getTotalMissingCount(), actualFacetResult.getTotalMissingCount());
+            expectedFacetResult.totalMissingCount(), actualFacetResult.getTotalMissingCount());
         assertEquals(expectedFacetEntries.size(), actualFacetEntries.size());
         for (int i = 0; i < expectedFacetEntries.size(); i++) {
           TermGroupFacetCollector.FacetEntry expectedFacetEntry = expectedFacetEntries.get(i);
@@ -487,20 +487,15 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
               "i="
                   + i
                   + ": "
-                  + expectedFacetEntry.getValue().utf8ToString()
+                  + expectedFacetEntry.value().utf8ToString()
                   + " != "
-                  + actualFacetEntry.getValue().utf8ToString(),
-              expectedFacetEntry.getValue(),
-              actualFacetEntry.getValue());
+                  + actualFacetEntry.value().utf8ToString(),
+              expectedFacetEntry.value(),
+              actualFacetEntry.value());
           assertEquals(
-              "i="
-                  + i
-                  + ": "
-                  + expectedFacetEntry.getCount()
-                  + " != "
-                  + actualFacetEntry.getCount(),
-              expectedFacetEntry.getCount(),
-              actualFacetEntry.getCount());
+              "i=" + i + ": " + expectedFacetEntry.count() + " != " + actualFacetEntry.count(),
+              expectedFacetEntry.count(),
+              actualFacetEntry.count());
         }
       }
 
@@ -736,12 +731,12 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
     entries.sort(
         (a, b) -> {
           if (orderByCount) {
-            int cmp = b.getCount() - a.getCount();
+            int cmp = b.count() - a.count();
             if (cmp != 0) {
               return cmp;
             }
           }
-          return a.getValue().compareTo(b.getValue());
+          return a.value().compareTo(b.value());
         });
 
     int endOffset = offset + limit;
@@ -805,31 +800,8 @@ public class TestGroupFacetCollector extends AbstractGroupingTestCase {
     }
   }
 
-  private static class GroupedFacetResult {
-
-    final int totalCount;
-    final int totalMissingCount;
-    final List<TermGroupFacetCollector.FacetEntry> facetEntries;
-
-    private GroupedFacetResult(
-        int totalCount,
-        int totalMissingCount,
-        List<TermGroupFacetCollector.FacetEntry> facetEntries) {
-      this.totalCount = totalCount;
-      this.totalMissingCount = totalMissingCount;
-      this.facetEntries = facetEntries;
-    }
-
-    public int getTotalCount() {
-      return totalCount;
-    }
-
-    public int getTotalMissingCount() {
-      return totalMissingCount;
-    }
-
-    public List<TermGroupFacetCollector.FacetEntry> getFacetEntries() {
-      return facetEntries;
-    }
-  }
+  private record GroupedFacetResult(
+      int totalCount,
+      int totalMissingCount,
+      List<TermGroupFacetCollector.FacetEntry> facetEntries) {}
 }
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
index 38493a01bb6..a179adf691c 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGrouping.java
@@ -164,29 +164,29 @@ public class TestGrouping extends LuceneTestCase {
     // value
     GroupDocs<?> group = groups.groups[0];
     compareGroupValue("author3", group);
-    assertEquals(2, group.scoreDocs.length);
-    assertEquals(5, group.scoreDocs[0].doc);
-    assertEquals(4, group.scoreDocs[1].doc);
-    assertTrue(group.scoreDocs[0].score > group.scoreDocs[1].score);
+    assertEquals(2, group.scoreDocs().length);
+    assertEquals(5, group.scoreDocs()[0].doc);
+    assertEquals(4, group.scoreDocs()[1].doc);
+    assertTrue(group.scoreDocs()[0].score > group.scoreDocs()[1].score);
 
     group = groups.groups[1];
     compareGroupValue("author1", group);
-    assertEquals(3, group.scoreDocs.length);
-    assertEquals(0, group.scoreDocs[0].doc);
-    assertEquals(1, group.scoreDocs[1].doc);
-    assertEquals(2, group.scoreDocs[2].doc);
-    assertTrue(group.scoreDocs[0].score >= group.scoreDocs[1].score);
-    assertTrue(group.scoreDocs[1].score >= group.scoreDocs[2].score);
+    assertEquals(3, group.scoreDocs().length);
+    assertEquals(0, group.scoreDocs()[0].doc);
+    assertEquals(1, group.scoreDocs()[1].doc);
+    assertEquals(2, group.scoreDocs()[2].doc);
+    assertTrue(group.scoreDocs()[0].score >= group.scoreDocs()[1].score);
+    assertTrue(group.scoreDocs()[1].score >= group.scoreDocs()[2].score);
 
     group = groups.groups[2];
     compareGroupValue("author2", group);
-    assertEquals(1, group.scoreDocs.length);
-    assertEquals(3, group.scoreDocs[0].doc);
+    assertEquals(1, group.scoreDocs().length);
+    assertEquals(3, group.scoreDocs()[0].doc);
 
     group = groups.groups[3];
     compareGroupValue(null, group);
-    assertEquals(1, group.scoreDocs.length);
-    assertEquals(6, group.scoreDocs[0].doc);
+    assertEquals(1, group.scoreDocs().length);
+    assertEquals(6, group.scoreDocs()[0].doc);
 
     indexSearcher.getIndexReader().close();
     dir.close();
@@ -292,22 +292,22 @@ public class TestGrouping extends LuceneTestCase {
 
   private void compareGroupValue(String expected, GroupDocs<?> group) {
     if (expected == null) {
-      if (group.groupValue == null) {
+      if (group.groupValue() == null) {
         return;
-      } else if (group.groupValue.getClass().isAssignableFrom(MutableValueStr.class)) {
+      } else if (group.groupValue().getClass().isAssignableFrom(MutableValueStr.class)) {
         return;
-      } else if (((BytesRef) group.groupValue).length == 0) {
+      } else if (((BytesRef) group.groupValue()).length == 0) {
         return;
       }
       fail();
     }
 
-    if (group.groupValue.getClass().isAssignableFrom(BytesRef.class)) {
-      assertEquals(new BytesRef(expected), group.groupValue);
-    } else if (group.groupValue.getClass().isAssignableFrom(MutableValueStr.class)) {
+    if (group.groupValue().getClass().isAssignableFrom(BytesRef.class)) {
+      assertEquals(new BytesRef(expected), group.groupValue());
+    } else if (group.groupValue().getClass().isAssignableFrom(MutableValueStr.class)) {
       MutableValueStr v = new MutableValueStr();
       v.value.copyChars(expected);
-      assertEquals(v, group.groupValue);
+      assertEquals(v, group.groupValue());
     } else {
       fail();
     }
@@ -356,15 +356,17 @@ public class TestGrouping extends LuceneTestCase {
       List<GroupDocs<BytesRef>> groups = new ArrayList<>(mvalTopGroups.groups.length);
       for (GroupDocs<MutableValue> mvalGd : mvalTopGroups.groups) {
         BytesRef groupValue =
-            mvalGd.groupValue.exists() ? ((MutableValueStr) mvalGd.groupValue).value.get() : null;
+            mvalGd.groupValue().exists()
+                ? ((MutableValueStr) mvalGd.groupValue()).value.get()
+                : null;
         groups.add(
             new GroupDocs<>(
                 Float.NaN,
-                mvalGd.maxScore,
-                mvalGd.totalHits,
-                mvalGd.scoreDocs,
+                mvalGd.maxScore(),
+                mvalGd.totalHits(),
+                mvalGd.scoreDocs(),
                 groupValue,
-                mvalGd.groupSortValues));
+                mvalGd.groupSortValues()));
       }
       // NOTE: currenlty using diamond operator on MergedIterator (without explicit Term class)
       // causes
@@ -1136,12 +1138,12 @@ public class TestGrouping extends LuceneTestCase {
             for (GroupDocs<BytesRef> gd : expectedGroups.groups) {
               System.out.println(
                   "  group="
-                      + (gd.groupValue == null ? "null" : gd.groupValue)
+                      + (gd.groupValue() == null ? "null" : gd.groupValue())
                       + " totalHits="
-                      + gd.totalHits.value
+                      + gd.totalHits().value
                       + " scoreDocs.len="
-                      + gd.scoreDocs.length);
-              for (ScoreDoc sd : gd.scoreDocs) {
+                      + gd.scoreDocs().length);
+              for (ScoreDoc sd : gd.scoreDocs()) {
                 System.out.println("    id=" + sd.doc + " score=" + sd.score);
               }
             }
@@ -1155,10 +1157,10 @@ public class TestGrouping extends LuceneTestCase {
             for (GroupDocs<BytesRef> gd : groupsResult.groups) {
               System.out.println(
                   "  group="
-                      + (gd.groupValue == null ? "null" : gd.groupValue)
+                      + (gd.groupValue() == null ? "null" : gd.groupValue())
                       + " totalHits="
-                      + gd.totalHits.value);
-              for (ScoreDoc sd : gd.scoreDocs) {
+                      + gd.totalHits().value);
+              for (ScoreDoc sd : gd.scoreDocs()) {
                 System.out.println("    id=" + docIDToID[sd.doc] + " score=" + sd.score);
               }
             }
@@ -1180,10 +1182,10 @@ public class TestGrouping extends LuceneTestCase {
             for (GroupDocs<BytesRef> gd : topGroupsShards.groups) {
               System.out.println(
                   "  group="
-                      + (gd.groupValue == null ? "null" : gd.groupValue)
+                      + (gd.groupValue() == null ? "null" : gd.groupValue())
                       + " totalHits="
-                      + gd.totalHits.value);
-              for (ScoreDoc sd : gd.scoreDocs) {
+                      + gd.totalHits().value);
+              for (ScoreDoc sd : gd.scoreDocs()) {
                 System.out.println("    id=" + docIDToID[sd.doc] + " score=" + sd.score);
               }
             }
@@ -1244,10 +1246,10 @@ public class TestGrouping extends LuceneTestCase {
             for (GroupDocs<BytesRef> gd : groupsResultBlocks.groups) {
               System.out.println(
                   "  group="
-                      + (gd.groupValue == null ? "null" : gd.groupValue.utf8ToString())
+                      + (gd.groupValue() == null ? "null" : gd.groupValue().utf8ToString())
                       + " totalHits="
-                      + gd.totalHits.value);
-              for (ScoreDoc sd : gd.scoreDocs) {
+                      + gd.totalHits().value);
+              for (ScoreDoc sd : gd.scoreDocs()) {
                 System.out.println("    id=" + docIDToIDBlocks[sd.doc] + " score=" + sd.score);
                 if (first) {
                   System.out.println("explain: " + sBlocks.explain(query, sd.doc));
@@ -1277,7 +1279,7 @@ public class TestGrouping extends LuceneTestCase {
         if (expectedGroups != null) {
           // Fixup scores for reader2
           for (GroupDocs<?> groupDocsHits : expectedGroups.groups) {
-            for (ScoreDoc hit : groupDocsHits.scoreDocs) {
+            for (ScoreDoc hit : groupDocsHits.scoreDocs()) {
               final GroupDoc gd = groupDocsByID[hit.doc];
               assertEquals(gd.id, hit.doc);
               // System.out.println("fixup score " + hit.score + " to " + gd.score2 + " vs " +
@@ -1291,12 +1293,12 @@ public class TestGrouping extends LuceneTestCase {
           for (int groupSortIDX = 0; groupSortIDX < sortFields.length; groupSortIDX++) {
             if (sortFields[groupSortIDX].getType() == SortField.Type.SCORE) {
               for (GroupDocs<?> groupDocsHits : expectedGroups.groups) {
-                if (groupDocsHits.groupSortValues != null) {
+                if (groupDocsHits.groupSortValues() != null) {
                   // System.out.println("remap " + groupDocsHits.groupSortValues[groupSortIDX] + "
                   // to " + termScoreMap.get(groupDocsHits.groupSortValues[groupSortIDX]));
-                  groupDocsHits.groupSortValues[groupSortIDX] =
-                      termScoreMap.get(groupDocsHits.groupSortValues[groupSortIDX]);
-                  assertNotNull(groupDocsHits.groupSortValues[groupSortIDX]);
+                  groupDocsHits.groupSortValues()[groupSortIDX] =
+                      termScoreMap.get(groupDocsHits.groupSortValues()[groupSortIDX]);
+                  assertNotNull(groupDocsHits.groupSortValues()[groupSortIDX]);
                 }
               }
             }
@@ -1306,7 +1308,7 @@ public class TestGrouping extends LuceneTestCase {
           for (int docSortIDX = 0; docSortIDX < docSortFields.length; docSortIDX++) {
             if (docSortFields[docSortIDX].getType() == SortField.Type.SCORE) {
               for (GroupDocs<?> groupDocsHits : expectedGroups.groups) {
-                for (ScoreDoc _hit : groupDocsHits.scoreDocs) {
+                for (ScoreDoc _hit : groupDocsHits.scoreDocs()) {
                   FieldDoc hit = (FieldDoc) _hit;
                   if (hit.fields != null) {
                     hit.fields[docSortIDX] = termScoreMap.get(hit.fields[docSortIDX]);
@@ -1332,8 +1334,8 @@ public class TestGrouping extends LuceneTestCase {
 
   private void verifyShards(int[] docStarts, TopGroups<BytesRef> topGroups) {
     for (GroupDocs<?> group : topGroups.groups) {
-      for (int hitIDX = 0; hitIDX < group.scoreDocs.length; hitIDX++) {
-        final ScoreDoc sd = group.scoreDocs[hitIDX];
+      for (int hitIDX = 0; hitIDX < group.scoreDocs().length; hitIDX++) {
+        final ScoreDoc sd = group.scoreDocs()[hitIDX];
         assertEquals(
             "doc=" + sd.doc + " wrong shard",
             ReaderUtil.subIndex(sd.doc, docStarts),
@@ -1465,11 +1467,11 @@ public class TestGrouping extends LuceneTestCase {
           for (GroupDocs<BytesRef> group : shardTopGroups[shardIDX].groups) {
             System.out.println(
                 "    ["
-                    + groupToString(group.groupValue)
+                    + groupToString(group.groupValue())
                     + "] groupSort="
-                    + Arrays.toString(group.groupSortValues)
+                    + Arrays.toString(group.groupSortValues())
                     + " numDocs="
-                    + group.scoreDocs.length);
+                    + group.scoreDocs().length);
           }
         }
       }
@@ -1487,11 +1489,11 @@ public class TestGrouping extends LuceneTestCase {
         for (GroupDocs<BytesRef> group : mergedGroups.groups) {
           System.out.println(
               "    ["
-                  + groupToString(group.groupValue)
+                  + groupToString(group.groupValue())
                   + "] groupSort="
-                  + Arrays.toString(group.groupSortValues)
+                  + Arrays.toString(group.groupSortValues())
                   + " numDocs="
-                  + group.scoreDocs.length);
+                  + group.scoreDocs().length);
         }
       }
       return mergedGroups;
@@ -1540,23 +1542,23 @@ public class TestGrouping extends LuceneTestCase {
       final GroupDocs<BytesRef> actualGroup = actual.groups[groupIDX];
       if (verifyGroupValues) {
         if (idvBasedImplsUsed) {
-          if (actualGroup.groupValue.length == 0) {
-            assertNull(expectedGroup.groupValue);
+          if (actualGroup.groupValue().length == 0) {
+            assertNull(expectedGroup.groupValue());
           } else {
-            assertEquals(expectedGroup.groupValue, actualGroup.groupValue);
+            assertEquals(expectedGroup.groupValue(), actualGroup.groupValue());
           }
         } else {
-          assertEquals(expectedGroup.groupValue, actualGroup.groupValue);
+          assertEquals(expectedGroup.groupValue(), actualGroup.groupValue());
         }
       }
-      assertArrayEquals(expectedGroup.groupSortValues, actualGroup.groupSortValues);
+      assertArrayEquals(expectedGroup.groupSortValues(), actualGroup.groupSortValues());
 
       // TODO
       // assertEquals(expectedGroup.maxScore, actualGroup.maxScore);
-      assertEquals(expectedGroup.totalHits.value, actualGroup.totalHits.value);
+      assertEquals(expectedGroup.totalHits().value, actualGroup.totalHits().value);
 
-      final ScoreDoc[] expectedFDs = expectedGroup.scoreDocs;
-      final ScoreDoc[] actualFDs = actualGroup.scoreDocs;
+      final ScoreDoc[] expectedFDs = expectedGroup.scoreDocs();
+      final ScoreDoc[] actualFDs = actualGroup.scoreDocs();
 
       assertEquals(expectedFDs.length, actualFDs.length);
       for (int docIDX = 0; docIDX < expectedFDs.length; docIDX++) {
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupingSearch.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupingSearch.java
index 95132d735a5..308b7d2c070 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupingSearch.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestGroupingSearch.java
@@ -135,29 +135,29 @@ public class TestGroupingSearch extends LuceneTestCase {
     // value
     GroupDocs<?> group = groups.groups[0];
     compareGroupValue("author3", group);
-    assertEquals(2, group.scoreDocs.length);
-    assertEquals(5, group.scoreDocs[0].doc);
-    assertEquals(4, group.scoreDocs[1].doc);
-    assertTrue(group.scoreDocs[0].score >= group.scoreDocs[1].score);
+    assertEquals(2, group.scoreDocs().length);
+    assertEquals(5, group.scoreDocs()[0].doc);
+    assertEquals(4, group.scoreDocs()[1].doc);
+    assertTrue(group.scoreDocs()[0].score >= group.scoreDocs()[1].score);
 
     group = groups.groups[1];
     compareGroupValue("author1", group);
-    assertEquals(3, group.scoreDocs.length);
-    assertEquals(0, group.scoreDocs[0].doc);
-    assertEquals(1, group.scoreDocs[1].doc);
-    assertEquals(2, group.scoreDocs[2].doc);
-    assertTrue(group.scoreDocs[0].score >= group.scoreDocs[1].score);
-    assertTrue(group.scoreDocs[1].score >= group.scoreDocs[2].score);
+    assertEquals(3, group.scoreDocs().length);
+    assertEquals(0, group.scoreDocs()[0].doc);
+    assertEquals(1, group.scoreDocs()[1].doc);
+    assertEquals(2, group.scoreDocs()[2].doc);
+    assertTrue(group.scoreDocs()[0].score >= group.scoreDocs()[1].score);
+    assertTrue(group.scoreDocs()[1].score >= group.scoreDocs()[2].score);
 
     group = groups.groups[2];
     compareGroupValue("author2", group);
-    assertEquals(1, group.scoreDocs.length);
-    assertEquals(3, group.scoreDocs[0].doc);
+    assertEquals(1, group.scoreDocs().length);
+    assertEquals(3, group.scoreDocs()[0].doc);
 
     group = groups.groups[3];
     compareGroupValue(null, group);
-    assertEquals(1, group.scoreDocs.length);
-    assertEquals(6, group.scoreDocs[0].doc);
+    assertEquals(1, group.scoreDocs().length);
+    assertEquals(6, group.scoreDocs()[0].doc);
 
     Query lastDocInBlock = new TermQuery(new Term("groupend", "x"));
     groupingSearch = new GroupingSearch(lastDocInBlock);
@@ -182,22 +182,22 @@ public class TestGroupingSearch extends LuceneTestCase {
 
   private void compareGroupValue(String expected, GroupDocs<?> group) {
     if (expected == null) {
-      if (group.groupValue == null) {
+      if (group.groupValue() == null) {
         return;
-      } else if (group.groupValue.getClass().isAssignableFrom(MutableValueStr.class)) {
+      } else if (group.groupValue().getClass().isAssignableFrom(MutableValueStr.class)) {
         return;
-      } else if (((BytesRef) group.groupValue).length == 0) {
+      } else if (((BytesRef) group.groupValue()).length == 0) {
         return;
       }
       fail();
     }
 
-    if (group.groupValue.getClass().isAssignableFrom(BytesRef.class)) {
-      assertEquals(new BytesRef(expected), group.groupValue);
-    } else if (group.groupValue.getClass().isAssignableFrom(MutableValueStr.class)) {
+    if (group.groupValue().getClass().isAssignableFrom(BytesRef.class)) {
+      assertEquals(new BytesRef(expected), group.groupValue());
+    } else if (group.groupValue().getClass().isAssignableFrom(MutableValueStr.class)) {
       MutableValueStr v = new MutableValueStr();
       v.value.copyChars(expected);
-      assertEquals(v, group.groupValue);
+      assertEquals(v, group.groupValue());
     } else {
       fail();
     }
diff --git a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestTopGroups.java b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestTopGroups.java
index 8740b639fa7..f7fe36ef401 100644
--- a/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestTopGroups.java
+++ b/lucene/grouping/src/test/org/apache/lucene/search/grouping/TestTopGroups.java
@@ -128,8 +128,8 @@ public class TestTopGroups extends LuceneTestCase {
           new TopGroups<String>(
               sort.getSort() /* groupSort */,
               sort.getSort() /* withinGroupSort */,
-              group1.scoreDocs.length + group2.scoreDocs.length /* totalHitCount */,
-              group1.scoreDocs.length + group2.scoreDocs.length /* totalGroupedHitCount */,
+              group1.scoreDocs().length + group2.scoreDocs().length /* totalHitCount */,
+              group1.scoreDocs().length + group2.scoreDocs().length /* totalGroupedHitCount */,
               combineGroupDocs(group1, group2) /* groups */,
               (haveBlueWhale
                   ? blueWhaleScore
@@ -162,8 +162,8 @@ public class TestTopGroups extends LuceneTestCase {
           new TopGroups<String>(
               sort.getSort() /* groupSort */,
               sort.getSort() /* withinGroupSort */,
-              group1.scoreDocs.length + group2.scoreDocs.length /* totalHitCount */,
-              group1.scoreDocs.length + group2.scoreDocs.length /* totalGroupedHitCount */,
+              group1.scoreDocs().length + group2.scoreDocs().length /* totalHitCount */,
+              group1.scoreDocs().length + group2.scoreDocs().length /* totalGroupedHitCount */,
               combineGroupDocs(group1, group2) /* groups */,
               (haveRedSquirrel
                   ? redSquirrelScore
@@ -191,16 +191,16 @@ public class TestTopGroups extends LuceneTestCase {
 
     assertEquals(2, mergedTopGroups.groups.length);
     {
-      assertEquals(blueGroupValue, mergedTopGroups.groups[0].groupValue);
+      assertEquals(blueGroupValue, mergedTopGroups.groups[0].groupValue());
       final float expectedBlueMaxScore =
           (haveBlueWhale ? blueWhaleScore : (haveBlueDragonfly ? blueDragonflyScore : Float.NaN));
-      checkMaxScore(expectedBlueMaxScore, mergedTopGroups.groups[0].maxScore);
+      checkMaxScore(expectedBlueMaxScore, mergedTopGroups.groups[0].maxScore());
     }
     {
-      assertEquals(redGroupValue, mergedTopGroups.groups[1].groupValue);
+      assertEquals(redGroupValue, mergedTopGroups.groups[1].groupValue());
       final float expectedRedMaxScore =
           (haveRedSquirrel ? redSquirrelScore : (haveRedAnt ? redAntScore : Float.NaN));
-      checkMaxScore(expectedRedMaxScore, mergedTopGroups.groups[1].maxScore);
+      checkMaxScore(expectedRedMaxScore, mergedTopGroups.groups[1].maxScore());
     }
 
     final float expectedMaxScore =
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/FieldOffsetStrategy.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/FieldOffsetStrategy.java
index dcc8e5af873..8275a59754b 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/FieldOffsetStrategy.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/FieldOffsetStrategy.java
@@ -46,7 +46,7 @@ public abstract class FieldOffsetStrategy {
   }
 
   public String getField() {
-    return components.getField();
+    return components.field();
   }
 
   public abstract UnifiedHighlighter.OffsetSource getOffsetSource();
@@ -69,7 +69,7 @@ public abstract class FieldOffsetStrategy {
     final List<OffsetsEnum> offsetsEnums = new ArrayList<>();
 
     // Handle Weight.matches approach
-    if (components.getHighlightFlags().contains(UnifiedHighlighter.HighlightFlag.WEIGHT_MATCHES)) {
+    if (components.highlightFlags().contains(UnifiedHighlighter.HighlightFlag.WEIGHT_MATCHES)) {
 
       createOffsetsEnumsWeightMatcher(leafReader, doc, offsetsEnums);
 
@@ -77,8 +77,8 @@ public abstract class FieldOffsetStrategy {
 
       // Handle position insensitive terms (a subset of this.terms field):
       final BytesRef[] insensitiveTerms;
-      final PhraseHelper phraseHelper = components.getPhraseHelper();
-      final BytesRef[] terms = components.getTerms();
+      final PhraseHelper phraseHelper = components.phraseHelper();
+      final BytesRef[] terms = components.terms();
       if (phraseHelper.hasPositionSensitivity()) {
         insensitiveTerms = phraseHelper.getAllPositionInsensitiveTerms();
         assert insensitiveTerms.length <= terms.length
@@ -96,7 +96,7 @@ public abstract class FieldOffsetStrategy {
       }
 
       // Handle automata
-      if (components.getAutomata().length > 0) {
+      if (components.automata().length > 0) {
         createOffsetsEnumsForAutomata(termsIndex, doc, offsetsEnums);
       }
     }
@@ -118,8 +118,8 @@ public abstract class FieldOffsetStrategy {
         new FilterLeafReader(_leafReader) {
           @Override
           public Terms terms(String field) throws IOException {
-            if (components.getFieldMatcher().test(field)) {
-              return super.terms(components.getField());
+            if (components.fieldMatcher().test(field)) {
+              return super.terms(components.field());
             } else {
               return super.terms(field);
             }
@@ -142,14 +142,14 @@ public abstract class FieldOffsetStrategy {
     indexSearcher.setQueryCache(null);
     Matches matches =
         indexSearcher
-            .rewrite(components.getQuery())
+            .rewrite(components.query())
             .createWeight(indexSearcher, ScoreMode.COMPLETE_NO_SCORES, 1.0f)
             .matches(leafReader.getContext(), docId);
     if (matches == null) {
       return; // doc doesn't match
     }
     for (String field : matches) {
-      if (components.getFieldMatcher().test(field)) {
+      if (components.fieldMatcher().test(field)) {
         MatchesIterator iterator = matches.getMatches(field);
         if (iterator == null) {
           continue;
@@ -180,7 +180,7 @@ public abstract class FieldOffsetStrategy {
 
   protected void createOffsetsEnumsForAutomata(Terms termsIndex, int doc, List<OffsetsEnum> results)
       throws IOException {
-    final LabelledCharArrayMatcher[] automata = components.getAutomata();
+    final LabelledCharArrayMatcher[] automata = components.automata();
     List<List<PostingsEnum>> automataPostings = new ArrayList<>(automata.length);
     for (int i = 0; i < automata.length; i++) {
       automataPostings.add(new ArrayList<>());
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java
index a4b090902ed..749cb765b39 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/MemoryIndexOffsetStrategy.java
@@ -44,8 +44,7 @@ public class MemoryIndexOffsetStrategy extends AnalysisOffsetStrategy {
 
   public MemoryIndexOffsetStrategy(UHComponents components, Analyzer analyzer) {
     super(components, analyzer);
-    boolean storePayloads =
-        components.getPhraseHelper().hasPositionSensitivity(); // might be needed
+    boolean storePayloads = components.phraseHelper().hasPositionSensitivity(); // might be needed
     memoryIndex = new MemoryIndex(true, storePayloads); // true==store offsets
     memIndexLeafReader =
         (LeafReader) memoryIndex.createSearcher().getIndexReader(); // appears to be re-usable
@@ -56,26 +55,26 @@ public class MemoryIndexOffsetStrategy extends AnalysisOffsetStrategy {
   /** Build one {@link CharArrayMatcher} matching any term the query might match. */
   private static CharArrayMatcher buildCombinedAutomaton(UHComponents components) {
     // We don't know enough about the query to do this confidently
-    if (components.getTerms() == null || components.getAutomata() == null) {
+    if (components.terms() == null || components.automata() == null) {
       return null;
     }
 
     List<CharArrayMatcher> allAutomata = new ArrayList<>();
-    if (components.getTerms().length > 0) {
+    if (components.terms().length > 0) {
       // Filter out any long terms that would otherwise cause exceptions if we tried
       // to build an automaton on them
       List<BytesRef> filteredTerms =
-          Arrays.stream(components.getTerms())
+          Arrays.stream(components.terms())
               .filter(b -> b.length < Automata.MAX_STRING_UNION_TERM_LENGTH)
               .toList();
       allAutomata.add(CharArrayMatcher.fromTerms(filteredTerms));
     }
-    Collections.addAll(allAutomata, components.getAutomata());
-    for (SpanQuery spanQuery : components.getPhraseHelper().getSpanQueries()) {
+    Collections.addAll(allAutomata, components.automata());
+    for (SpanQuery spanQuery : components.phraseHelper().getSpanQueries()) {
       Collections.addAll(
           allAutomata,
           MultiTermHighlighting.extractAutomata(
-              spanQuery, components.getFieldMatcher(), true)); // true==lookInSpan
+              spanQuery, components.fieldMatcher(), true)); // true==lookInSpan
     }
 
     if (allAutomata.size() == 1) {
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/TokenStreamOffsetStrategy.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/TokenStreamOffsetStrategy.java
index 05a9743a8cb..e22286ced43 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/TokenStreamOffsetStrategy.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/TokenStreamOffsetStrategy.java
@@ -38,8 +38,8 @@ public class TokenStreamOffsetStrategy extends AnalysisOffsetStrategy {
 
   public TokenStreamOffsetStrategy(UHComponents components, Analyzer indexAnalyzer) {
     super(components, indexAnalyzer);
-    assert components.getPhraseHelper().hasPositionSensitivity() == false;
-    combinedAutomata = convertTermsToMatchers(components.getTerms(), components.getAutomata());
+    assert components.phraseHelper().hasPositionSensitivity() == false;
+    combinedAutomata = convertTermsToMatchers(components.terms(), components.automata());
   }
 
   // TODO this is inefficient; instead build a union automata just for terms part.
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UHComponents.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UHComponents.java
index 96e40a4cbca..a8d4d617986 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UHComponents.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UHComponents.java
@@ -25,71 +25,19 @@ import org.apache.lucene.util.BytesRef;
 /**
  * A parameter object to hold the components a {@link FieldOffsetStrategy} needs.
  *
+ * @param terms Query: all terms we extracted (some may be position sensitive)
+ * @param phraseHelper Query: position-sensitive information
+ * @param automata Query: wildcards (i.e. multi-term query), not position sensitive
+ * @param hasUnrecognizedQueryPart Query: if part of the query (other than the extracted terms /
+ *     automata) is a leaf we don't know
  * @lucene.internal
  */
-public class UHComponents {
-  private final String field;
-  private final Predicate<String> fieldMatcher;
-  private final Query query;
-  // Query: all terms we extracted (some may be position sensitive)
-  private final BytesRef[] terms;
-  // Query: position-sensitive information
-  private final PhraseHelper phraseHelper;
-  // Query: wildcards (i.e. multi-term query), not position sensitive
-  private final LabelledCharArrayMatcher[] automata;
-  // Query: if part of the query (other than the extracted terms / automata) is a leaf we don't know
-  private final boolean hasUnrecognizedQueryPart;
-
-  private final Set<UnifiedHighlighter.HighlightFlag> highlightFlags;
-
-  public UHComponents(
-      String field,
-      Predicate<String> fieldMatcher,
-      Query query,
-      BytesRef[] terms,
-      PhraseHelper phraseHelper,
-      LabelledCharArrayMatcher[] automata,
-      boolean hasUnrecognizedQueryPart,
-      Set<UnifiedHighlighter.HighlightFlag> highlightFlags) {
-    this.field = field;
-    this.fieldMatcher = fieldMatcher;
-    this.query = query;
-    this.terms = terms;
-    this.phraseHelper = phraseHelper;
-    this.automata = automata;
-    this.hasUnrecognizedQueryPart = hasUnrecognizedQueryPart;
-    this.highlightFlags = highlightFlags;
-  }
-
-  public String getField() {
-    return field;
-  }
-
-  public Predicate<String> getFieldMatcher() {
-    return fieldMatcher;
-  }
-
-  public Query getQuery() {
-    return query;
-  }
-
-  public BytesRef[] getTerms() {
-    return terms;
-  }
-
-  public PhraseHelper getPhraseHelper() {
-    return phraseHelper;
-  }
-
-  public LabelledCharArrayMatcher[] getAutomata() {
-    return automata;
-  }
-
-  public boolean hasUnrecognizedQueryPart() {
-    return hasUnrecognizedQueryPart;
-  }
-
-  public Set<UnifiedHighlighter.HighlightFlag> getHighlightFlags() {
-    return highlightFlags;
-  }
-}
+public record UHComponents(
+    String field,
+    Predicate<String> fieldMatcher,
+    Query query,
+    BytesRef[] terms,
+    PhraseHelper phraseHelper,
+    LabelledCharArrayMatcher[] automata,
+    boolean hasUnrecognizedQueryPart,
+    Set<UnifiedHighlighter.HighlightFlag> highlightFlags) {}
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
index 397239c7d66..97a940446f0 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/uhighlight/UnifiedHighlighter.java
@@ -1252,19 +1252,17 @@ public class UnifiedHighlighter {
   }
 
   protected OffsetSource getOptimizedOffsetSource(UHComponents components) {
-    OffsetSource offsetSource = getOffsetSource(components.getField());
+    OffsetSource offsetSource = getOffsetSource(components.field());
 
     // null automata means unknown, so assume a possibility
     boolean mtqOrRewrite =
-        components.getAutomata() == null
-            || components.getAutomata().length > 0
-            || components.getPhraseHelper().willRewrite()
+        components.automata() == null
+            || components.automata().length > 0
+            || components.phraseHelper().willRewrite()
             || components.hasUnrecognizedQueryPart();
 
     // null terms means unknown, so assume something to highlight
-    if (mtqOrRewrite == false
-        && components.getTerms() != null
-        && components.getTerms().length == 0) {
+    if (mtqOrRewrite == false && components.terms() != null && components.terms().length == 0) {
       return OffsetSource.NONE_NEEDED; // nothing to highlight
     }
 
@@ -1295,9 +1293,9 @@ public class UnifiedHighlighter {
       OffsetSource offsetSource, UHComponents components) {
     switch (offsetSource) {
       case ANALYSIS:
-        if (!components.getPhraseHelper().hasPositionSensitivity()
-            && !components.getHighlightFlags().contains(HighlightFlag.PASSAGE_RELEVANCY_OVER_SPEED)
-            && !components.getHighlightFlags().contains(HighlightFlag.WEIGHT_MATCHES)) {
+        if (!components.phraseHelper().hasPositionSensitivity()
+            && !components.highlightFlags().contains(HighlightFlag.PASSAGE_RELEVANCY_OVER_SPEED)
+            && !components.highlightFlags().contains(HighlightFlag.WEIGHT_MATCHES)) {
           // skip using a memory index since it's pure term filtering
           return new TokenStreamOffsetStrategy(components, getIndexAnalyzer());
         } else {
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/BaseFragmentsBuilder.java b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/BaseFragmentsBuilder.java
index e46ecbfb466..292ffb6b3b8 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/BaseFragmentsBuilder.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/BaseFragmentsBuilder.java
@@ -215,18 +215,18 @@ public abstract class BaseFragmentsBuilder implements FragmentsBuilder {
             buffer, index, values, s, fragInfo.getEndOffset(), modifiedStartOffset);
     int srcIndex = 0;
     for (SubInfo subInfo : fragInfo.getSubInfos()) {
-      for (Toffs to : subInfo.getTermsOffsets()) {
+      for (Toffs to : subInfo.termsOffsets()) {
         fragment
             .append(
                 encoder.encodeText(
                     src.substring(srcIndex, to.getStartOffset() - modifiedStartOffset[0])))
-            .append(getPreTag(preTags, subInfo.getSeqnum()))
+            .append(getPreTag(preTags, subInfo.seqnum()))
             .append(
                 encoder.encodeText(
                     src.substring(
                         to.getStartOffset() - modifiedStartOffset[0],
                         to.getEndOffset() - modifiedStartOffset[0])))
-            .append(getPostTag(postTags, subInfo.getSeqnum()));
+            .append(getPostTag(postTags, subInfo.seqnum()));
         srcIndex = to.getEndOffset() - modifiedStartOffset[0];
       }
     }
@@ -298,7 +298,7 @@ public abstract class BaseFragmentsBuilder implements FragmentsBuilder {
           continue fragInfos;
         }
 
-        Toffs firstToffs = fragInfo.getSubInfos().get(0).getTermsOffsets().get(0);
+        Toffs firstToffs = fragInfo.getSubInfos().get(0).termsOffsets().get(0);
         if (fragInfo.getStartOffset() >= fieldEnd || firstToffs.getStartOffset() >= fieldEnd) {
           continue;
         }
@@ -320,7 +320,7 @@ public abstract class BaseFragmentsBuilder implements FragmentsBuilder {
         while (subInfoIterator.hasNext()) {
           SubInfo subInfo = subInfoIterator.next();
           List<Toffs> toffsList = new ArrayList<>();
-          Iterator<Toffs> toffsIterator = subInfo.getTermsOffsets().iterator();
+          Iterator<Toffs> toffsIterator = subInfo.termsOffsets().iterator();
           while (toffsIterator.hasNext()) {
             Toffs toffs = toffsIterator.next();
             if (toffs.getStartOffset() >= fieldEnd) {
@@ -359,12 +359,11 @@ public abstract class BaseFragmentsBuilder implements FragmentsBuilder {
             }
           }
           if (!toffsList.isEmpty()) {
-            subInfos.add(
-                new SubInfo(subInfo.getText(), toffsList, subInfo.getSeqnum(), subInfo.getBoost()));
-            boost += subInfo.getBoost();
+            subInfos.add(new SubInfo(subInfo.text(), toffsList, subInfo.seqnum(), subInfo.boost()));
+            boost += subInfo.boost();
           }
 
-          if (subInfo.getTermsOffsets().isEmpty()) {
+          if (subInfo.termsOffsets().isEmpty()) {
             subInfoIterator.remove();
           }
         }
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldFragList.java b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldFragList.java
index d08060b8945..6799b39f856 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldFragList.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/FieldFragList.java
@@ -101,37 +101,15 @@ public abstract class FieldFragList {
       return sb.toString();
     }
 
-    /** Represents the list of term offsets for some text */
-    public static class SubInfo {
-      private final String text; // unnecessary member, just exists for debugging purpose
-      // usually termsOffsets.size() == 1,
-      // but if position-gap > 1 and slop > 0 then size() could be greater than 1
-      private final List<Toffs> termsOffsets;
-      private final int seqnum;
-      private final float boost; // used for scoring split WeightedPhraseInfos.
-
-      public SubInfo(String text, List<Toffs> termsOffsets, int seqnum, float boost) {
-        this.text = text;
-        this.termsOffsets = termsOffsets;
-        this.seqnum = seqnum;
-        this.boost = boost;
-      }
-
-      public List<Toffs> getTermsOffsets() {
-        return termsOffsets;
-      }
-
-      public int getSeqnum() {
-        return seqnum;
-      }
-
-      public String getText() {
-        return text;
-      }
-
-      public float getBoost() {
-        return boost;
-      }
+    /**
+     * Represents the list of term offsets for some text
+     *
+     * @param text unnecessary member, just exists for debugging purpose
+     * @param termsOffsets usually termsOffsets.size() == 1, but if position-gap > 1 and slop > 0
+     *     then size() could be greater than 1
+     * @param boost used for scoring split WeightedPhraseInfos.
+     */
+    public record SubInfo(String text, List<Toffs> termsOffsets, int seqnum, float boost) {
 
       @Override
       public String toString() {
diff --git a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/WeightedFieldFragList.java b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/WeightedFieldFragList.java
index 6965ee66117..1b3c7c1a88a 100644
--- a/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/WeightedFieldFragList.java
+++ b/lucene/highlighter/src/java/org/apache/lucene/search/vectorhighlight/WeightedFieldFragList.java
@@ -70,13 +70,10 @@ public class WeightedFieldFragList extends FieldFragList {
 
     float totalBoost = 0;
     for (SubInfo tempSubInfo : tempSubInfos) {
-      float subInfoBoost = tempSubInfo.getBoost() * norm;
+      float subInfoBoost = tempSubInfo.boost() * norm;
       realSubInfos.add(
           new SubInfo(
-              tempSubInfo.getText(),
-              tempSubInfo.getTermsOffsets(),
-              tempSubInfo.getSeqnum(),
-              subInfoBoost));
+              tempSubInfo.text(), tempSubInfo.termsOffsets(), tempSubInfo.seqnum(), subInfoBoost));
       totalBoost += subInfoBoost;
     }
 
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterRanking.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterRanking.java
index 83ce335e5a9..6c7e9c89174 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterRanking.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/TestUnifiedHighlighterRanking.java
@@ -203,23 +203,7 @@ public class TestUnifiedHighlighterRanking extends UnifiedHighlighterTestBase {
     }
   }
 
-  static class Pair {
-    final int start;
-    final int end;
-
-    Pair(int start, int end) {
-      this.start = start;
-      this.end = end;
-    }
-
-    @Override
-    public int hashCode() {
-      final int prime = 31;
-      int result = 1;
-      result = prime * result + end;
-      result = prime * result + start;
-      return result;
-    }
+  record Pair(int start, int end) {
 
     @Override
     public boolean equals(Object obj) {
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/visibility/TestUnifiedHighlighterExtensibility.java b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/visibility/TestUnifiedHighlighterExtensibility.java
index d12a2109101..55146300a49 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/visibility/TestUnifiedHighlighterExtensibility.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/uhighlight/visibility/TestUnifiedHighlighterExtensibility.java
@@ -175,14 +175,14 @@ public class TestUnifiedHighlighterExtensibility extends LuceneTestCase {
             OffsetSource offsetSource = getOptimizedOffsetSource(components);
 
             // test all is accessible
-            components.getField();
-            components.getFieldMatcher();
-            components.getQuery();
-            components.getTerms();
-            components.getPhraseHelper();
-            components.getAutomata();
+            components.field();
+            components.fieldMatcher();
+            components.query();
+            components.terms();
+            components.phraseHelper();
+            components.automata();
             components.hasUnrecognizedQueryPart();
-            components.getHighlightFlags();
+            components.highlightFlags();
 
             return new CustomFieldHighlighter(
                 field,
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestSimpleFragmentsBuilder.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestSimpleFragmentsBuilder.java
index e4a949cc729..b6ff90c47ac 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestSimpleFragmentsBuilder.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestSimpleFragmentsBuilder.java
@@ -334,12 +334,5 @@ public class TestSimpleFragmentsBuilder extends AbstractTestCase {
     return value;
   }
 
-  private static class Doc {
-
-    final String[][] fieldValues;
-
-    private Doc(String[][] fieldValues) {
-      this.fieldValues = fieldValues;
-    }
-  }
+  private record Doc(String[][] fieldValues) {}
 }
diff --git a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestWeightedFragListBuilder.java b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestWeightedFragListBuilder.java
index 9fcf4d67298..ad60e995308 100644
--- a/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestWeightedFragListBuilder.java
+++ b/lucene/highlighter/src/test/org/apache/lucene/search/vectorhighlight/TestWeightedFragListBuilder.java
@@ -56,7 +56,7 @@ public class TestWeightedFragListBuilder extends AbstractTestCase {
     float totalSubInfoBoost = 0;
     for (WeightedFragInfo info : ffl.getFragInfos()) {
       for (SubInfo subInfo : info.getSubInfos()) {
-        totalSubInfoBoost += subInfo.getBoost();
+        totalSubInfoBoost += subInfo.boost();
       }
     }
     assertEquals(expectedTotalSubInfoBoost, totalSubInfoBoost, .0000001);
diff --git a/lucene/join/src/java/org/apache/lucene/search/join/DiversifyingNearestChildrenKnnCollector.java b/lucene/join/src/java/org/apache/lucene/search/join/DiversifyingNearestChildrenKnnCollector.java
index afab8ac57d9..15227a50342 100644
--- a/lucene/join/src/java/org/apache/lucene/search/join/DiversifyingNearestChildrenKnnCollector.java
+++ b/lucene/join/src/java/org/apache/lucene/search/join/DiversifyingNearestChildrenKnnCollector.java
@@ -278,15 +278,8 @@ class DiversifyingNearestChildrenKnnCollector extends AbstractKnnCollector {
   }
 
   /** Keeps track of child node, parent node, and the stored score. */
-  private static class ParentChildScore implements Comparable<ParentChildScore> {
-    private final int parent, child;
-    private final float score;
-
-    ParentChildScore(int child, int parent, float score) {
-      this.child = child;
-      this.parent = parent;
-      this.score = score;
-    }
+  private record ParentChildScore(int child, int parent, float score)
+      implements Comparable<ParentChildScore> {
 
     @Override
     public int compareTo(ParentChildScore o) {
diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/AnalysisImpl.java b/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/AnalysisImpl.java
index 7f5136a2dd8..9a70acc7c36 100644
--- a/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/AnalysisImpl.java
+++ b/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/AnalysisImpl.java
@@ -167,16 +167,16 @@ public final class AnalysisImpl implements Analysis {
 
       // set tokenizer
       builder.withTokenizer(
-          config.getTokenizerConfig().getName(), config.getTokenizerConfig().getParams());
+          config.getTokenizerConfig().name(), config.getTokenizerConfig().params());
 
       // add char filters
       for (CustomAnalyzerConfig.ComponentConfig cfConf : config.getCharFilterConfigs()) {
-        builder.addCharFilter(cfConf.getName(), cfConf.getParams());
+        builder.addCharFilter(cfConf.name(), cfConf.params());
       }
 
       // add token filters
       for (CustomAnalyzerConfig.ComponentConfig tfConf : config.getTokenFilterConfigs()) {
-        builder.addTokenFilter(tfConf.getName(), tfConf.getParams());
+        builder.addTokenFilter(tfConf.name(), tfConf.params());
       }
 
       // build analyzer
diff --git a/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/CustomAnalyzerConfig.java b/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/CustomAnalyzerConfig.java
index aaa29c47937..465d6a37f1e 100644
--- a/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/CustomAnalyzerConfig.java
+++ b/lucene/luke/src/java/org/apache/lucene/luke/models/analysis/CustomAnalyzerConfig.java
@@ -99,24 +99,15 @@ public final class CustomAnalyzerConfig {
     return List.copyOf(tokenFilterConfigs);
   }
 
-  static class ComponentConfig {
-
-    /* SPI name */
-    private final String name;
-    /* parameter map */
-    private final Map<String, String> params;
+  /**
+   * @param name SPI name
+   * @param params parameter map
+   */
+  record ComponentConfig(String name, Map<String, String> params) {
 
     ComponentConfig(String name, Map<String, String> params) {
       this.name = Objects.requireNonNull(name);
       this.params = Objects.requireNonNull(params);
     }
-
-    String getName() {
-      return this.name;
-    }
-
-    Map<String, String> getParams() {
-      return this.params;
-    }
   }
 }
diff --git a/lucene/memory/src/test/org/apache/lucene/index/memory/TestMemoryIndex.java b/lucene/memory/src/test/org/apache/lucene/index/memory/TestMemoryIndex.java
index cf5628b9873..18e97c67d9d 100644
--- a/lucene/memory/src/test/org/apache/lucene/index/memory/TestMemoryIndex.java
+++ b/lucene/memory/src/test/org/apache/lucene/index/memory/TestMemoryIndex.java
@@ -1010,28 +1010,14 @@ public class TestMemoryIndex extends LuceneTestCase {
     assertEquals(50, sndv.nextValue());
   }
 
-  private static class MockIndexableField implements IndexableField {
-
-    private final String field;
-    private final BytesRef value;
-    private final IndexableFieldType fieldType;
-
-    MockIndexableField(String field, BytesRef value, IndexableFieldType fieldType) {
-      this.field = field;
-      this.value = value;
-      this.fieldType = fieldType;
-    }
+  private record MockIndexableField(String field, BytesRef value, IndexableFieldType fieldType)
+      implements IndexableField {
 
     @Override
     public String name() {
       return field;
     }
 
-    @Override
-    public IndexableFieldType fieldType() {
-      return fieldType;
-    }
-
     @Override
     public TokenStream tokenStream(Analyzer analyzer, TokenStream reuse) {
       return null;
diff --git a/lucene/misc/src/java/org/apache/lucene/misc/util/fst/UpToTwoPositiveIntOutputs.java b/lucene/misc/src/java/org/apache/lucene/misc/util/fst/UpToTwoPositiveIntOutputs.java
index c35a03dfc9f..c7e2da71552 100644
--- a/lucene/misc/src/java/org/apache/lucene/misc/util/fst/UpToTwoPositiveIntOutputs.java
+++ b/lucene/misc/src/java/org/apache/lucene/misc/util/fst/UpToTwoPositiveIntOutputs.java
@@ -42,36 +42,11 @@ import org.apache.lucene.util.fst.Outputs;
 public final class UpToTwoPositiveIntOutputs extends Outputs<Object> {
 
   /** Holds two long outputs. */
-  public static final class TwoLongs {
-    public final long first;
-    public final long second;
-
-    public TwoLongs(long first, long second) {
-      this.first = first;
-      this.second = second;
+  public record TwoLongs(long first, long second) {
+    public TwoLongs {
       assert first >= 0;
       assert second >= 0;
     }
-
-    @Override
-    public String toString() {
-      return "TwoLongs:" + first + "," + second;
-    }
-
-    @Override
-    public boolean equals(Object _other) {
-      if (_other instanceof TwoLongs) {
-        final TwoLongs other = (TwoLongs) _other;
-        return first == other.first && second == other.second;
-      } else {
-        return false;
-      }
-    }
-
-    @Override
-    public int hashCode() {
-      return (int) ((first ^ (first >>> 32)) ^ (second ^ (second >> 32)));
-    }
   }
 
   private static final Long NO_OUTPUT = 0L;
diff --git a/lucene/misc/src/test/org/apache/lucene/misc/util/fst/TestFSTsMisc.java b/lucene/misc/src/test/org/apache/lucene/misc/util/fst/TestFSTsMisc.java
index 44c342b29ab..5d10c6a4911 100644
--- a/lucene/misc/src/test/org/apache/lucene/misc/util/fst/TestFSTsMisc.java
+++ b/lucene/misc/src/test/org/apache/lucene/misc/util/fst/TestFSTsMisc.java
@@ -114,10 +114,12 @@ public class TestFSTsMisc extends LuceneTestCase {
         protected boolean outputsEqual(Object output1, Object output2) {
           if (output1 instanceof TwoLongs && output2 instanceof List) {
             TwoLongs twoLongs1 = (TwoLongs) output1;
-            return Arrays.asList(new Long[] {twoLongs1.first, twoLongs1.second}).equals(output2);
+            return Arrays.asList(new Long[] {twoLongs1.first(), twoLongs1.second()})
+                .equals(output2);
           } else if (output2 instanceof TwoLongs && output1 instanceof List) {
             TwoLongs twoLongs2 = (TwoLongs) output2;
-            return Arrays.asList(new Long[] {twoLongs2.first, twoLongs2.second}).equals(output1);
+            return Arrays.asList(new Long[] {twoLongs2.first(), twoLongs2.second()})
+                .equals(output1);
           }
           return output1.equals(output2);
         }
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/HighlightsMatch.java b/lucene/monitor/src/java/org/apache/lucene/monitor/HighlightsMatch.java
index 0e3aea210a1..013c1bf6282 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/HighlightsMatch.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/HighlightsMatch.java
@@ -180,47 +180,16 @@ public class HighlightsMatch extends QueryMatch {
     hitSet.add(new Hit(startPos, startOffset, endPos, endOffset));
   }
 
-  /** Represents an individual hit */
-  public static class Hit implements Comparable<Hit> {
-
-    /** The start position */
-    public final int startPosition;
-
-    /** The start offset */
-    public final int startOffset;
-
-    /** The end positions */
-    public final int endPosition;
-
-    /** The end offset */
-    public final int endOffset;
-
-    public Hit(int startPosition, int startOffset, int endPosition, int endOffset) {
-      this.startPosition = startPosition;
-      this.startOffset = startOffset;
-      this.endPosition = endPosition;
-      this.endOffset = endOffset;
-    }
-
-    @Override
-    public boolean equals(Object obj) {
-      if (this == obj) return true;
-      if (!(obj instanceof Hit)) return false;
-      Hit other = (Hit) obj;
-      return this.startOffset == other.startOffset
-          && this.endOffset == other.endOffset
-          && this.startPosition == other.startPosition
-          && this.endPosition == other.endPosition;
-    }
-
-    @Override
-    public int hashCode() {
-      int result = startPosition;
-      result = 31 * result + startOffset;
-      result = 31 * result + endPosition;
-      result = 31 * result + endOffset;
-      return result;
-    }
+  /**
+   * Represents an individual hit
+   *
+   * @param startPosition The start position
+   * @param startOffset The start offset
+   * @param endPosition The end position
+   * @param endOffset The end offset
+   */
+  public record Hit(int startPosition, int startOffset, int endPosition, int endOffset)
+      implements Comparable<Hit> {
 
     @Override
     public String toString() {
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/Monitor.java b/lucene/monitor/src/java/org/apache/lucene/monitor/Monitor.java
index affb851ee51..e450f687c1a 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/Monitor.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/Monitor.java
@@ -116,24 +116,14 @@ public class Monitor implements Closeable {
         queryIndex.numDocs(), queryIndex.cacheSize(), queryIndex.getLastPurged());
   }
 
-  /** Statistics for the query cache and query index */
-  public static class QueryCacheStats {
-
-    /** Total number of queries in the query index */
-    public final int queries;
-
-    /** Total number of queries int the query cache */
-    public final int cachedQueries;
-
-    /** Time the query cache was last purged */
-    public final long lastPurged;
-
-    public QueryCacheStats(int queries, int cachedQueries, long lastPurged) {
-      this.queries = queries;
-      this.cachedQueries = cachedQueries;
-      this.lastPurged = lastPurged;
-    }
-  }
+  /**
+   * Statistics for the query cache and query index
+   *
+   * @param queries Total number of queries in the query index
+   * @param cachedQueries Total number of queries int the query cache
+   * @param lastPurged Time the query cache was last purged
+   */
+  public record QueryCacheStats(int queries, int cachedQueries, long lastPurged) {}
 
   /**
    * Remove unused queries from the query cache.
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/ParallelMatcher.java b/lucene/monitor/src/java/org/apache/lucene/monitor/ParallelMatcher.java
index 027343701fc..e6974b234f8 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/ParallelMatcher.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/ParallelMatcher.java
@@ -138,35 +138,15 @@ public class ParallelMatcher<T extends QueryMatch> extends CandidateMatcher<T> {
     }
   }
 
-  private static class MatcherTask {
-
-    final String id;
-    final Query matchQuery;
-    final Map<String, String> metadata;
-
-    private MatcherTask(String id, Query matchQuery, Map<String, String> metadata) {
-      this.id = id;
-      this.matchQuery = matchQuery;
-      this.metadata = metadata;
-    }
-  }
+  private record MatcherTask(String id, Query matchQuery, Map<String, String> metadata) {}
 
   /* Marker object placed on the queue after all matches are done, to indicate to the
   worker threads that they should finish */
   private static final MatcherTask END = new MatcherTask("", null, Collections.emptyMap());
 
-  private static class ParallelMatcherFactory<T extends QueryMatch> implements MatcherFactory<T> {
-
-    private final ExecutorService executor;
-    private final MatcherFactory<T> matcherFactory;
-    private final int threads;
-
-    ParallelMatcherFactory(
-        ExecutorService executor, MatcherFactory<T> matcherFactory, int threads) {
-      this.executor = executor;
-      this.matcherFactory = matcherFactory;
-      this.threads = threads;
-    }
+  private record ParallelMatcherFactory<T extends QueryMatch>(
+      ExecutorService executor, MatcherFactory<T> matcherFactory, int threads)
+      implements MatcherFactory<T> {
 
     @Override
     public ParallelMatcher<T> createMatcher(IndexSearcher searcher) {
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/PartitionMatcher.java b/lucene/monitor/src/java/org/apache/lucene/monitor/PartitionMatcher.java
index 7a38edd74a1..d432f8437c8 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/PartitionMatcher.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/PartitionMatcher.java
@@ -51,18 +51,7 @@ public class PartitionMatcher<T extends QueryMatch> extends CandidateMatcher<T>
 
   private final CandidateMatcher<T> resolvingMatcher;
 
-  private static class MatchTask {
-
-    final String queryId;
-    final Query matchQuery;
-    final Map<String, String> metadata;
-
-    private MatchTask(String queryId, Query matchQuery, Map<String, String> metadata) {
-      this.queryId = queryId;
-      this.matchQuery = matchQuery;
-      this.metadata = metadata;
-    }
-  }
+  private record MatchTask(String queryId, Query matchQuery, Map<String, String> metadata) {}
 
   private final List<MatchTask> tasks = new ArrayList<>();
 
@@ -135,18 +124,9 @@ public class PartitionMatcher<T extends QueryMatch> extends CandidateMatcher<T>
     }
   }
 
-  private static class PartitionMatcherFactory<T extends QueryMatch> implements MatcherFactory<T> {
-
-    private final ExecutorService executor;
-    private final MatcherFactory<T> matcherFactory;
-    private final int threads;
-
-    PartitionMatcherFactory(
-        ExecutorService executor, MatcherFactory<T> matcherFactory, int threads) {
-      this.executor = executor;
-      this.matcherFactory = matcherFactory;
-      this.threads = threads;
-    }
+  private record PartitionMatcherFactory<T extends QueryMatch>(
+      ExecutorService executor, MatcherFactory<T> matcherFactory, int threads)
+      implements MatcherFactory<T> {
 
     @Override
     public PartitionMatcher<T> createMatcher(IndexSearcher searcher) {
diff --git a/lucene/monitor/src/java/org/apache/lucene/monitor/WritableQueryIndex.java b/lucene/monitor/src/java/org/apache/lucene/monitor/WritableQueryIndex.java
index b51ad40d9c4..69ab393b9bf 100644
--- a/lucene/monitor/src/java/org/apache/lucene/monitor/WritableQueryIndex.java
+++ b/lucene/monitor/src/java/org/apache/lucene/monitor/WritableQueryIndex.java
@@ -130,15 +130,7 @@ class WritableQueryIndex extends QueryIndex {
     }
   }
 
-  private static class Indexable {
-    final QueryCacheEntry queryCacheEntry;
-    final Document document;
-
-    private Indexable(QueryCacheEntry queryCacheEntry, Document document) {
-      this.queryCacheEntry = queryCacheEntry;
-      this.document = document;
-    }
-  }
+  private record Indexable(QueryCacheEntry queryCacheEntry, Document document) {}
 
   private void populateQueryCache(MonitorQuerySerializer serializer, QueryDecomposer decomposer)
       throws IOException {
diff --git a/lucene/monitor/src/test/org/apache/lucene/monitor/TestCachePurging.java b/lucene/monitor/src/test/org/apache/lucene/monitor/TestCachePurging.java
index a020c23d336..e681d173b07 100644
--- a/lucene/monitor/src/test/org/apache/lucene/monitor/TestCachePurging.java
+++ b/lucene/monitor/src/test/org/apache/lucene/monitor/TestCachePurging.java
@@ -51,7 +51,7 @@ public class TestCachePurging extends MonitorTestBase {
       monitor.register(queries);
       assertEquals(3, monitor.getQueryCount());
       assertEquals(4, monitor.getDisjunctCount());
-      assertEquals(4, monitor.getQueryCacheStats().cachedQueries);
+      assertEquals(4, monitor.getQueryCacheStats().cachedQueries());
 
       Document doc = new Document();
       doc.add(newTextField("field", "test1 test2 test3", Field.Store.NO));
@@ -59,11 +59,11 @@ public class TestCachePurging extends MonitorTestBase {
 
       monitor.deleteById("1");
       assertEquals(2, monitor.getQueryCount());
-      assertEquals(4, monitor.getQueryCacheStats().cachedQueries);
+      assertEquals(4, monitor.getQueryCacheStats().cachedQueries());
       assertEquals(2, monitor.match(doc, QueryMatch.SIMPLE_MATCHER).getMatchCount());
 
       monitor.purgeCache();
-      assertEquals(2, monitor.getQueryCacheStats().cachedQueries);
+      assertEquals(2, monitor.getQueryCacheStats().cachedQueries());
 
       MatchingQueries<QueryMatch> result = monitor.match(doc, QueryMatch.SIMPLE_MATCHER);
       assertEquals(2, result.getMatchCount());
@@ -109,13 +109,13 @@ public class TestCachePurging extends MonitorTestBase {
           monitor.deleteById(Integer.toString(i));
         }
 
-        assertEquals(200, monitor.getQueryCacheStats().cachedQueries);
+        assertEquals(200, monitor.getQueryCacheStats().cachedQueries());
 
         startUpdating.countDown();
         monitor.purgeCache();
         finishUpdating.await();
 
-        assertEquals(340, monitor.getQueryCacheStats().cachedQueries);
+        assertEquals(340, monitor.getQueryCacheStats().cachedQueries());
         Document doc = new Document();
         doc.add(newTextField("field", "test", Field.Store.NO));
         MatchingQueries<QueryMatch> matcher = monitor.match(doc, QueryMatch.SIMPLE_MATCHER);
@@ -137,15 +137,15 @@ public class TestCachePurging extends MonitorTestBase {
         new MonitorConfiguration().setPurgeFrequency(50, TimeUnit.MILLISECONDS);
     try (Monitor monitor = new Monitor(ANALYZER, Presearcher.NO_FILTERING, config)) {
 
-      assertEquals(-1, monitor.getQueryCacheStats().lastPurged);
+      assertEquals(-1, monitor.getQueryCacheStats().lastPurged());
 
       for (int i = 0; i < 100; i++) {
         monitor.register(newMonitorQuery(i));
       }
-      assertEquals(100, monitor.getQueryCacheStats().cachedQueries);
+      assertEquals(100, monitor.getQueryCacheStats().cachedQueries());
 
       monitor.deleteById("5");
-      assertEquals(99, monitor.getQueryCacheStats().queries);
+      assertEquals(99, monitor.getQueryCacheStats().queries());
 
       CountDownLatch latch = new CountDownLatch(1);
       monitor.addQueryIndexUpdateListener(
@@ -154,7 +154,7 @@ public class TestCachePurging extends MonitorTestBase {
             public void onPurge() {
               // It can sometimes take a couple of purge runs to get everything in sync
               try {
-                if (monitor.getQueryCacheStats().cachedQueries == 99) latch.countDown();
+                if (monitor.getQueryCacheStats().cachedQueries() == 99) latch.countDown();
               } catch (IOException e) {
                 // Ignore
                 throw new RuntimeException(e);
@@ -163,9 +163,9 @@ public class TestCachePurging extends MonitorTestBase {
           });
 
       assertTrue(latch.await(5, TimeUnit.SECONDS));
-      assertEquals(99, monitor.getQueryCacheStats().queries);
-      assertEquals(99, monitor.getQueryCacheStats().cachedQueries);
-      assertTrue(monitor.getQueryCacheStats().lastPurged > 0);
+      assertEquals(99, monitor.getQueryCacheStats().queries());
+      assertEquals(99, monitor.getQueryCacheStats().cachedQueries());
+      assertTrue(monitor.getQueryCacheStats().lastPurged() > 0);
     }
   }
 }
diff --git a/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java b/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java
index 6f683537c6a..63d66822cab 100644
--- a/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java
+++ b/lucene/queries/src/java/org/apache/lucene/queries/intervals/DisjunctionIntervalsSource.java
@@ -370,16 +370,9 @@ class DisjunctionIntervalsSource extends IntervalsSource {
         }
       };
 
-  private static class DisjunctionMatchesIterator implements IntervalMatchesIterator {
-
-    final DisjunctionIntervalIterator it;
-    final List<IntervalMatchesIterator> subs;
-
-    private DisjunctionMatchesIterator(
-        DisjunctionIntervalIterator it, List<IntervalMatchesIterator> subs) {
-      this.it = it;
-      this.subs = subs;
-    }
+  private record DisjunctionMatchesIterator(
+      DisjunctionIntervalIterator it, List<IntervalMatchesIterator> subs)
+      implements IntervalMatchesIterator {
 
     @Override
     public boolean next() throws IOException {
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtendableQueryParser.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtendableQueryParser.java
index 7a79c850b35..b0e06d053b8 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtendableQueryParser.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtendableQueryParser.java
@@ -108,9 +108,9 @@ public class ExtendableQueryParser extends QueryParser {
       throws ParseException {
     final Pair<String, String> splitExtensionField =
         this.extensions.splitExtensionField(defaultField, field);
-    final ParserExtension extension = this.extensions.getExtension(splitExtensionField.cud);
+    final ParserExtension extension = this.extensions.getExtension(splitExtensionField.cud());
     if (extension != null) {
-      return extension.parse(new ExtensionQuery(this, splitExtensionField.cur, queryText));
+      return extension.parse(new ExtensionQuery(this, splitExtensionField.cur(), queryText));
     }
     return super.getFieldQuery(field, queryText, quoted);
   }
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtensionQuery.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtensionQuery.java
index 8e4acd17531..b86b1831cc9 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtensionQuery.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/ExtensionQuery.java
@@ -22,52 +22,11 @@ import org.apache.lucene.queryparser.classic.QueryParser;
  * {@link ExtensionQuery} holds all query components extracted from the original query string like
  * the query field and the extension query string.
  *
+ * @param topLevelParser the top level parser
+ * @param field the query field
+ * @param rawQueryString the raw extension query string
  * @see Extensions
  * @see ExtendableQueryParser
  * @see ParserExtension
  */
-public class ExtensionQuery {
-
-  private final String field;
-  private final String rawQueryString;
-  private final QueryParser topLevelParser;
-
-  /**
-   * Creates a new {@link ExtensionQuery}
-   *
-   * @param field the query field
-   * @param rawQueryString the raw extension query string
-   */
-  public ExtensionQuery(QueryParser topLevelParser, String field, String rawQueryString) {
-    this.field = field;
-    this.rawQueryString = rawQueryString;
-    this.topLevelParser = topLevelParser;
-  }
-
-  /**
-   * Returns the query field
-   *
-   * @return the query field
-   */
-  public String getField() {
-    return field;
-  }
-
-  /**
-   * Returns the raw extension query string
-   *
-   * @return the raw extension query string
-   */
-  public String getRawQueryString() {
-    return rawQueryString;
-  }
-
-  /**
-   * Returns the top level parser which created this {@link ExtensionQuery}
-   *
-   * @return the top level parser which created this {@link ExtensionQuery}
-   */
-  public QueryParser getTopLevelParser() {
-    return topLevelParser;
-  }
-}
+public record ExtensionQuery(QueryParser topLevelParser, String field, String rawQueryString) {}
diff --git a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/Extensions.java b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/Extensions.java
index c2dda823598..0b016487d39 100644
--- a/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/Extensions.java
+++ b/lucene/queryparser/src/java/org/apache/lucene/queryparser/ext/Extensions.java
@@ -167,20 +167,5 @@ public class Extensions {
    * @param <Cur> the pairs first element
    * @param <Cud> the pairs last element of the pair.
    */
-  public static class Pair<Cur, Cud> {
-
-    public final Cur cur;
-    public final Cud cud;
-
-    /**
-     * Creates a new Pair
-     *
-     * @param cur the pairs first element
-     * @param cud the pairs last element
-     */
-    public Pair(Cur cur, Cud cud) {
-      this.cur = cur;
-      this.cud = cud;
-    }
-  }
+  public record Pair<Cur, Cud>(Cur cur, Cud cud) {}
 }
diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiPhraseQueryParsing.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiPhraseQueryParsing.java
index fb028b858d3..2109d686763 100644
--- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiPhraseQueryParsing.java
+++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/classic/TestMultiPhraseQueryParsing.java
@@ -28,15 +28,7 @@ import org.apache.lucene.tests.util.LuceneTestCase;
 
 public class TestMultiPhraseQueryParsing extends LuceneTestCase {
 
-  private static class TokenAndPos {
-    public final String token;
-    public final int pos;
-
-    public TokenAndPos(String token, int pos) {
-      this.token = token;
-      this.pos = pos;
-    }
-  }
+  private record TokenAndPos(String token, int pos) {}
 
   private static class CannedAnalyzer extends Analyzer {
     private final TokenAndPos[] tokens;
diff --git a/lucene/queryparser/src/test/org/apache/lucene/queryparser/ext/ExtensionStub.java b/lucene/queryparser/src/test/org/apache/lucene/queryparser/ext/ExtensionStub.java
index 3a0b80a6b37..4cc9502d0bf 100644
--- a/lucene/queryparser/src/test/org/apache/lucene/queryparser/ext/ExtensionStub.java
+++ b/lucene/queryparser/src/test/org/apache/lucene/queryparser/ext/ExtensionStub.java
@@ -25,6 +25,6 @@ class ExtensionStub extends ParserExtension {
 
   @Override
   public Query parse(ExtensionQuery components) throws ParseException {
-    return new TermQuery(new Term(components.getField(), components.getRawQueryString()));
+    return new TermQuery(new Term(components.field(), components.rawQueryString()));
   }
 }
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyJob.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyJob.java
index 236e61c1ee3..c91febf7325 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyJob.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyJob.java
@@ -137,7 +137,7 @@ public abstract class CopyJob implements Comparable<CopyJob> {
       if (prevTmpFileName != null) {
         // This fileName is common to both jobs, and the old job already finished copying it (to a
         // temp file), so we keep it:
-        long fileLength = ent.getValue().length;
+        long fileLength = ent.getValue().length();
         bytesAlreadyCopied += fileLength;
         dest.message(
             "xfer: carry over already-copied file "
@@ -187,7 +187,7 @@ public abstract class CopyJob implements Comparable<CopyJob> {
 
         prevJob.current = null;
 
-        totBytes += current.metaData.length;
+        totBytes += current.metaData.length();
 
         // So it's not in our copy list anymore:
         it.remove();
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyOneFile.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyOneFile.java
index d8329ff761c..5ee74ed5ee9 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyOneFile.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyOneFile.java
@@ -53,7 +53,7 @@ public class CopyOneFile implements Closeable {
 
     // last 8 bytes are checksum, which we write ourselves after copying all bytes and confirming
     // checksum:
-    bytesToCopy = metaData.length - Long.BYTES;
+    bytesToCopy = metaData.length() - Long.BYTES;
 
     if (Node.VERBOSE_FILES) {
       dest.message(
@@ -97,7 +97,7 @@ public class CopyOneFile implements Closeable {
       long bytesLeft = bytesToCopy - bytesCopied;
       if (bytesLeft == 0) {
         long checksum = out.getChecksum();
-        if (checksum != metaData.checksum) {
+        if (checksum != metaData.checksum()) {
           // Bits flipped during copy!
           dest.message(
               "file "
@@ -105,7 +105,7 @@ public class CopyOneFile implements Closeable {
                   + ": checksum mismatch after copy (bits flipped during network copy?) after-copy checksum="
                   + checksum
                   + " vs expected="
-                  + metaData.checksum
+                  + metaData.checksum()
                   + "; cancel job");
           throw new IOException("file " + name + ": checksum mismatch after file copy");
         }
@@ -134,7 +134,7 @@ public class CopyOneFile implements Closeable {
                   Locale.ROOT,
                   "file %s: done copying [%s, %.3fms]",
                   name,
-                  Node.bytesToString(metaData.length),
+                  Node.bytesToString(metaData.length()),
                   (System.nanoTime() - copyStartNS) / (double) TimeUnit.MILLISECONDS.toNanos(1)));
         }
 
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyState.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyState.java
index c4ef3135c38..b0ee9deb4b3 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyState.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/CopyState.java
@@ -25,36 +25,22 @@ import org.apache.lucene.index.SegmentInfos;
 /**
  * Holds incRef'd file level details for one point-in-time segment infos on the primary node.
  *
+ * @param infos only non-null on the primary node
  * @lucene.experimental
  */
-public class CopyState {
+public record CopyState(
+    Map<String, FileMetaData> files,
+    long version,
+    long gen,
+    byte[] infosBytes,
+    Set<String> completedMergeFiles,
+    long primaryGen,
+    SegmentInfos infos) {
 
-  public final Map<String, FileMetaData> files;
-  public final long version;
-  public final long gen;
-  public final byte[] infosBytes;
-  public final Set<String> completedMergeFiles;
-  public final long primaryGen;
-
-  // only non-null on the primary node
-  public final SegmentInfos infos;
-
-  public CopyState(
-      Map<String, FileMetaData> files,
-      long version,
-      long gen,
-      byte[] infosBytes,
-      Set<String> completedMergeFiles,
-      long primaryGen,
-      SegmentInfos infos) {
+  public CopyState {
     assert completedMergeFiles != null;
-    this.files = Collections.unmodifiableMap(files);
-    this.version = version;
-    this.gen = gen;
-    this.infosBytes = infosBytes;
-    this.completedMergeFiles = Collections.unmodifiableSet(completedMergeFiles);
-    this.primaryGen = primaryGen;
-    this.infos = infos;
+    files = Collections.unmodifiableMap(files);
+    completedMergeFiles = Collections.unmodifiableSet(completedMergeFiles);
   }
 
   @Override
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/FileMetaData.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/FileMetaData.java
index d7eeebf6646..48cebe2d6e9 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/FileMetaData.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/FileMetaData.java
@@ -19,31 +19,19 @@ package org.apache.lucene.replicator.nrt;
 
 /**
  * Holds metadata details about a single file that we use to confirm two files (one remote, one
- * local) are in fact "identical".
+ * local) are in fact "identical". Header and footer of the file must be identical between primary
+ * and replica to consider the files equal:
  *
+ * @param header Header of the file
+ * @param footer Footer of the file
+ * @param length Length of the file
+ * @param checksum Used to ensure no bit flips when copying the file:
  * @lucene.experimental
  */
-public class FileMetaData {
-
-  // Header and footer of the file must be identical between primary and replica to consider the
-  // files equal:
-  public final byte[] header;
-  public final byte[] footer;
-
-  public final long length;
-
-  // Used to ensure no bit flips when copying the file:
-  public final long checksum;
-
-  public FileMetaData(byte[] header, byte[] footer, long length, long checksum) {
-    this.header = header;
-    this.footer = footer;
-    this.length = length;
-    this.checksum = checksum;
-  }
+public record FileMetaData(byte[] header, byte[] footer, long length, long checksum) {
 
   @Override
   public String toString() {
-    return "FileMetaData(length=" + length + ")";
+    return "FileMetaData(length=" + length + " checksum=" + checksum + ")";
   }
 }
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/PrimaryNode.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/PrimaryNode.java
index d9605a9018d..6674d9f10d2 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/PrimaryNode.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/PrimaryNode.java
@@ -181,7 +181,7 @@ public abstract class PrimaryNode extends Node {
   }
 
   public long getCopyStateVersion() {
-    return copyState.version;
+    return copyState.version();
   }
 
   public synchronized long getLastCommitVersion() {
@@ -222,7 +222,7 @@ public abstract class PrimaryNode extends Node {
     // TODO (opto): it's a bit wasteful that we put "last refresh" version here, not the actual
     // version we are committing, because it means
     // on xlog replay we are replaying more ops than necessary.
-    commitData.put(VERSION_KEY, Long.toString(copyState.version));
+    commitData.put(VERSION_KEY, Long.toString(copyState.version()));
     message("top: commit commitData=" + commitData);
     writer.setLiveCommitData(commitData.entrySet(), false);
     writer.commit();
@@ -233,8 +233,8 @@ public abstract class PrimaryNode extends Node {
     ensureOpen(false);
     // message("top: getCopyState replicaID=" + replicaID + " replicaNodeID=" + replicaNodeID + "
     // version=" + curInfos.getVersion() + " infos=" + curInfos.toString());
-    assert curInfos == copyState.infos;
-    writer.incRefDeleter(copyState.infos);
+    assert curInfos == copyState.infos();
+    writer.incRefDeleter(copyState.infos());
     int count = copyingCount.incrementAndGet();
     assert count > 0;
     return copyState;
@@ -243,8 +243,8 @@ public abstract class PrimaryNode extends Node {
   /** Called once replica is done (or failed) copying an NRT point */
   public void releaseCopyState(CopyState copyState) throws IOException {
     // message("top: releaseCopyState version=" + copyState.version);
-    assert copyState.infos != null;
-    writer.decRefDeleter(copyState.infos);
+    assert copyState.infos() != null;
+    writer.decRefDeleter(copyState.infos());
     int count = copyingCount.decrementAndGet();
     assert count >= 0;
   }
diff --git a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/ReplicaNode.java b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/ReplicaNode.java
index c3d79b84843..e4a88e3dd03 100644
--- a/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/ReplicaNode.java
+++ b/lucene/replicator/src/java/org/apache/lucene/replicator/nrt/ReplicaNode.java
@@ -249,7 +249,7 @@ public abstract class ReplicaNode extends Node {
                   null);
           job.start();
 
-          message("top: init: sync sis.version=" + job.getCopyState().version);
+          message("top: init: sync sis.version=" + job.getCopyState().version());
 
           // Force this copy job to finish while we wait, now.  Note that this can be very time
           // consuming!
@@ -272,17 +272,17 @@ public abstract class ReplicaNode extends Node {
           }
         }
 
-        lastPrimaryGen = job.getCopyState().primaryGen;
+        lastPrimaryGen = job.getCopyState().primaryGen();
 
         SegmentInfos syncInfos =
             SegmentInfos.readCommit(
-                dir, toIndexInput(job.getCopyState().infosBytes), job.getCopyState().gen);
+                dir, toIndexInput(job.getCopyState().infosBytes()), job.getCopyState().gen());
 
         // Must always commit to a larger generation than what's currently in the index:
         syncInfos.updateGeneration(infos);
         infos = syncInfos;
 
-        assert infos.getVersion() == job.getCopyState().version;
+        assert infos.getVersion() == job.getCopyState().version();
         message("  version=" + infos.getVersion() + " segments=" + infos.toString());
         message("top: init: incRef nrtFiles=" + job.getFileNames());
         deleter.incRef(job.getFileNames());
@@ -293,7 +293,7 @@ public abstract class ReplicaNode extends Node {
         lastNRTFiles.addAll(job.getFileNames());
 
         message("top: init: set lastNRTFiles=" + lastNRTFiles);
-        lastFileMetaData = job.getCopyState().files;
+        lastFileMetaData = job.getCopyState().files();
         message(
             String.format(
                 Locale.ROOT,
@@ -301,7 +301,7 @@ public abstract class ReplicaNode extends Node {
                 id,
                 (System.nanoTime() - initSyncStartNS) / (double) TimeUnit.SECONDS.toNanos(1),
                 bytesToString(job.getTotalBytesCopied()),
-                job.getCopyState().version));
+                job.getCopyState().version()));
 
         doCommit = true;
       } else {
@@ -406,7 +406,7 @@ public abstract class ReplicaNode extends Node {
     CopyState copyState = job.getCopyState();
     message(
         "top: finishNRTCopy: version="
-            + copyState.version
+            + copyState.version()
             + (job.getFailed() ? " FAILED" : "")
             + " job="
             + job);
@@ -437,8 +437,8 @@ public abstract class ReplicaNode extends Node {
 
       // Turn byte[] back to SegmentInfos:
       SegmentInfos infos =
-          SegmentInfos.readCommit(dir, toIndexInput(copyState.infosBytes), copyState.gen);
-      assert infos.getVersion() == copyState.version;
+          SegmentInfos.readCommit(dir, toIndexInput(copyState.infosBytes()), copyState.gen());
+      assert infos.getVersion() == copyState.version();
 
       message("  version=" + infos.getVersion() + " segments=" + infos.toString());
 
@@ -447,7 +447,7 @@ public abstract class ReplicaNode extends Node {
 
       // Must first incRef new NRT files, then decRef old ones, to make sure we don't remove an NRT
       // file that's in common to both:
-      Collection<String> newFiles = copyState.files.keySet();
+      Collection<String> newFiles = copyState.files().keySet();
       message("top: incRef newNRTFiles=" + newFiles);
       deleter.incRef(newFiles);
 
@@ -467,9 +467,10 @@ public abstract class ReplicaNode extends Node {
       // finishes, copies its files out to us, but is then merged away (or dropped due to 100%
       // deletions) before we ever cutover to it
       // in an NRT point:
-      if (copyState.completedMergeFiles.isEmpty() == false) {
-        message("now remove-if-not-ref'd completed merge files: " + copyState.completedMergeFiles);
-        for (String fileName : copyState.completedMergeFiles) {
+      if (copyState.completedMergeFiles().isEmpty() == false) {
+        message(
+            "now remove-if-not-ref'd completed merge files: " + copyState.completedMergeFiles());
+        for (String fileName : copyState.completedMergeFiles()) {
           if (pendingMergeFiles.contains(fileName)) {
             pendingMergeFiles.remove(fileName);
             deleter.deleteIfNoRef(fileName);
@@ -477,7 +478,7 @@ public abstract class ReplicaNode extends Node {
         }
       }
 
-      lastFileMetaData = copyState.files;
+      lastFileMetaData = copyState.files();
     }
 
     int markerCount;
@@ -494,7 +495,7 @@ public abstract class ReplicaNode extends Node {
             "top: done sync: took %.3fs for %s, opened NRT reader version=%d markerCount=%d",
             (System.nanoTime() - startNS) / (double) TimeUnit.SECONDS.toNanos(1),
             bytesToString(job.getTotalBytesCopied()),
-            copyState.version,
+            copyState.version(),
             markerCount));
   }
 
@@ -609,7 +610,7 @@ public abstract class ReplicaNode extends Node {
       return null;
     }
 
-    assert newPrimaryGen == job.getCopyState().primaryGen;
+    assert newPrimaryGen == job.getCopyState().primaryGen();
 
     Collection<String> newNRTFiles = job.getFileNames();
 
@@ -865,8 +866,8 @@ public abstract class ReplicaNode extends Node {
       return false;
     }
 
-    if (Arrays.equals(destMetaData.header, srcMetaData.header) == false
-        || Arrays.equals(destMetaData.footer, srcMetaData.footer) == false) {
+    if (Arrays.equals(destMetaData.header(), srcMetaData.header()) == false
+        || Arrays.equals(destMetaData.footer(), srcMetaData.footer()) == false) {
       // Segment name was reused!  This is rare but possible and otherwise devastating:
       if (Node.VERBOSE_FILES) {
         message("file " + fileName + ": will copy [header/footer is different]");
diff --git a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleCopyJob.java b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleCopyJob.java
index d85b644c054..0cd8e85420b 100644
--- a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleCopyJob.java
+++ b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleCopyJob.java
@@ -66,13 +66,13 @@ class SimpleCopyJob extends CopyJob {
           c.out.writeByte((byte) 0);
           c.out.writeString(current.name);
           c.out.writeVLong(current.getBytesCopied());
-          totBytes += current.metaData.length;
+          totBytes += current.metaData.length();
         }
 
         for (Map.Entry<String, FileMetaData> ent : toCopy) {
           String fileName = ent.getKey();
           FileMetaData metaData = ent.getValue();
-          totBytes += metaData.length;
+          totBytes += metaData.length();
           c.out.writeByte((byte) 0);
           c.out.writeString(fileName);
           c.out.writeVLong(0);
@@ -86,12 +86,12 @@ class SimpleCopyJob extends CopyJob {
           // socket buffering waiting for primary to
           // send us this length:
           long len = c.in.readVLong();
-          if (len != current.metaData.length) {
+          if (len != current.metaData.length()) {
             throw new IllegalStateException(
                 "file "
                     + current.name
                     + ": meta data says length="
-                    + current.metaData.length
+                    + current.metaData.length()
                     + " but c.in says "
                     + len);
           }
@@ -197,12 +197,12 @@ class SimpleCopyJob extends CopyJob {
       FileMetaData metaData = next.getValue();
       String fileName = next.getKey();
       long len = c.in.readVLong();
-      if (len != metaData.length) {
+      if (len != metaData.length()) {
         throw new IllegalStateException(
             "file "
                 + fileName
                 + ": meta data says length="
-                + metaData.length
+                + metaData.length()
                 + " but c.in says "
                 + len);
       }
diff --git a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimplePrimaryNode.java b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimplePrimaryNode.java
index 0822b53947d..8c1f5fd71e3 100644
--- a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimplePrimaryNode.java
+++ b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimplePrimaryNode.java
@@ -388,17 +388,17 @@ class SimplePrimaryNode extends PrimaryNode {
   private static void writeCopyState(CopyState state, DataOutput out) throws IOException {
     // TODO (opto): we could encode to byte[] once when we created the copyState, and then just send
     // same byts to all replicas...
-    out.writeVInt(state.infosBytes.length);
-    out.writeBytes(state.infosBytes, 0, state.infosBytes.length);
-    out.writeVLong(state.gen);
-    out.writeVLong(state.version);
-    TestSimpleServer.writeFilesMetaData(out, state.files);
-
-    out.writeVInt(state.completedMergeFiles.size());
-    for (String fileName : state.completedMergeFiles) {
+    out.writeVInt(state.infosBytes().length);
+    out.writeBytes(state.infosBytes(), 0, state.infosBytes().length);
+    out.writeVLong(state.gen());
+    out.writeVLong(state.version());
+    TestSimpleServer.writeFilesMetaData(out, state.files());
+
+    out.writeVInt(state.completedMergeFiles().size());
+    for (String fileName : state.completedMergeFiles()) {
       out.writeString(fileName);
     }
-    out.writeVLong(state.primaryGen);
+    out.writeVLong(state.primaryGen());
   }
 
   /** Called when another node (replica) wants to copy files from us */
@@ -417,7 +417,7 @@ class SimplePrimaryNode extends PrimaryNode {
     } else if (b == 1) {
       // Caller does not have CopyState; we pull the latest one:
       copyState = getCopyState();
-      Thread.currentThread().setName("send-R" + replicaID + "-" + copyState.version);
+      Thread.currentThread().setName("send-R" + replicaID + "-" + copyState.version());
     } else {
       // Protocol error:
       throw new IllegalArgumentException("invalid CopyState byte=" + b);
diff --git a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleReplicaNode.java b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleReplicaNode.java
index 3af0915ca25..03cb5a6bfdd 100644
--- a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleReplicaNode.java
+++ b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/SimpleReplicaNode.java
@@ -136,7 +136,7 @@ class SimpleReplicaNode extends ReplicaNode {
         c.out.writeByte((byte) 1);
         c.flush();
         copyState = TestSimpleServer.readCopyState(c.in);
-        files = copyState.files;
+        files = copyState.files();
       } else {
         c.out.writeByte((byte) 0);
         copyState = null;
diff --git a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/TestSimpleServer.java b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/TestSimpleServer.java
index edcb09a01b7..82adf086bf2 100644
--- a/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/TestSimpleServer.java
+++ b/lucene/replicator/src/test/org/apache/lucene/replicator/nrt/TestSimpleServer.java
@@ -141,12 +141,12 @@ public class TestSimpleServer extends LuceneTestCase {
       out.writeString(ent.getKey());
 
       FileMetaData fmd = ent.getValue();
-      out.writeVLong(fmd.length);
-      out.writeVLong(fmd.checksum);
-      out.writeVInt(fmd.header.length);
-      out.writeBytes(fmd.header, 0, fmd.header.length);
-      out.writeVInt(fmd.footer.length);
-      out.writeBytes(fmd.footer, 0, fmd.footer.length);
+      out.writeVLong(fmd.length());
+      out.writeVLong(fmd.checksum());
+      out.writeVInt(fmd.header().length);
+      out.writeBytes(fmd.header(), 0, fmd.header().length);
+      out.writeVInt(fmd.footer().length);
+      out.writeBytes(fmd.footer(), 0, fmd.footer().length);
     }
   }
 
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/codecs/idversion/VersionBlockTreeTermsWriter.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/codecs/idversion/VersionBlockTreeTermsWriter.java
index b0abc0b5059..6d498ba950a 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/codecs/idversion/VersionBlockTreeTermsWriter.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/codecs/idversion/VersionBlockTreeTermsWriter.java
@@ -143,15 +143,14 @@ public final class VersionBlockTreeTermsWriter extends FieldsConsumer {
   final PostingsWriterBase postingsWriter;
   final FieldInfos fieldInfos;
 
-  private static class FieldMetaData {
-    public final FieldInfo fieldInfo;
-    public final Pair<BytesRef, Long> rootCode;
-    public final long numTerms;
-    public final long indexStartFP;
-    public final BytesRef minTerm;
-    public final BytesRef maxTerm;
-
-    public FieldMetaData(
+  private record FieldMetaData(
+      FieldInfo fieldInfo,
+      Pair<BytesRef, Long> rootCode,
+      long numTerms,
+      long indexStartFP,
+      BytesRef minTerm,
+      BytesRef maxTerm) {
+    private FieldMetaData(
         FieldInfo fieldInfo,
         Pair<BytesRef, Long> rootCode,
         long numTerms,
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/document/FloatPointNearestNeighbor.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/document/FloatPointNearestNeighbor.java
index bb18ecc1bcb..0bd424d93ce 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/document/FloatPointNearestNeighbor.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/document/FloatPointNearestNeighbor.java
@@ -40,15 +40,12 @@ import org.apache.lucene.util.Bits;
  */
 public class FloatPointNearestNeighbor {
 
-  static class Cell implements Comparable<Cell> {
-    final int readerIndex;
-    final byte[] minPacked;
-    final byte[] maxPacked;
-    final PointTree index;
-
-    /** The closest possible distance^2 of all points in this cell */
-    final double distanceSquared;
-
+  /**
+   * @param distanceSquared The closest possible distance^2 of all points in this cell
+   */
+  record Cell(
+      PointTree index, int readerIndex, byte[] minPacked, byte[] maxPacked, double distanceSquared)
+      implements Comparable<Cell> {
     Cell(
         PointTree index,
         int readerIndex,
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
index 35b9e8dc78d..417119fa9c8 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/CombinedFieldQuery.java
@@ -147,28 +147,7 @@ public final class CombinedFieldQuery extends Query implements Accountable {
     }
   }
 
-  static class FieldAndWeight {
-    final String field;
-    final float weight;
-
-    FieldAndWeight(String field, float weight) {
-      this.field = field;
-      this.weight = weight;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-      if (this == o) return true;
-      if (o == null || getClass() != o.getClass()) return false;
-      FieldAndWeight that = (FieldAndWeight) o;
-      return Float.compare(that.weight, weight) == 0 && Objects.equals(field, that.field);
-    }
-
-    @Override
-    public int hashCode() {
-      return Objects.hash(field, weight);
-    }
-  }
+  record FieldAndWeight(String field, float weight) {}
 
   // sorted map for fields.
   private final TreeMap<String, FieldAndWeight> fieldAndWeights;
diff --git a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiNormsLeafSimScorer.java b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiNormsLeafSimScorer.java
index ebc98df31af..1454e1cdaaa 100644
--- a/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiNormsLeafSimScorer.java
+++ b/lucene/sandbox/src/java/org/apache/lucene/sandbox/search/MultiNormsLeafSimScorer.java
@@ -65,15 +65,15 @@ final class MultiNormsLeafSimScorer {
       final List<Float> weightList = new ArrayList<>();
       final Set<String> duplicateCheckingSet = new HashSet<>();
       for (FieldAndWeight field : normFields) {
-        assert duplicateCheckingSet.add(field.field)
+        assert duplicateCheckingSet.add(field.field())
             : "There is a duplicated field ["
-                + field.field
+                + field.field()
                 + "] used to construct MultiNormsLeafSimScorer";
 
-        NumericDocValues norms = reader.getNormValues(field.field);
+        NumericDocValues norms = reader.getNormValues(field.field());
         if (norms != null) {
           normsList.add(norms);
-          weightList.add(field.weight);
+          weightList.add(field.weight());
         }
       }
 
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
index 29bb0889577..6a3b0ce6bc5 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoPolygonFactory.java
@@ -1717,20 +1717,16 @@ public class GeoPolygonFactory {
     return index;
   }
 
-  /** Class representing a single (unused) edge. */
-  private static class Edge {
-    /** Plane */
-    public final SidedPlane plane;
-
-    /** Start point */
-    public final GeoPoint startPoint;
-
-    /** End point */
-    public final GeoPoint endPoint;
-
-    /** Internal edge flag */
-    public final boolean isInternal;
-
+  /**
+   * Class representing a single (unused) edge.
+   *
+   * @param plane Plane
+   * @param startPoint Start point
+   * @param endPoint End point
+   * @param isInternal Internal edge flag
+   */
+  private record Edge(
+      GeoPoint startPoint, GeoPoint endPoint, SidedPlane plane, boolean isInternal) {
     /**
      * Constructor.
      *
@@ -1739,16 +1735,7 @@ public class GeoPolygonFactory {
      * @param plane the edge plane
      * @param isInternal true if internal edge
      */
-    public Edge(
-        final GeoPoint startPoint,
-        final GeoPoint endPoint,
-        final SidedPlane plane,
-        final boolean isInternal) {
-      this.startPoint = startPoint;
-      this.endPoint = endPoint;
-      this.plane = plane;
-      this.isInternal = isInternal;
-    }
+    private Edge {}
 
     @Override
     public int hashCode() {
diff --git a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
index 7c3de452e24..60bb7cd0c20 100755
--- a/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
+++ b/lucene/spatial3d/src/java/org/apache/lucene/spatial3d/geom/GeoStandardPath.java
@@ -430,14 +430,7 @@ class GeoStandardPath extends GeoBasePath {
         + "}}";
   }
 
-  private static class DistancePair {
-    public final double pathCenterDistance;
-    public final double distanceAlongPath;
-
-    public DistancePair(final double pathCenterDistance, final double distanceAlongPath) {
-      this.pathCenterDistance = pathCenterDistance;
-      this.distanceAlongPath = distanceAlongPath;
-    }
+  private record DistancePair(double pathCenterDistance, double distanceAlongPath) {
 
     @Override
     public String toString() {
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/spell/CombineSuggestion.java b/lucene/suggest/src/java/org/apache/lucene/search/spell/CombineSuggestion.java
index 72cefcf5b73..8d96cfda6db 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/spell/CombineSuggestion.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/spell/CombineSuggestion.java
@@ -16,20 +16,11 @@
  */
 package org.apache.lucene.search.spell;
 
-/** A suggestion generated by combining one or more original query terms */
-public class CombineSuggestion {
-  /** The indexes from the passed-in array of terms used to make this word combination */
-  public final int[] originalTermIndexes;
-
-  /** The word combination suggestion */
-  public final SuggestWord suggestion;
-
-  /**
-   * Creates a new CombineSuggestion from a <code>suggestion</code> and an array of term ids
-   * (referencing the indexes to the original terms that form this combined suggestion)
-   */
-  public CombineSuggestion(SuggestWord suggestion, int[] originalTermIndexes) {
-    this.suggestion = suggestion;
-    this.originalTermIndexes = originalTermIndexes;
-  }
-}
+/**
+ * A suggestion generated by combining one or more original query terms
+ *
+ * @param originalTermIndexes The indexes from the passed-in array of terms used to make this word
+ *     combination
+ * @param suggestion The word combination suggestion
+ */
+public record CombineSuggestion(SuggestWord suggestion, int[] originalTermIndexes) {}
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/spell/WordBreakSpellChecker.java b/lucene/suggest/src/java/org/apache/lucene/search/spell/WordBreakSpellChecker.java
index b3a84e9aaf8..58d68a66bd8 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/spell/WordBreakSpellChecker.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/spell/WordBreakSpellChecker.java
@@ -130,7 +130,7 @@ public class WordBreakSpellChecker {
    * returned {@link CombineSuggestion} contains both a {@link SuggestWord} and also an array
    * detailing which passed-in terms were involved in creating this combination. The scores returned
    * are equal to the number of word combinations needed, also one less than the length of the array
-   * {@link CombineSuggestion#originalTermIndexes}. Generally, a suggestion with a lower score is
+   * {@link CombineSuggestion#originalTermIndexes()}. Generally, a suggestion with a lower score is
    * preferred over a higher score.
    *
    * <p>To prevent two adjacent terms from being combined (for instance, if one is mandatory and the
@@ -491,8 +491,8 @@ public class WordBreakSpellChecker {
       if (o1.numCombinations != o2.numCombinations) {
         return o2.numCombinations - o1.numCombinations;
       }
-      if (o1.combineSuggestion.suggestion.freq != o2.combineSuggestion.suggestion.freq) {
-        return o1.combineSuggestion.suggestion.freq - o2.combineSuggestion.suggestion.freq;
+      if (o1.combineSuggestion.suggestion().freq != o2.combineSuggestion.suggestion().freq) {
+        return o1.combineSuggestion.suggestion().freq - o2.combineSuggestion.suggestion().freq;
       }
       return 0;
     }
@@ -516,13 +516,6 @@ public class WordBreakSpellChecker {
     }
   }
 
-  private static class CombineSuggestionWrapper {
-    final CombineSuggestion combineSuggestion;
-    final int numCombinations;
-
-    CombineSuggestionWrapper(CombineSuggestion combineSuggestion, int numCombinations) {
-      this.combineSuggestion = combineSuggestion;
-      this.numCombinations = numCombinations;
-    }
-  }
+  private record CombineSuggestionWrapper(
+      CombineSuggestion combineSuggestion, int numCombinations) {}
 }
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingSuggester.java
index a995b6725e9..b55634e9b49 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingSuggester.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/AnalyzingSuggester.java
@@ -717,7 +717,7 @@ public class AnalyzingSuggester extends Lookup {
 
         int count = 0;
         for (FSTUtil.Path<Pair<Long, BytesRef>> path : prefixPaths) {
-          if (fst.findTargetArc(END_BYTE, path.fstNode, scratchArc, bytesReader) != null) {
+          if (fst.findTargetArc(END_BYTE, path.fstNode(), scratchArc, bytesReader) != null) {
             // This node has END_BYTE arc leaving, meaning it's an
             // "exact" match:
             count++;
@@ -740,11 +740,14 @@ public class AnalyzingSuggester extends Lookup {
         // pruned our exact match from one of these nodes
         // ...:
         for (FSTUtil.Path<Pair<Long, BytesRef>> path : prefixPaths) {
-          if (fst.findTargetArc(END_BYTE, path.fstNode, scratchArc, bytesReader) != null) {
+          if (fst.findTargetArc(END_BYTE, path.fstNode(), scratchArc, bytesReader) != null) {
             // This node has END_BYTE arc leaving, meaning it's an
             // "exact" match:
             searcher.addStartPaths(
-                scratchArc, fst.outputs.add(path.output, scratchArc.output()), false, path.input);
+                scratchArc,
+                fst.outputs.add(path.output(), scratchArc.output()),
+                false,
+                path.input());
           }
         }
 
@@ -764,9 +767,9 @@ public class AnalyzingSuggester extends Lookup {
         // nodes we have and the
         // maxSurfaceFormsPerAnalyzedForm:
         for (Result<Pair<Long, BytesRef>> completion : completions) {
-          BytesRef output2 = completion.output.output2;
+          BytesRef output2 = completion.output().output2;
           if (sameSurfaceForm(utf8Key, output2)) {
-            results.add(getLookupResult(completion.output.output1, output2, spare));
+            results.add(getLookupResult(completion.output().output1, output2, spare));
             break;
           }
         }
@@ -814,7 +817,7 @@ public class AnalyzingSuggester extends Lookup {
       prefixPaths = getFullPrefixPaths(prefixPaths, lookupAutomaton, fst);
 
       for (FSTUtil.Path<Pair<Long, BytesRef>> path : prefixPaths) {
-        searcher.addStartPaths(path.fstNode, path.output, true, path.input);
+        searcher.addStartPaths(path.fstNode(), path.output(), true, path.input());
       }
 
       TopResults<Pair<Long, BytesRef>> completions = searcher.search();
@@ -823,7 +826,7 @@ public class AnalyzingSuggester extends Lookup {
       for (Result<Pair<Long, BytesRef>> completion : completions) {
 
         LookupResult result =
-            getLookupResult(completion.output.output1, completion.output.output2, spare);
+            getLookupResult(completion.output().output1, completion.output().output2, spare);
 
         // TODO: for fuzzy case would be nice to return
         // how many edits were required
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FSTUtil.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FSTUtil.java
index 1c5a3bf23db..4ff6d3451dd 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FSTUtil.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FSTUtil.java
@@ -35,29 +35,15 @@ public class FSTUtil {
 
   private FSTUtil() {}
 
-  /** Holds a pair (automaton, fst) of states and accumulated output in the intersected machine. */
-  public static final class Path<T> {
-
-    /** Node in the automaton where path ends: */
-    public final int state;
-
-    /** Node in the FST where path ends: */
-    public final FST.Arc<T> fstNode;
-
-    /** Output of the path so far: */
-    public final T output;
-
-    /** Input of the path so far: */
-    public final IntsRefBuilder input;
-
-    /** Sole constructor. */
-    public Path(int state, FST.Arc<T> fstNode, T output, IntsRefBuilder input) {
-      this.state = state;
-      this.fstNode = fstNode;
-      this.output = output;
-      this.input = input;
-    }
-  }
+  /**
+   * Holds a pair (automaton, fst) of states and accumulated output in the intersected machine.
+   *
+   * @param state Node in the automaton where path ends:
+   * @param fstNode Node in the FST where path ends:
+   * @param output Output of the path so far:
+   * @param input Input of the path so far:
+   */
+  public record Path<T>(int state, FST.Arc<T> fstNode, T output, IntsRefBuilder input) {}
 
   /**
    * Enumerates all minimal prefix paths in the automaton that also intersect the FST, accumulating
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FreeTextSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FreeTextSuggester.java
index 87346e9482e..f7555c3c419 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FreeTextSuggester.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/analyzing/FreeTextSuggester.java
@@ -666,7 +666,7 @@ public class FreeTextSuggester extends Lookup {
         for (Result<Long> completion : completions) {
           token.setLength(prefixLength);
           // append suffix
-          Util.toBytesRef(completion.input, suffix);
+          Util.toBytesRef(completion.input(), suffix);
           token.append(suffix);
 
           // System.out.println("    completion " + token.utf8ToString());
@@ -693,7 +693,7 @@ public class FreeTextSuggester extends Lookup {
                   (long)
                       (Long.MAX_VALUE
                           * backoff
-                          * ((double) decodeWeight(completion.output))
+                          * ((double) decodeWeight(completion.output()))
                           / contextCount));
           results.add(result);
           assert results.size() == seen.size();
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionFieldsConsumer.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionFieldsConsumer.java
index 8c6a0856f05..73518308b36 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionFieldsConsumer.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/CompletionFieldsConsumer.java
@@ -163,19 +163,7 @@ final class CompletionFieldsConsumer extends FieldsConsumer {
     }
   }
 
-  private static class CompletionMetaData {
-    private final long filePointer;
-    private final long minWeight;
-    private final long maxWeight;
-    private final byte type;
-
-    private CompletionMetaData(long filePointer, long minWeight, long maxWeight, byte type) {
-      this.filePointer = filePointer;
-      this.minWeight = minWeight;
-      this.maxWeight = maxWeight;
-      this.type = type;
-    }
-  }
+  private record CompletionMetaData(long filePointer, long minWeight, long maxWeight, byte type) {}
 
   // builds an FST based on the terms written
   private static class CompletionTermWriter {
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java
index c727b1e621c..bbcfc7feb43 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/ContextQuery.java
@@ -249,23 +249,14 @@ public class ContextQuery extends CompletionQuery implements Accountable {
     }
   }
 
-  /** Holder for context value meta data */
-  private static class ContextMetaData {
-
-    /** Boost associated with a context value */
-    private final float boost;
-
-    /**
-     * flag to indicate whether the context value should be treated as an exact value or a context
-     * prefix
-     */
-    private final boolean exact;
-
-    private ContextMetaData(float boost, boolean exact) {
-      this.boost = boost;
-      this.exact = exact;
-    }
-  }
+  /**
+   * Holder for context value meta data
+   *
+   * @param boost Boost associated with a context value
+   * @param exact flag to indicate whether the context value should be treated as an exact value or
+   *     a context prefix
+   */
+  private record ContextMetaData(float boost, boolean exact) {}
 
   private static class ContextCompletionWeight extends CompletionWeight {
 
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggester.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggester.java
index a56365fed9d..df803a7ca1b 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggester.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggester.java
@@ -226,8 +226,8 @@ public final class NRTSuggester implements Accountable {
         };
 
     for (FSTUtil.Path<Pair<Long, BytesRef>> path : prefixPaths) {
-      scorer.weight.setNextMatch(path.input.get());
-      BytesRef output = path.output.output2;
+      scorer.weight.setNextMatch(path.input().get());
+      BytesRef output = path.output().output2;
       int payload = -1;
       if (collector.doSkipDuplicates()) {
         for (int j = 0; j < output.length; j++) {
@@ -241,10 +241,10 @@ public final class NRTSuggester implements Accountable {
       }
 
       searcher.addStartPaths(
-          path.fstNode,
-          path.output,
+          path.fstNode(),
+          path.output(),
           false,
-          path.input,
+          path.input(),
           scorer.weight.boost(),
           scorer.weight.context(),
           payload);
@@ -261,13 +261,8 @@ public final class NRTSuggester implements Accountable {
    * Compares partial completion paths using {@link CompletionScorer#score(float, float)}, breaks
    * ties comparing path inputs
    */
-  private static class ScoringPathComparator
+  private record ScoringPathComparator(CompletionScorer scorer)
       implements Comparator<Util.FSTPath<Pair<Long, BytesRef>>> {
-    private final CompletionScorer scorer;
-
-    public ScoringPathComparator(CompletionScorer scorer) {
-      this.scorer = scorer;
-    }
 
     @Override
     public int compare(
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggesterBuilder.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggesterBuilder.java
index 02d9f84d3d4..7aec1568ad7 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggesterBuilder.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/document/NRTSuggesterBuilder.java
@@ -136,14 +136,7 @@ final class NRTSuggesterBuilder {
     return (int) Math.min(maxArcs, 255);
   }
 
-  private static final class Entry implements Comparable<Entry> {
-    final BytesRef payload;
-    final long weight;
-
-    public Entry(BytesRef payload, long weight) {
-      this.payload = payload;
-      this.weight = weight;
-    }
+  private record Entry(BytesRef payload, long weight) implements Comparable<Entry> {
 
     @Override
     public int compareTo(Entry o) {
diff --git a/lucene/suggest/src/java/org/apache/lucene/search/suggest/fst/WFSTCompletionLookup.java b/lucene/suggest/src/java/org/apache/lucene/search/suggest/fst/WFSTCompletionLookup.java
index a3c0fdd137f..e0f0727478c 100644
--- a/lucene/suggest/src/java/org/apache/lucene/search/suggest/fst/WFSTCompletionLookup.java
+++ b/lucene/suggest/src/java/org/apache/lucene/search/suggest/fst/WFSTCompletionLookup.java
@@ -204,10 +204,10 @@ public class WFSTCompletionLookup extends Lookup {
     for (Result<Long> completion : completions) {
       scratch.setLength(prefixLength);
       // append suffix
-      Util.toBytesRef(completion.input, suffix);
+      Util.toBytesRef(completion.input(), suffix);
       scratch.append(suffix);
       spare.copyUTF8Bytes(scratch.get());
-      results.add(new LookupResult(spare.toString(), decodeWeight(completion.output)));
+      results.add(new LookupResult(spare.toString(), decodeWeight(completion.output())));
     }
     return results;
   }
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/spell/TestWordBreakSpellChecker.java b/lucene/suggest/src/test/org/apache/lucene/search/spell/TestWordBreakSpellChecker.java
index 38121ced691..12a1a5782df 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/spell/TestWordBreakSpellChecker.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/spell/TestWordBreakSpellChecker.java
@@ -183,17 +183,17 @@ public class TestWordBreakSpellChecker extends LuceneTestCase {
       assertSuggestionEquals(cs[2], "yeight", 1.0f, 4, 5);
 
       for (int i = 3; i < 5; i++) {
-        assertEquals(3, cs[i].originalTermIndexes.length);
-        assertEquals(2, cs[i].suggestion.score, 0);
+        assertEquals(3, cs[i].originalTermIndexes().length);
+        assertEquals(2, cs[i].suggestion().score, 0);
         assertTrue(
-            (cs[i].originalTermIndexes[0] == 1
-                    && cs[i].originalTermIndexes[1] == 2
-                    && cs[i].originalTermIndexes[2] == 3
-                    && cs[i].suggestion.string.equals("hundredeight"))
-                || (cs[i].originalTermIndexes[0] == 3
-                    && cs[i].originalTermIndexes[1] == 4
-                    && cs[i].originalTermIndexes[2] == 5
-                    && cs[i].suggestion.string.equals("eightyeight")));
+            (cs[i].originalTermIndexes()[0] == 1
+                    && cs[i].originalTermIndexes()[1] == 2
+                    && cs[i].originalTermIndexes()[2] == 3
+                    && cs[i].suggestion().string.equals("hundredeight"))
+                || (cs[i].originalTermIndexes()[0] == 3
+                    && cs[i].originalTermIndexes()[1] == 4
+                    && cs[i].originalTermIndexes()[2] == 5
+                    && cs[i].suggestion().string.equals("eightyeight")));
       }
 
       cs = wbsp.suggestWordCombinations(terms, 5, ir, SuggestMode.SUGGEST_WHEN_NOT_IN_INDEX);
@@ -428,8 +428,8 @@ public class TestWordBreakSpellChecker extends LuceneTestCase {
             wbsp.suggestWordCombinations(terms, originals.size(), ir, SuggestMode.SUGGEST_ALWAYS);
         boolean failed = true;
         for (CombineSuggestion cs1 : cs) {
-          assertEquals(2, cs1.originalTermIndexes.length);
-          if (cs1.suggestion.string.equals(left + right)) {
+          assertEquals(2, cs1.originalTermIndexes().length);
+          if (cs1.suggestion().string.equals(left + right)) {
             failed = false;
           }
         }
@@ -448,9 +448,9 @@ public class TestWordBreakSpellChecker extends LuceneTestCase {
 
   private static void assertSuggestionEquals(
       CombineSuggestion cs, String word, float score, int... termIndexes) {
-    assertEquals(word, cs.suggestion.string);
-    assertEquals(score, cs.suggestion.score, 0);
-    assertArrayEquals(termIndexes, cs.originalTermIndexes);
+    assertEquals(word, cs.suggestion().string);
+    assertEquals(score, cs.suggestion().score, 0);
+    assertArrayEquals(termIndexes, cs.originalTermIndexes());
   }
 
   private static void assertSuggestionEquals(SuggestWord sw, String word, float score) {
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/Average.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/Average.java
index 2c2c5334322..737449cfd6b 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/Average.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/Average.java
@@ -19,19 +19,15 @@ package org.apache.lucene.search.suggest;
 import java.util.List;
 import java.util.Locale;
 
-/** Average with standard deviation. */
-final class Average {
-  /** Average (in milliseconds). */
-  public final double avg;
-
-  /** Standard deviation (in milliseconds). */
-  public final double stddev;
-
+/**
+ * Average with standard deviation.
+ *
+ * @param avg Average (in milliseconds).
+ * @param stddev Standard deviation (in milliseconds).
+ */
+record Average(double avg, double stddev) {
   /** */
-  Average(double avg, double stddev) {
-    this.avg = avg;
-    this.stddev = stddev;
-  }
+  Average {}
 
   @Override
   public String toString() {
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/SuggestRebuildTestUtil.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/SuggestRebuildTestUtil.java
index afad8f6e387..bde129463ab 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/SuggestRebuildTestUtil.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/SuggestRebuildTestUtil.java
@@ -108,19 +108,13 @@ public final class SuggestRebuildTestUtil {
    * An InputArrayIterator wrapper whose {@link InputIterator#next} method releases on a Semaphore,
    * and then acquires from a differnet Semaphore.
    */
-  private static final class DelayedInputIterator implements InputIterator {
-    final Semaphore releaseOnNext;
-    final Semaphore acquireOnNext;
-    final InputIterator inner;
-
-    public DelayedInputIterator(
-        final Semaphore releaseOnNext, final Semaphore acquireOnNext, final InputIterator inner) {
+  private record DelayedInputIterator(
+      Semaphore releaseOnNext, Semaphore acquireOnNext, InputIterator inner)
+      implements InputIterator {
+    private DelayedInputIterator {
       assert null != releaseOnNext;
       assert null != acquireOnNext;
       assert null != inner;
-      this.releaseOnNext = releaseOnNext;
-      this.acquireOnNext = acquireOnNext;
-      this.inner = inner;
     }
 
     @Override
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/TestLookupBenchmark.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/TestLookupBenchmark.java
index 80e6add070d..55c4f8c8dc0 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/TestLookupBenchmark.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/TestLookupBenchmark.java
@@ -235,7 +235,7 @@ public class TestLookupBenchmark extends LuceneTestCase {
           lookup.getClass().getSimpleName(),
           input.size(),
           result.average,
-          input.size() / result.average.avg);
+          input.size() / result.average.avg());
     }
   }
 
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingInfixSuggester.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingInfixSuggester.java
index 6983c7eba59..3ea17ee146b 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingInfixSuggester.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingInfixSuggester.java
@@ -227,19 +227,15 @@ public class TestAnalyzingInfixSuggester extends LuceneTestCase {
     a.close();
   }
 
-  /** Used to return highlighted result; see {@link LookupResult#highlightKey} */
-  private static final class LookupHighlightFragment {
-    /** Portion of text for this fragment. */
-    public final String text;
-
-    /** True if this text matched a part of the user's query. */
-    public final boolean isHit;
-
+  /**
+   * Used to return highlighted result; see {@link LookupResult#highlightKey}
+   *
+   * @param text Portion of text for this fragment.
+   * @param isHit True if this text matched a part of the user's query.
+   */
+  private record LookupHighlightFragment(String text, boolean isHit) {
     /** Sole constructor. */
-    public LookupHighlightFragment(String text, boolean isHit) {
-      this.text = text;
-      this.isHit = isHit;
-    }
+    private LookupHighlightFragment {}
 
     @Override
     public String toString() {
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java
index 75003c9293a..e61935d9395 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestAnalyzingSuggester.java
@@ -616,18 +616,8 @@ public class TestAnalyzingSuggester extends LuceneTestCase {
   }
 
   // Holds surface form separately:
-  private static class TermFreq2 implements Comparable<TermFreq2> {
-    public final String surfaceForm;
-    public final String analyzedForm;
-    public final long weight;
-    public final BytesRef payload;
-
-    public TermFreq2(String surfaceForm, String analyzedForm, long weight, BytesRef payload) {
-      this.surfaceForm = surfaceForm;
-      this.analyzedForm = analyzedForm;
-      this.weight = weight;
-      this.payload = payload;
-    }
+  private record TermFreq2(String surfaceForm, String analyzedForm, long weight, BytesRef payload)
+      implements Comparable<TermFreq2> {
 
     @Override
     public int compareTo(TermFreq2 other) {
diff --git a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestFuzzySuggester.java b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestFuzzySuggester.java
index 0fc33673c82..68807710129 100644
--- a/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestFuzzySuggester.java
+++ b/lucene/suggest/src/test/org/apache/lucene/search/suggest/analyzing/TestFuzzySuggester.java
@@ -503,16 +503,8 @@ public class TestFuzzySuggester extends LuceneTestCase {
   }
 
   // Holds surface form separately:
-  private static class TermFreqPayload2 implements Comparable<TermFreqPayload2> {
-    public final String surfaceForm;
-    public final String analyzedForm;
-    public final long weight;
-
-    public TermFreqPayload2(String surfaceForm, String analyzedForm, long weight) {
-      this.surfaceForm = surfaceForm;
-      this.analyzedForm = analyzedForm;
-      this.weight = weight;
-    }
+  private record TermFreqPayload2(String surfaceForm, String analyzedForm, long weight)
+      implements Comparable<TermFreqPayload2> {
 
     @Override
     public int compareTo(TermFreqPayload2 other) {
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/ramonly/RAMOnlyPostingsFormat.java b/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/ramonly/RAMOnlyPostingsFormat.java
index abc0299db2d..be547fa29ef 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/ramonly/RAMOnlyPostingsFormat.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/codecs/ramonly/RAMOnlyPostingsFormat.java
@@ -327,9 +327,9 @@ public final class RAMOnlyPostingsFormat extends PostingsFormat {
     }
 
     public void finishTerm(BytesRef text, TermStats stats) {
-      assert stats.docFreq > 0;
-      assert stats.docFreq == current.docs.size();
-      current.totalTermFreq = stats.totalTermFreq;
+      assert stats.docFreq() > 0;
+      assert stats.docFreq() == current.docs.size();
+      current.totalTermFreq = stats.totalTermFreq();
       field.termToDocs.put(current.term, current);
     }
 
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/search/ShardSearchingTestBase.java b/lucene/test-framework/src/java/org/apache/lucene/tests/search/ShardSearchingTestBase.java
index b72c7f3f8f4..7a3785d2b59 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/search/ShardSearchingTestBase.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/search/ShardSearchingTestBase.java
@@ -62,21 +62,7 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase {
     }
   }
 
-  private static class FieldAndShardVersion {
-    private final long version;
-    private final int nodeID;
-    private final String field;
-
-    public FieldAndShardVersion(int nodeID, long version, String field) {
-      this.nodeID = nodeID;
-      this.version = version;
-      this.field = field;
-    }
-
-    @Override
-    public int hashCode() {
-      return (int) (version * nodeID + field.hashCode());
-    }
+  private record FieldAndShardVersion(int nodeID, long version, String field) {
 
     @Override
     public boolean equals(Object _other) {
@@ -101,21 +87,7 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase {
     }
   }
 
-  private static class TermAndShardVersion {
-    private final long version;
-    private final int nodeID;
-    private final Term term;
-
-    public TermAndShardVersion(int nodeID, long version, Term term) {
-      this.nodeID = nodeID;
-      this.version = version;
-      this.term = term;
-    }
-
-    @Override
-    public int hashCode() {
-      return (int) (version * nodeID + term.hashCode());
-    }
+  private record TermAndShardVersion(int nodeID, long version, Term term) {
 
     @Override
     public boolean equals(Object _other) {
@@ -665,13 +637,5 @@ public abstract class ShardSearchingTestBase extends LuceneTestCase {
   }
 
   /** An IndexSearcher and associated version (lease) */
-  protected static class SearcherAndVersion {
-    public final IndexSearcher searcher;
-    public final long version;
-
-    public SearcherAndVersion(IndexSearcher searcher, long version) {
-      this.searcher = searcher;
-      this.version = version;
-    }
-  }
+  protected record SearcherAndVersion(IndexSearcher searcher, long version) {}
 }
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/util/RamUsageTester.java b/lucene/test-framework/src/java/org/apache/lucene/tests/util/RamUsageTester.java
index 7e793f2c6c1..e50f865d944 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/util/RamUsageTester.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/util/RamUsageTester.java
@@ -307,15 +307,7 @@ public final class RamUsageTester {
           });
 
   /** Cached information about a given class. */
-  private static final class ClassCache {
-    public final long alignedShallowInstanceSize;
-    public final Field[] referenceFields;
-
-    public ClassCache(long alignedShallowInstanceSize, Field[] referenceFields) {
-      this.alignedShallowInstanceSize = alignedShallowInstanceSize;
-      this.referenceFields = referenceFields;
-    }
-  }
+  private record ClassCache(long alignedShallowInstanceSize, Field[] referenceFields) {}
 
   /** Create a cached information about shallow size and reference fields for a given class. */
   @SuppressForbidden(reason = "We need to access private fields of measured objects.")
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/util/automaton/AutomatonTestUtil.java b/lucene/test-framework/src/java/org/apache/lucene/tests/util/automaton/AutomatonTestUtil.java
index df2731f3cb4..5a308f37133 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/util/automaton/AutomatonTestUtil.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/util/automaton/AutomatonTestUtil.java
@@ -156,15 +156,7 @@ public class AutomatonTestUtil {
     private final Automaton a;
     private final Transition[][] transitions;
 
-    private static class ArrivingTransition {
-      final int from;
-      final Transition t;
-
-      public ArrivingTransition(int from, Transition t) {
-        this.from = from;
-        this.t = t;
-      }
-    }
+    private record ArrivingTransition(int from, Transition t) {}
 
     public RandomAcceptedStrings(Automaton a) {
       this.a = a;
diff --git a/lucene/test-framework/src/java/org/apache/lucene/tests/util/fst/FSTTester.java b/lucene/test-framework/src/java/org/apache/lucene/tests/util/fst/FSTTester.java
index 521e8cbe645..cbd2ac3f762 100644
--- a/lucene/test-framework/src/java/org/apache/lucene/tests/util/fst/FSTTester.java
+++ b/lucene/test-framework/src/java/org/apache/lucene/tests/util/fst/FSTTester.java
@@ -164,14 +164,7 @@ public class FSTTester<T> {
   }
 
   /** Holds one input/output pair. */
-  public static class InputOutput<T> implements Comparable<InputOutput<T>> {
-    public final IntsRef input;
-    public final T output;
-
-    public InputOutput(IntsRef input, T output) {
-      this.input = input;
-      this.output = output;
-    }
+  public record InputOutput<T>(IntsRef input, T output) implements Comparable<InputOutput<T>> {
 
     @Override
     public int compareTo(InputOutput<T> other) {