Merge changes I50d52d3f,I37779385,Id54b9856,I8812982c

* changes:
  Move getPersonParts to SchemaUtil and add tests
  Extract method from ChangeSchemas to build schema version map
  Extract interfaces for Index and IndexCollection
  Move most Change-related index code to an index subpackage
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
index 386fe73..046008c 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/AbstractDaemonTest.java
@@ -61,7 +61,7 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MetaDataUpdate;
 import com.google.gerrit.server.git.ProjectConfig;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeNoteUtil;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ChangeControl;
diff --git a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
index dfd628c..74cea20 100644
--- a/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
+++ b/gerrit-acceptance-framework/src/test/java/com/google/gerrit/acceptance/GerritServer.java
@@ -26,7 +26,7 @@
 import com.google.gerrit.pgm.Init;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.AsyncReceiveCommits;
-import com.google.gerrit.server.index.ChangeSchemas;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.gerrit.server.ssh.NoSshModule;
 import com.google.gerrit.server.util.SocketUtil;
 import com.google.gerrit.server.util.SystemLog;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
index 1334bcb..93d7a51 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneChangeIndex.java
@@ -17,11 +17,11 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 import static com.google.common.collect.Iterables.getOnlyElement;
 import static com.google.gerrit.server.git.QueueProvider.QueueType.INTERACTIVE;
-import static com.google.gerrit.server.index.ChangeField.CHANGE;
-import static com.google.gerrit.server.index.ChangeField.LEGACY_ID;
-import static com.google.gerrit.server.index.ChangeField.PROJECT;
-import static com.google.gerrit.server.index.IndexRewriter.CLOSED_STATUSES;
-import static com.google.gerrit.server.index.IndexRewriter.OPEN_STATUSES;
+import static com.google.gerrit.server.index.change.ChangeField.CHANGE;
+import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID;
+import static com.google.gerrit.server.index.change.ChangeField.PROJECT;
+import static com.google.gerrit.server.index.change.IndexRewriter.CLOSED_STATUSES;
+import static com.google.gerrit.server.index.change.IndexRewriter.OPEN_STATUSES;
 import static java.util.concurrent.TimeUnit.MILLISECONDS;
 import static java.util.concurrent.TimeUnit.MINUTES;
 
@@ -41,23 +41,23 @@
 import com.google.gerrit.server.config.ConfigUtil;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.index.ChangeField;
-import com.google.gerrit.server.index.ChangeField.ChangeProtoField;
-import com.google.gerrit.server.index.ChangeField.PatchSetApprovalProtoField;
-import com.google.gerrit.server.index.ChangeField.PatchSetProtoField;
-import com.google.gerrit.server.index.ChangeIndex;
 import com.google.gerrit.server.index.FieldDef;
 import com.google.gerrit.server.index.FieldDef.FillArgs;
 import com.google.gerrit.server.index.FieldType;
 import com.google.gerrit.server.index.IndexExecutor;
-import com.google.gerrit.server.index.IndexRewriter;
+import com.google.gerrit.server.index.QueryOptions;
 import com.google.gerrit.server.index.Schema;
 import com.google.gerrit.server.index.Schema.Values;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeField.ChangeProtoField;
+import com.google.gerrit.server.index.change.ChangeField.PatchSetApprovalProtoField;
+import com.google.gerrit.server.index.change.ChangeField.PatchSetProtoField;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.IndexRewriter;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeDataSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 import com.google.gwtorm.protobuf.ProtobufCodec;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
index 5af7cc5..360053b 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneIndexModule.java
@@ -17,11 +17,11 @@
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.index.ChangeSchemas;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.IndexConfig;
 import com.google.gerrit.server.index.IndexModule;
 import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.Inject;
 import com.google.inject.Provides;
@@ -88,11 +88,11 @@
 
   @Singleton
   static class SingleVersionListener implements LifecycleListener {
-    private final IndexCollection indexes;
+    private final ChangeIndexCollection indexes;
     private final LuceneChangeIndex index;
 
     @Inject
-    SingleVersionListener(IndexCollection indexes,
+    SingleVersionListener(ChangeIndexCollection indexes,
         LuceneChangeIndex index) {
       this.indexes = indexes;
       this.index = index;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
index 95035fc..d15f933 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/LuceneVersionManager.java
@@ -22,9 +22,9 @@
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.index.ChangeSchemas;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.inject.Inject;
 import com.google.inject.ProvisionException;
@@ -92,7 +92,7 @@
 
   private final SitePaths sitePaths;
   private final LuceneChangeIndex.Factory indexFactory;
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final OnlineReindexer.Factory reindexerFactory;
   private final boolean onlineUpgrade;
   private OnlineReindexer reindexer;
@@ -102,7 +102,7 @@
       @GerritServerConfig Config cfg,
       SitePaths sitePaths,
       LuceneChangeIndex.Factory indexFactory,
-      IndexCollection indexes,
+      ChangeIndexCollection indexes,
       OnlineReindexer.Factory reindexerFactory) {
     this.sitePaths = sitePaths;
     this.indexFactory = indexFactory;
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/OnlineReindexer.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/OnlineReindexer.java
index 1dbc427..89aa57c 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/OnlineReindexer.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/OnlineReindexer.java
@@ -17,9 +17,10 @@
 import static com.google.common.base.Preconditions.checkNotNull;
 
 import com.google.common.collect.Lists;
-import com.google.gerrit.server.index.ChangeIndex;
-import com.google.gerrit.server.index.IndexCollection;
+import com.google.gerrit.server.index.Index;
 import com.google.gerrit.server.index.SiteIndexer;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -39,7 +40,7 @@
     OnlineReindexer create(int version);
   }
 
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final SiteIndexer batchIndexer;
   private final ProjectCache projectCache;
   private final int version;
@@ -48,7 +49,7 @@
 
   @Inject
   OnlineReindexer(
-      IndexCollection indexes,
+      ChangeIndexCollection indexes,
       SiteIndexer batchIndexer,
       ProjectCache projectCache,
       @Assisted int version) {
@@ -84,7 +85,7 @@
     return version;
   }
 
-  private static int version(ChangeIndex i) {
+  private static int version(Index<?, ?> i) {
     return i.getSchema().getVersion();
   }
 
diff --git a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
index 7f26d83..9897ded 100644
--- a/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
+++ b/gerrit-lucene/src/main/java/com/google/gerrit/lucene/QueryBuilder.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.lucene;
 
-import static com.google.gerrit.server.index.ChangeField.LEGACY_ID;
+import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID;
 import static org.apache.lucene.search.BooleanClause.Occur.MUST;
 import static org.apache.lucene.search.BooleanClause.Occur.MUST_NOT;
 import static org.apache.lucene.search.BooleanClause.Occur.SHOULD;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
index 91e7b87..2c8499a 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/RebuildNotedb.java
@@ -44,7 +44,7 @@
 import com.google.gerrit.server.git.SearchingChangeCacheImpl;
 import com.google.gerrit.server.git.WorkQueue;
 import com.google.gerrit.server.index.DummyIndexModule;
-import com.google.gerrit.server.index.ReindexAfterUpdate;
+import com.google.gerrit.server.index.change.ReindexAfterUpdate;
 import com.google.gerrit.server.notedb.ChangeRebuilder;
 import com.google.gerrit.server.notedb.NoteDbModule;
 import com.google.gerrit.server.notedb.NotesMigration;
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
index 9ce29f5..3020460 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/Reindex.java
@@ -28,12 +28,12 @@
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.ScanningChangeCacheImpl;
-import com.google.gerrit.server.index.ChangeIndex;
-import com.google.gerrit.server.index.ChangeSchemas;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.IndexModule;
 import com.google.gerrit.server.index.IndexModule.IndexType;
 import com.google.gerrit.server.index.SiteIndexer;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.inject.Injector;
@@ -100,7 +100,8 @@
     projectCache = sysInjector.getInstance(ProjectCache.class);
     repoManager = sysInjector.getInstance(GitRepositoryManager.class);
 
-    index = sysInjector.getInstance(IndexCollection.class).getSearchIndex();
+    index = sysInjector.getInstance(ChangeIndexCollection.class)
+        .getSearchIndex();
     int result = 0;
     try {
       index.markReady(false);
diff --git a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
index 425c39a..53bb349 100644
--- a/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
+++ b/gerrit-pgm/src/main/java/com/google/gerrit/pgm/init/InitIndex.java
@@ -21,8 +21,8 @@
 import com.google.gerrit.pgm.init.api.InitStep;
 import com.google.gerrit.pgm.init.api.Section;
 import com.google.gerrit.server.config.SitePaths;
-import com.google.gerrit.server.index.ChangeSchemas;
 import com.google.gerrit.server.index.IndexModule.IndexType;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
index f995760..5fda005 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/ConsistencyChecker.java
@@ -45,7 +45,7 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.UpdateException;
 import com.google.gerrit.server.git.validators.CommitValidators;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeUpdate;
 import com.google.gerrit.server.notedb.NotesMigration;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
index a0be718..0d282c5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Index.java
@@ -19,7 +19,7 @@
 import com.google.gerrit.extensions.restapi.RestModifyView;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.change.Index.Input;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
index 34bc00a..23d29de5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/change/Mergeable.java
@@ -28,7 +28,7 @@
 import com.google.gerrit.server.git.BranchOrderSection;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.MergeUtil;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
index dee43ac..81b3e0f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/config/GerritGlobalModule.java
@@ -102,7 +102,7 @@
 import com.google.gerrit.server.git.validators.UploadValidators;
 import com.google.gerrit.server.group.GroupInfoCacheFactory;
 import com.google.gerrit.server.group.GroupModule;
-import com.google.gerrit.server.index.ReindexAfterUpdate;
+import com.google.gerrit.server.index.change.ReindexAfterUpdate;
 import com.google.gerrit.server.mail.AddKeySender;
 import com.google.gerrit.server.mail.AddReviewerSender;
 import com.google.gerrit.server.mail.CreateChangeSender;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
index ca4ac04..1528751 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditModifier.java
@@ -34,7 +34,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.git.GitRepositoryManager;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.project.InvalidChangeOperationException;
 import com.google.inject.Inject;
 import com.google.inject.Provider;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
index 695b6bb..b8e6093 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/edit/ChangeEditUtil.java
@@ -36,7 +36,7 @@
 import com.google.gerrit.server.git.BatchUpdate;
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.UpdateException;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.NoSuchProjectException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
index 693fb92..7357965 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/BatchUpdate.java
@@ -36,7 +36,7 @@
 import com.google.gerrit.server.GerritPersonIdent;
 import com.google.gerrit.server.PatchLineCommentsUtil;
 import com.google.gerrit.server.extensions.events.GitReferenceUpdated;
-import com.google.gerrit.server.index.ChangeIndexer;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeDelete;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.notedb.ChangeUpdate;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
index ce220cf..9869aee 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/git/MergeSuperSet.java
@@ -27,7 +27,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.change.Submit;
 import com.google.gerrit.server.config.GerritServerConfig;
-import com.google.gerrit.server.index.ChangeField;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
 import com.google.gwtorm.server.OrmException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndexModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndexModule.java
index d14a2f7..b4188a7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndexModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndexModule.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.index;
 
+import com.google.gerrit.server.index.change.DummyChangeIndex;
 import com.google.inject.AbstractModule;
 
 public class DummyIndexModule extends AbstractModule {
@@ -22,6 +23,6 @@
   protected void configure() {
     install(new IndexModule(1));
     bind(IndexConfig.class).toInstance(IndexConfig.createDefault());
-    bind(ChangeIndex.class).toInstance(new DummyIndex());
+    bind(Index.class).toInstance(new DummyChangeIndex());
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
index cf3fd09..386092d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/FieldDef.java
@@ -36,7 +36,7 @@
 public abstract class FieldDef<I, T> {
   /** Definition of a single (non-repeatable) field. */
   public abstract static class Single<I, T> extends FieldDef<I, T> {
-    Single(String name, FieldType<T> type, boolean stored) {
+    protected Single(String name, FieldType<T> type, boolean stored) {
       super(name, type, stored);
     }
 
@@ -49,7 +49,7 @@
   /** Definition of a repeatable field. */
   public abstract static class Repeatable<I, T>
       extends FieldDef<I, Iterable<T>> {
-    Repeatable(String name, FieldType<T> type, boolean stored) {
+    protected Repeatable(String name, FieldType<T> type, boolean stored) {
       super(name, type, stored);
       Preconditions.checkArgument(type != FieldType.INTEGER_RANGE,
           "Range queries against repeated fields are unsupported");
@@ -63,8 +63,8 @@
 
   /** Arguments needed to fill in missing data in the input object. */
   public static class FillArgs {
-    final TrackingFooters trackingFooters;
-    final boolean allowsDrafts;
+    public final TrackingFooters trackingFooters;
+    public final boolean allowsDrafts;
 
     @Inject
     FillArgs(TrackingFooters trackingFooters,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndex.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/Index.java
similarity index 69%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndex.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/Index.java
index 258f1e9..533e57c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndex.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/Index.java
@@ -14,57 +14,54 @@
 
 package com.google.gerrit.server.index;
 
-import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.query.DataSource;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
-import com.google.gerrit.server.query.change.ChangeData;
-import com.google.gerrit.server.query.change.ChangeDataSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 
 import java.io.IOException;
 
 /**
- * Secondary index implementation for change documents.
+ * Secondary index implementation for arbitrary documents.
  * <p>
- * {@link ChangeData} objects are inserted into the index and are queried by
- * converting special {@link com.google.gerrit.server.query.Predicate} instances
- * into index-aware predicates that use the index search results as a source.
+ * Documents are inserted into the index and are queried by converting special
+ * {@link com.google.gerrit.server.query.Predicate} instances into index-aware
+ * predicates that use the index search results as a source.
  * <p>
  * Implementations must be thread-safe and should batch inserts/updates where
  * appropriate.
  */
-public interface ChangeIndex {
+public interface Index<K, V> {
   /** @return the schema version used by this index. */
-  Schema<ChangeData> getSchema();
+  Schema<V> getSchema();
 
   /** Close this index. */
   void close();
 
   /**
-   * Update a change document in the index.
+   * Update a document in the index.
    * <p>
    * Semantically equivalent to deleting the document and reinserting it with
    * new field values. A document that does not already exist is created. Results
    * may not be immediately visible to searchers, but should be visible within a
    * reasonable amount of time.
    *
-   * @param cd change document
+   * @param obj document object
    *
    * @throws IOException
    */
-  void replace(ChangeData cd) throws IOException;
+  void replace(V obj) throws IOException;
 
   /**
-   * Delete a change document from the index by id.
+   * Delete a document from the index by key.
    *
-   * @param id change id
+   * @param key document key
    *
    * @throws IOException
    */
-  void delete(Change.Id id) throws IOException;
+  void delete(K key) throws IOException;
 
   /**
-   * Delete all change documents from the index.
+   * Delete all documents from the index.
    *
    * @throws IOException
    */
@@ -84,13 +81,13 @@
    *     leaves.
    * @param opts query options not implied by the predicate, such as start and
    *     limit.
-   * @return a source of documents matching the predicate. Documents must be
-   *     returned in descending updated timestamp order.
+   * @return a source of documents matching the predicate, returned in a
+   *     defined order depending on the type of documents.
    *
    * @throws QueryParseException if the predicate could not be converted to an
    *     indexed data source.
    */
-  ChangeDataSource getSource(Predicate<ChangeData> p, QueryOptions opts)
+  DataSource<V> getSource(Predicate<V> p, QueryOptions opts)
       throws QueryParseException;
 
   /**
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
index 2380c76..669e253 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexCollection.java
@@ -18,7 +18,6 @@
 import com.google.common.collect.Lists;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.inject.Inject;
-import com.google.inject.Singleton;
 
 import java.util.Collection;
 import java.util.Collections;
@@ -26,10 +25,10 @@
 import java.util.concurrent.atomic.AtomicReference;
 
 /** Dynamic pointers to the index versions used for searching and writing. */
-@Singleton
-public class IndexCollection implements LifecycleListener {
-  private final CopyOnWriteArrayList<ChangeIndex> writeIndexes;
-  private final AtomicReference<ChangeIndex> searchIndex;
+public abstract class IndexCollection<K, V, I extends Index<K, V>>
+    implements LifecycleListener {
+  private final CopyOnWriteArrayList<I> writeIndexes;
+  private final AtomicReference<I> searchIndex;
 
   @Inject
   @VisibleForTesting
@@ -39,22 +38,22 @@
   }
 
   /** @return the current search index version. */
-  public ChangeIndex getSearchIndex() {
+  public I getSearchIndex() {
     return searchIndex.get();
   }
 
-  public void setSearchIndex(ChangeIndex index) {
-    ChangeIndex old = searchIndex.getAndSet(index);
+  public void setSearchIndex(I index) {
+    I old = searchIndex.getAndSet(index);
     if (old != null && old != index && !writeIndexes.contains(old)) {
       old.close();
     }
   }
 
-  public Collection<ChangeIndex> getWriteIndexes() {
+  public Collection<I> getWriteIndexes() {
     return Collections.unmodifiableCollection(writeIndexes);
   }
 
-  public synchronized ChangeIndex addWriteIndex(ChangeIndex index) {
+  public synchronized I addWriteIndex(I index) {
     int version = index.getSchema().getVersion();
     for (int i = 0; i < writeIndexes.size(); i++) {
       if (writeIndexes.get(i).getSchema().getVersion() == version) {
@@ -82,8 +81,8 @@
     }
   }
 
-  public ChangeIndex getWriteIndex(int version) {
-    for (ChangeIndex i : writeIndexes) {
+  public I getWriteIndex(int version) {
+    for (I i : writeIndexes) {
       if (i.getSchema().getVersion() == version) {
         return i;
       }
@@ -97,11 +96,11 @@
 
   @Override
   public void stop() {
-    ChangeIndex read = searchIndex.get();
+    I read = searchIndex.get();
     if (read != null) {
       read.close();
     }
-    for (ChangeIndex write : writeIndexes) {
+    for (I write : writeIndexes) {
       if (write != read) {
         write.close();
       }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
index 2c2019b..12eb347 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexConfig.java
@@ -24,7 +24,7 @@
  * Implementation-specific configuration for secondary indexes.
  * <p>
  * Contains configuration that is tied to a specific index implementation but is
- * otherwise global, i.e. not tied to a specific {@link ChangeIndex} and schema
+ * otherwise global, i.e. not tied to a specific {@link Index} and schema
  * version.
  */
 @AutoValue
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
index 2799144..b8ce160 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexModule.java
@@ -22,6 +22,9 @@
 import com.google.gerrit.lifecycle.LifecycleModule;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.gerrit.server.git.WorkQueue;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.ChangeIndexer;
+import com.google.gerrit.server.index.change.IndexRewriter;
 import com.google.inject.Injector;
 import com.google.inject.Key;
 import com.google.inject.Provides;
@@ -67,8 +70,7 @@
   @Override
   protected void configure() {
     bind(IndexRewriter.class);
-    bind(IndexCollection.class);
-    listener().to(IndexCollection.class);
+    listener().to(ChangeIndexCollection.class);
     factory(ChangeIndexer.Factory.class);
   }
 
@@ -77,7 +79,7 @@
   ChangeIndexer getChangeIndexer(
       @IndexExecutor(INTERACTIVE) ListeningExecutorService executor,
       ChangeIndexer.Factory factory,
-      IndexCollection indexes) {
+      ChangeIndexCollection indexes) {
     // Bind default indexer to interactive executor; callers who need a
     // different executor can use the factory directly.
     return factory.create(executor, indexes);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryOptions.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/QueryOptions.java
similarity index 70%
rename from gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryOptions.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/QueryOptions.java
index 686eb6d..a9f5442 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryOptions.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/QueryOptions.java
@@ -12,17 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.query.change;
+package com.google.gerrit.server.index;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.gerrit.server.index.ChangeField.CHANGE;
-import static com.google.gerrit.server.index.ChangeField.PROJECT;
 
 import com.google.auto.value.AutoValue;
 import com.google.common.collect.ImmutableSet;
-import com.google.gerrit.server.index.IndexConfig;
 
-import java.util.HashSet;
 import java.util.Set;
 
 @AutoValue
@@ -31,23 +27,10 @@
       Set<String> fields) {
     checkArgument(start >= 0, "start must be nonnegative: %s", start);
     checkArgument(limit > 0, "limit must be positive: %s", limit);
-
-    // Always include project since it is needed to load the change from notedb.
-    if (!fields.contains(CHANGE.getName())
-        && !fields.contains(PROJECT.getName())) {
-      fields = new HashSet<>(fields);
-      fields.add(PROJECT.getName());
-    }
-
     return new AutoValue_QueryOptions(config, start, limit,
         ImmutableSet.copyOf(fields));
   }
 
-  public static QueryOptions oneResult() {
-    return create(IndexConfig.createDefault(), 0, 1,
-        ImmutableSet.<String> of());
-  }
-
   public abstract IndexConfig config();
   public abstract int start();
   public abstract int limit();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
index a605461..a8ec51f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/Schema.java
@@ -16,7 +16,6 @@
 
 import static com.google.common.base.Preconditions.checkState;
 
-import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.MoreObjects;
 import com.google.common.base.Optional;
@@ -65,11 +64,10 @@
 
   private int version;
 
-  protected Schema(Iterable<FieldDef<T, ?>> fields) {
+  public Schema(Iterable<FieldDef<T, ?>> fields) {
     this(0, fields);
   }
 
-  @VisibleForTesting
   public Schema(int version, Iterable<FieldDef<T, ?>> fields) {
     this.version = version;
     ImmutableMap.Builder<String, FieldDef<T, ?>> b = ImmutableMap.builder();
@@ -190,7 +188,7 @@
         .toString();
   }
 
-  void setVersion(int version) {
+  public void setVersion(int version) {
     this.version = version;
   }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java
new file mode 100644
index 0000000..404357d
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/SchemaUtil.java
@@ -0,0 +1,96 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.index;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import com.google.common.base.CharMatcher;
+import com.google.common.base.Splitter;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
+
+import org.eclipse.jgit.lib.PersonIdent;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+public class SchemaUtil {
+  public static <V> ImmutableMap<Integer, Schema<V>> schemasFromClass(
+      Class<?> schemasClass, Class<V> valueClass) {
+    Map<Integer, Schema<V>> schemas = Maps.newTreeMap();
+    for (Field f : schemasClass.getDeclaredFields()) {
+      if (Modifier.isStatic(f.getModifiers())
+          && Modifier.isFinal(f.getModifiers())
+          && Schema.class.isAssignableFrom(f.getType())) {
+        ParameterizedType t = (ParameterizedType) f.getGenericType();
+        if (t.getActualTypeArguments()[0] == valueClass) {
+          try {
+            f.setAccessible(true);
+            @SuppressWarnings("unchecked")
+            Schema<V> schema = (Schema<V>) f.get(null);
+            checkArgument(f.getName().startsWith("V"));
+            schema.setVersion(Integer.parseInt(f.getName().substring(1)));
+            schemas.put(schema.getVersion(), schema);
+          } catch (IllegalAccessException e) {
+            throw new IllegalArgumentException(e);
+          }
+        } else {
+          throw new IllegalArgumentException(
+              "non-" + schemasClass.getSimpleName() + " schema: " + f);
+        }
+      }
+    }
+    if (schemas.isEmpty()) {
+      throw new ExceptionInInitializerError("no ChangeSchemas found");
+    }
+    return ImmutableMap.copyOf(schemas);
+  }
+
+  public static <V> Schema<V> schema(Collection<FieldDef<V, ?>> fields) {
+    return new Schema<>(ImmutableList.copyOf(fields));
+  }
+
+  @SafeVarargs
+  public static <V> Schema<V> schema(FieldDef<V, ?>... fields) {
+    return schema(ImmutableList.copyOf(fields));
+  }
+
+  public static Set<String> getPersonParts(PersonIdent person) {
+    if (person == null) {
+      return ImmutableSet.of();
+    }
+    HashSet<String> parts = Sets.newHashSet();
+    String email = person.getEmailAddress().toLowerCase();
+    parts.add(email);
+    parts.addAll(Arrays.asList(email.split("@")));
+    Splitter s = Splitter.on(CharMatcher.anyOf("@.- ")).omitEmptyStrings();
+    Iterables.addAll(parts, s.split(email));
+    Iterables.addAll(parts, s.split(person.getName().toLowerCase()));
+    return parts;
+  }
+
+  private SchemaUtil() {
+  }
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java
index a6cb12f..a60c2a8 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/SiteIndexer.java
@@ -36,6 +36,8 @@
 import com.google.gerrit.server.git.MergeUtil;
 import com.google.gerrit.server.git.MultiProgressMonitor;
 import com.google.gerrit.server.git.MultiProgressMonitor.Task;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexer;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.patch.PatchListLoader;
 import com.google.gerrit.server.query.change.ChangeData;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
similarity index 96%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
index 2248360..fdeb654 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeField.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeField.java
@@ -12,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import static com.google.common.base.MoreObjects.firstNonNull;
 
-import com.google.common.base.CharMatcher;
 import com.google.common.base.Function;
 import com.google.common.base.Splitter;
 import com.google.common.collect.ImmutableList;
@@ -30,6 +29,9 @@
 import com.google.gerrit.reviewdb.client.PatchLineComment;
 import com.google.gerrit.reviewdb.client.PatchSet;
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
+import com.google.gerrit.server.index.FieldDef;
+import com.google.gerrit.server.index.FieldType;
+import com.google.gerrit.server.index.SchemaUtil;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
@@ -39,14 +41,12 @@
 import com.google.gwtorm.server.OrmException;
 import com.google.protobuf.CodedOutputStream;
 
-import org.eclipse.jgit.lib.PersonIdent;
 import org.eclipse.jgit.revwalk.FooterLine;
 
 import java.io.ByteArrayOutputStream;
 import java.io.IOException;
 import java.sql.Timestamp;
 import java.util.ArrayList;
-import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -370,23 +370,9 @@
         }
       };
 
-  private static Set<String> getPersonParts(PersonIdent person) {
-    if (person == null) {
-      return ImmutableSet.of();
-    }
-    HashSet<String> parts = Sets.newHashSet();
-    String email = person.getEmailAddress().toLowerCase();
-    parts.add(email);
-    parts.addAll(Arrays.asList(email.split("@")));
-    Splitter s = Splitter.on(CharMatcher.anyOf("@.- ")).omitEmptyStrings();
-    Iterables.addAll(parts, s.split(email));
-    Iterables.addAll(parts, s.split(person.getName().toLowerCase()));
-    return parts;
-  }
-
   public static Set<String> getAuthorParts(ChangeData cd) throws OrmException {
     try {
-      return getPersonParts(cd.getAuthor());
+      return SchemaUtil.getPersonParts(cd.getAuthor());
     } catch (IOException e) {
       throw new OrmException(e);
     }
@@ -394,7 +380,7 @@
 
   public static Set<String> getCommitterParts(ChangeData cd) throws OrmException {
     try {
-      return getPersonParts(cd.getCommitter());
+      return SchemaUtil.getPersonParts(cd.getCommitter());
     } catch (IOException e) {
       throw new OrmException(e);
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndex.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndex.java
new file mode 100644
index 0000000..910dd93
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndex.java
@@ -0,0 +1,22 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.index.change;
+
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.index.Index;
+import com.google.gerrit.server.query.change.ChangeData;
+
+public interface ChangeIndex extends Index<Change.Id, ChangeData> {
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexCollection.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexCollection.java
new file mode 100644
index 0000000..247aa62
--- /dev/null
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexCollection.java
@@ -0,0 +1,25 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.index.change;
+
+import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.index.IndexCollection;
+import com.google.gerrit.server.query.change.ChangeData;
+import com.google.inject.Singleton;
+
+@Singleton
+public class ChangeIndexCollection extends
+    IndexCollection<Change.Id, ChangeData, ChangeIndex> {
+}
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexer.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
similarity index 96%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexer.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
index 0f9b459..48df562 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeIndexer.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeIndexer.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import com.google.common.base.Function;
 import com.google.common.util.concurrent.Atomics;
@@ -26,6 +26,7 @@
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.extensions.events.ChangeIndexedListener;
+import com.google.gerrit.server.index.Index;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.util.RequestContext;
 import com.google.gerrit.server.util.ThreadLocalRequestContext;
@@ -63,7 +64,7 @@
   public interface Factory {
     ChangeIndexer create(ListeningExecutorService executor, ChangeIndex index);
     ChangeIndexer create(ListeningExecutorService executor,
-        IndexCollection indexes);
+        ChangeIndexCollection indexes);
   }
 
   public static CheckedFuture<?, IOException> allAsList(
@@ -90,7 +91,7 @@
     }
   };
 
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final ChangeIndex index;
   private final SchemaFactory<ReviewDb> schemaFactory;
   private final ChangeData.Factory changeDataFactory;
@@ -120,7 +121,7 @@
       ThreadLocalRequestContext context,
       DynamicSet<ChangeIndexedListener> indexedListener,
       @Assisted ListeningExecutorService executor,
-      @Assisted IndexCollection indexes) {
+      @Assisted ChangeIndexCollection indexes) {
     this.executor = executor;
     this.schemaFactory = schemaFactory;
     this.changeDataFactory = changeDataFactory;
@@ -164,7 +165,7 @@
    * @param cd change to index.
    */
   public void index(ChangeData cd) throws IOException {
-    for (ChangeIndex i : getWriteIndexes()) {
+    for (Index<?, ChangeData> i : getWriteIndexes()) {
       i.replace(cd);
     }
     fireChangeIndexedEvent(cd);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemas.java
similarity index 65%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemas.java
index 58a4433..60896d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ChangeSchemas.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ChangeSchemas.java
@@ -12,22 +12,17 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.gerrit.server.index.SchemaUtil.schema;
 
-import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
+import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.SchemaUtil;
 import com.google.gerrit.server.query.change.ChangeData;
 
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.util.Collection;
-import java.util.Map;
-
 /** Secondary index schemas for changes. */
 public class ChangeSchemas {
   @Deprecated
@@ -107,16 +102,8 @@
 
   static final Schema<ChangeData> V27 = schema(V26.getFields().values());
 
-  private static Schema<ChangeData> schema(Collection<FieldDef<ChangeData, ?>> fields) {
-    return new Schema<>(ImmutableList.copyOf(fields));
-  }
-
-  @SafeVarargs
-  private static Schema<ChangeData> schema(FieldDef<ChangeData, ?>... fields) {
-    return schema(ImmutableList.copyOf(fields));
-  }
-
-  public static final ImmutableMap<Integer, Schema<ChangeData>> ALL;
+  public static final ImmutableMap<Integer, Schema<ChangeData>> ALL =
+      SchemaUtil.schemasFromClass(ChangeSchemas.class, ChangeData.class);
 
   public static Schema<ChangeData> get(int version) {
     Schema<ChangeData> schema = ALL.get(version);
@@ -127,33 +114,4 @@
   public static Schema<ChangeData> getLatest() {
     return Iterables.getLast(ALL.values());
   }
-
-  static {
-    Map<Integer, Schema<ChangeData>> all = Maps.newTreeMap();
-    for (Field f : ChangeSchemas.class.getDeclaredFields()) {
-      if (Modifier.isStatic(f.getModifiers())
-          && Modifier.isFinal(f.getModifiers())
-          && Schema.class.isAssignableFrom(f.getType())) {
-        ParameterizedType t = (ParameterizedType) f.getGenericType();
-        if (t.getActualTypeArguments()[0] == ChangeData.class) {
-          try {
-            @SuppressWarnings("unchecked")
-            Schema<ChangeData> schema = (Schema<ChangeData>) f.get(null);
-            checkArgument(f.getName().startsWith("V"));
-            schema.setVersion(Integer.parseInt(f.getName().substring(1)));
-            all.put(schema.getVersion(), schema);
-          } catch (IllegalArgumentException | IllegalAccessException e) {
-            throw new ExceptionInInitializerError(e);
-          }
-        } else {
-          throw new ExceptionInInitializerError(
-              "non-ChangeData schema: " + f);
-        }
-      }
-    }
-    if (all.isEmpty()) {
-      throw new ExceptionInInitializerError("no ChangeSchemas found");
-    }
-    ALL = ImmutableMap.copyOf(all);
-  }
 }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndex.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/DummyChangeIndex.java
similarity index 87%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndex.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/DummyChangeIndex.java
index d204905..ff68106 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/DummyIndex.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/DummyChangeIndex.java
@@ -12,17 +12,18 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.index.QueryOptions;
+import com.google.gerrit.server.index.Schema;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeDataSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 
 import java.io.IOException;
 
-public class DummyIndex implements ChangeIndex {
+public class DummyChangeIndex implements ChangeIndex {
   @Override
   public Schema<ChangeData> getSchema() {
     throw new UnsupportedOperationException();
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexRewriter.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexRewriter.java
similarity index 95%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/IndexRewriter.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexRewriter.java
index d56348b..324347b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexRewriter.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexRewriter.java
@@ -12,12 +12,15 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Change.Status;
+import com.google.gerrit.server.index.IndexConfig;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.QueryOptions;
 import com.google.gerrit.server.query.AndPredicate;
 import com.google.gerrit.server.query.NotPredicate;
 import com.google.gerrit.server.query.OrPredicate;
@@ -28,7 +31,6 @@
 import com.google.gerrit.server.query.change.ChangeStatusPredicate;
 import com.google.gerrit.server.query.change.LimitPredicate;
 import com.google.gerrit.server.query.change.OrSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 
@@ -118,11 +120,11 @@
     return null;
   }
 
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final IndexConfig config;
 
   @Inject
-  IndexRewriter(IndexCollection indexes,
+  IndexRewriter(ChangeIndexCollection indexes,
       IndexConfig config) {
     this.indexes = indexes;
     this.config = config;
@@ -205,7 +207,8 @@
     return partitionChildren(in, newChildren, isIndexed, index, opts);
   }
 
-  private boolean isIndexPredicate(Predicate<ChangeData> in, ChangeIndex index) {
+  private boolean isIndexPredicate(Predicate<ChangeData> in,
+      ChangeIndex index) {
     if (!(in instanceof IndexPredicate)) {
       return false;
     }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
similarity index 82%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedChangeQuery.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
index 28fa9f8..bb6ca45 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/IndexedChangeQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/IndexedChangeQuery.java
@@ -12,26 +12,35 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
+
+import static com.google.gerrit.server.index.change.ChangeField.CHANGE;
+import static com.google.gerrit.server.index.change.ChangeField.PROJECT;
 
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Function;
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Iterables;
 import com.google.common.primitives.Ints;
+import com.google.gerrit.server.index.IndexConfig;
+import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.QueryOptions;
+import com.google.gerrit.server.query.DataSource;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeDataSource;
 import com.google.gerrit.server.query.change.Paginated;
-import com.google.gerrit.server.query.change.QueryOptions;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
 
 import java.util.Collection;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Wrapper combining an {@link IndexPredicate} together with a
@@ -43,6 +52,22 @@
  */
 public class IndexedChangeQuery extends Predicate<ChangeData>
     implements ChangeDataSource, Paginated {
+  public static QueryOptions oneResult() {
+    return createOptions(IndexConfig.createDefault(), 0, 1,
+        ImmutableSet.<String> of());
+  }
+
+  public static QueryOptions createOptions(IndexConfig config, int start,
+      int limit, Set<String> fields) {
+    // Always include project since it is needed to load the change from notedb.
+    if (!fields.contains(CHANGE.getName())
+        && !fields.contains(PROJECT.getName())) {
+      fields = new HashSet<>(fields);
+      fields.add(PROJECT.getName());
+    }
+    return QueryOptions.create(config, start, limit, fields);
+  }
+
   @VisibleForTesting
   static QueryOptions convertOptions(QueryOptions opts) {
     // Increase the limit rather than skipping, since we don't know how many
@@ -50,14 +75,14 @@
     int backendLimit = opts.config().maxLimit();
     int limit = Ints.saturatedCast((long) opts.limit() + opts.start());
     limit = Math.min(limit, backendLimit);
-    return QueryOptions.create(opts.config(), 0, limit, opts.fields());
+    return IndexedChangeQuery.createOptions(opts.config(), 0, limit, opts.fields());
   }
 
   private final ChangeIndex index;
 
   private QueryOptions opts;
   private Predicate<ChangeData> pred;
-  private ChangeDataSource source;
+  private DataSource<ChangeData> source;
 
   public IndexedChangeQuery(ChangeIndex index, Predicate<ChangeData> pred,
       QueryOptions opts) throws QueryParseException {
@@ -102,7 +127,7 @@
 
   @Override
   public ResultSet<ChangeData> read() throws OrmException {
-    final ChangeDataSource currSource = source;
+    final DataSource<ChangeData> currSource = source;
     final ResultSet<ChangeData> rs = currSource.read();
 
     return new ResultSet<ChangeData>() {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
similarity index 96%
rename from gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java
rename to gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
index c0f4cfc..97463ff 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/index/ReindexAfterUpdate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/index/change/ReindexAfterUpdate.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import static com.google.gerrit.server.query.change.ChangeData.asChanges;
 
@@ -26,6 +26,7 @@
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.git.QueueProvider.QueueType;
+import com.google.gerrit.server.index.IndexExecutor;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.query.change.InternalChangeQuery;
@@ -50,7 +51,7 @@
   private final OneOffRequestContext requestContext;
   private final Provider<InternalChangeQuery> queryProvider;
   private final ChangeIndexer.Factory indexerFactory;
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final ChangeNotes.Factory notesFactory;
   private final ListeningExecutorService executor;
 
@@ -59,7 +60,7 @@
       OneOffRequestContext requestContext,
       Provider<InternalChangeQuery> queryProvider,
       ChangeIndexer.Factory indexerFactory,
-      IndexCollection indexes,
+      ChangeIndexCollection indexes,
       ChangeNotes.Factory notesFactory,
       @IndexExecutor(QueueType.BATCH) ListeningExecutorService executor) {
     this.requestContext = requestContext;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
index 95da72a..b20a194 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AddedPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IntegerRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
index aeb9619..5ed871a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AfterPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.TimestampRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
index 9a4ef19..2b140d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AgePredicate.java
@@ -20,8 +20,8 @@
 import com.google.gerrit.common.TimeUtil;
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.ConfigUtil;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.TimestampRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import java.sql.Timestamp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
index 6264f3a..ae192ab 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/AuthorPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.AUTHOR;
+import static com.google.gerrit.server.index.change.ChangeField.AUTHOR;
 import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_AUTHOR;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 public class AuthorPredicate extends IndexPredicate<ChangeData>  {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
index 8f51476..0618cc2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/BeforePredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.TimestampRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
index b2930e8..0db99e6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeData.java
@@ -58,6 +58,7 @@
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
 import com.google.gerrit.server.project.SubmitRuleEvaluator;
+import com.google.gerrit.server.query.DataSource;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
 import com.google.inject.assistedinject.Assisted;
@@ -315,7 +316,7 @@
   private final NotesMigration notesMigration;
   private final MergeabilityCache mergeabilityCache;
   private final Change.Id legacyId;
-  private ChangeDataSource returnedBySource;
+  private DataSource<ChangeData> returnedBySource;
   private Project.NameKey project;
   private Change change;
   private ChangeNotes notes;
@@ -528,11 +529,11 @@
     return db;
   }
 
-  public boolean isFromSource(ChangeDataSource s) {
+  public boolean isFromSource(DataSource<ChangeData> s) {
     return s == returnedBySource;
   }
 
-  public void cacheFromSource(ChangeDataSource s) {
+  public void cacheFromSource(DataSource<ChangeData> s) {
     returnedBySource = s;
   }
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
index 7f517d8..1fbeb86 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeIdPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 /** Predicate over Change-Id strings (aka Change.Key). */
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
index 16e8b6b..cb27de4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeQueryBuilder.java
@@ -49,13 +49,13 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.strategy.SubmitDryRun;
 import com.google.gerrit.server.group.ListMembers;
-import com.google.gerrit.server.index.ChangeField;
-import com.google.gerrit.server.index.ChangeIndex;
 import com.google.gerrit.server.index.FieldDef;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.IndexConfig;
-import com.google.gerrit.server.index.IndexRewriter;
 import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.IndexRewriter;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.patch.PatchListCache;
 import com.google.gerrit.server.project.ChangeControl;
@@ -205,7 +205,7 @@
         GitRepositoryManager repoManager,
         ProjectCache projectCache,
         Provider<ListChildProjects> listChildProjects,
-        IndexCollection indexes,
+        ChangeIndexCollection indexes,
         SubmitDryRun submitDryRun,
         ConflictsCache conflictsCache,
         TrackingFooters trackingFooters,
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
index 8cbe71f..4d42c33 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ChangeStatusPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Change.Status;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
index dee7086..1967a06 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentByPredicate.java
@@ -17,8 +17,8 @@
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.ChangeMessage;
 import com.google.gerrit.reviewdb.client.PatchLineComment;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import java.util.Objects;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
index 756715b..5e3fa3d 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommentPredicate.java
@@ -14,9 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
-import com.google.gerrit.server.index.ChangeIndex;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.IndexedChangeQuery;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
@@ -35,7 +36,7 @@
       Predicate<ChangeData> p = Predicate.and(
           new LegacyChangeIdPredicate(object.getId()), this);
       for (ChangeData cData
-          : index.getSource(p, QueryOptions.oneResult()).read()) {
+          : index.getSource(p, IndexedChangeQuery.oneResult()).read()) {
         if (cData.getId().equals(object.getId())) {
           return true;
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
index 1ac4d9c..91b2c58 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.COMMIT;
-import static com.google.gerrit.server.index.ChangeField.EXACT_COMMIT;
+import static com.google.gerrit.server.index.change.ChangeField.COMMIT;
+import static com.google.gerrit.server.index.change.ChangeField.EXACT_COMMIT;
 import static org.eclipse.jgit.lib.Constants.OBJECT_ID_STRING_LENGTH;
 
 import com.google.gerrit.reviewdb.client.PatchSet;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
index 3cb7f8e..f923d00 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/CommitterPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.COMMITTER;
+import static com.google.gerrit.server.index.change.ChangeField.COMMITTER;
 import static com.google.gerrit.server.query.change.ChangeQueryBuilder.FIELD_COMMITTER;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 public class CommitterPredicate extends IndexPredicate<ChangeData>  {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
index 478990d..8e9ac73 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeletedPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IntegerRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
index 39b860a..a3eaa8a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/DeltaPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IntegerRangePredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData.ChangedLines;
 import com.google.gwtorm.server.OrmException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
index b544da6..f1fa000 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EditByPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class EditByPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
index a21c590..8c98b6f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsFilePredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder.Arguments;
 import com.google.gwtorm.server.OrmException;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
index 859b05b..ff9c853 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsLabelPredicate.java
@@ -23,8 +23,8 @@
 import com.google.gerrit.reviewdb.client.PatchSetApproval;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.IdentifiedUser;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.project.NoSuchChangeException;
 import com.google.gerrit.server.project.ProjectCache;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
index 055b6d5..85c3cd5 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/EqualsPathPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import java.util.Collections;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
index c2a9084..6658577 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ExactTopicPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.EXACT_TOPIC;
+import static com.google.gerrit.server.index.change.ChangeField.EXACT_TOPIC;
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.index.IndexPredicate;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
index 154a659..23b3ee6 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/FuzzyTopicPredicate.java
@@ -14,12 +14,13 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.FUZZY_TOPIC;
+import static com.google.gerrit.server.index.change.ChangeField.FUZZY_TOPIC;
 
 import com.google.common.collect.Iterables;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeIndex;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.IndexedChangeQuery;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
@@ -45,7 +46,7 @@
     try {
       Predicate<ChangeData> thisId = new LegacyChangeIdPredicate(cd.getId());
       Iterable<ChangeData> results =
-          index.getSource(and(thisId, this), QueryOptions.oneResult()).read();
+          index.getSource(and(thisId, this), IndexedChangeQuery.oneResult()).read();
       return !Iterables.isEmpty(results);
     } catch (QueryParseException e) {
       throw new OrmException(e);
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
index 235d64e..ff9c544 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/GroupPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.PatchSet;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import java.util.List;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
index fbc6cfb..c18e19c 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HasDraftByPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class HasDraftByPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
index ea591ec..3f952d3 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/HashtagPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.server.change.HashtagsUtil;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class HashtagPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
index d02e58b..bb72a1b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/InternalChangeQuery.java
@@ -15,7 +15,7 @@
 package com.google.gerrit.server.query.change;
 
 import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.gerrit.server.index.ChangeField.SUBMISSIONID;
+import static com.google.gerrit.server.index.change.ChangeField.SUBMISSIONID;
 import static com.google.gerrit.server.query.Predicate.and;
 import static com.google.gerrit.server.query.Predicate.not;
 import static com.google.gerrit.server.query.Predicate.or;
@@ -33,10 +33,10 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.reviewdb.client.RefNames;
 import com.google.gerrit.reviewdb.server.ReviewDb;
-import com.google.gerrit.server.index.ChangeIndex;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.IndexConfig;
 import com.google.gerrit.server.index.Schema;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
@@ -85,14 +85,14 @@
 
   private final IndexConfig indexConfig;
   private final QueryProcessor qp;
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final ChangeData.Factory changeDataFactory;
   private final ChangeNotes.Factory notesFactory;
 
   @Inject
   InternalChangeQuery(IndexConfig indexConfig,
       QueryProcessor queryProcessor,
-      IndexCollection indexes,
+      ChangeIndexCollection indexes,
       ChangeData.Factory changeDataFactory,
       ChangeNotes.Factory notesFactory) {
     this.indexConfig = indexConfig;
@@ -305,7 +305,8 @@
     }
   }
 
-  private static Schema<ChangeData> schema(@Nullable IndexCollection indexes) {
+  private static Schema<ChangeData> schema(
+      @Nullable ChangeIndexCollection indexes) {
     ChangeIndex index = indexes != null ? indexes.getSearchIndex() : null;
     return index != null ? index.getSchema() : null;
   }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
index 8e300a9..5dd7dd2 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsMergeablePredicate.java
@@ -14,9 +14,9 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.FieldDef.FillArgs;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class IsMergeablePredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
index bd8d275..604f84b 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/IsReviewedPredicate.java
@@ -14,11 +14,11 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.REVIEWEDBY;
+import static com.google.gerrit.server.index.change.ChangeField.REVIEWEDBY;
 
 import com.google.gerrit.reviewdb.client.Account;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
index f4a1550..656eca0 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/LegacyChangeIdPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.LEGACY_ID;
+import static com.google.gerrit.server.index.change.ChangeField.LEGACY_ID;
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.index.IndexPredicate;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
index 43d7708..021b6d7 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/MessagePredicate.java
@@ -14,9 +14,10 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
-import com.google.gerrit.server.index.ChangeIndex;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.IndexedChangeQuery;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gwtorm.server.OrmException;
@@ -39,7 +40,7 @@
       Predicate<ChangeData> p = Predicate.and(
           new LegacyChangeIdPredicate(object.getId()), this);
       for (ChangeData cData
-          : index.getSource(p, QueryOptions.oneResult()).read()) {
+          : index.getSource(p, IndexedChangeQuery.oneResult()).read()) {
         if (cData.getId().equals(object.getId())) {
           return true;
         }
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
index 87ebffb..bb7cb403a 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/OwnerPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class OwnerPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
index 3278b7f..a6a155f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/Paginated.java
@@ -14,6 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
+import com.google.gerrit.server.index.QueryOptions;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
index 872b854..0bb5650 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class ProjectPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
index d0faf0f..400a204 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ProjectPrefixPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class ProjectPrefixPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
index 12882f3..cd6b1ae 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/QueryProcessor.java
@@ -26,11 +26,13 @@
 import com.google.gerrit.metrics.Timer0;
 import com.google.gerrit.reviewdb.server.ReviewDb;
 import com.google.gerrit.server.CurrentUser;
-import com.google.gerrit.server.index.ChangeIndex;
-import com.google.gerrit.server.index.IndexCollection;
 import com.google.gerrit.server.index.IndexConfig;
 import com.google.gerrit.server.index.IndexPredicate;
-import com.google.gerrit.server.index.IndexRewriter;
+import com.google.gerrit.server.index.QueryOptions;
+import com.google.gerrit.server.index.change.ChangeIndex;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
+import com.google.gerrit.server.index.change.IndexRewriter;
+import com.google.gerrit.server.index.change.IndexedChangeQuery;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ChangeControl;
 import com.google.gerrit.server.query.Predicate;
@@ -50,7 +52,7 @@
   private final Provider<CurrentUser> userProvider;
   private final ChangeControl.GenericFactory changeControlFactory;
   private final ChangeNotes.Factory notesFactory;
-  private final IndexCollection indexes;
+  private final ChangeIndexCollection indexes;
   private final IndexRewriter rewriter;
   private final IndexConfig indexConfig;
   private final Metrics metrics;
@@ -65,7 +67,7 @@
       Provider<CurrentUser> userProvider,
       ChangeControl.GenericFactory changeControlFactory,
       ChangeNotes.Factory notesFactory,
-      IndexCollection indexes,
+      ChangeIndexCollection indexes,
       IndexRewriter rewriter,
       IndexConfig indexConfig,
       Metrics metrics) {
@@ -168,7 +170,7 @@
             "Cannot go beyond page " + indexConfig.maxPages() + "of results");
       }
 
-      QueryOptions opts = QueryOptions.create(
+      QueryOptions opts = IndexedChangeQuery.createOptions(
           indexConfig, start, limit + 1, getRequestedFields());
       Predicate<ChangeData> s = rewriter.rewrite(q, opts);
       if (!(s instanceof ChangeDataSource)) {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
index 8a43fb1..e62855f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RefPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class RefPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
index 049aa40..a8c0e60 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexPathPredicate.java
@@ -14,8 +14,8 @@
 
 package com.google.gerrit.server.query.change;
 
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.RegexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gerrit.server.util.RegexListSearcher;
 import com.google.gwtorm.server.OrmException;
 
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
index df4fff9..48c815f 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexProjectPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.reviewdb.client.Project;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.RegexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
index 31625df..00c1dfe 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexRefPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.RegexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import dk.brics.automaton.RegExp;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
index 35b94ea..d51aaa4 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/RegexTopicPredicate.java
@@ -14,7 +14,7 @@
 
 package com.google.gerrit.server.query.change;
 
-import static com.google.gerrit.server.index.ChangeField.FUZZY_TOPIC;
+import static com.google.gerrit.server.index.change.ChangeField.FUZZY_TOPIC;
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.index.RegexPredicate;
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
index 004de72..eb07250 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/ReviewerPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Account;
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class ReviewerPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
index 3b2dd94..35a5a29 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/SubmissionIdPredicate.java
@@ -15,8 +15,8 @@
 package com.google.gerrit.server.query.change;
 
 import com.google.gerrit.reviewdb.client.Change;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 class SubmissionIdPredicate extends IndexPredicate<ChangeData> {
diff --git a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
index 4f2a8d7..aed8831 100644
--- a/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
+++ b/gerrit-server/src/main/java/com/google/gerrit/server/query/change/TrackingIdPredicate.java
@@ -16,8 +16,8 @@
 
 import com.google.gerrit.reviewdb.client.Change;
 import com.google.gerrit.server.config.TrackingFooters;
-import com.google.gerrit.server.index.ChangeField;
 import com.google.gerrit.server.index.IndexPredicate;
+import com.google.gerrit.server.index.change.ChangeField;
 import com.google.gwtorm.server.OrmException;
 
 import org.eclipse.jgit.revwalk.FooterLine;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/SchemaUtilTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/SchemaUtilTest.java
new file mode 100644
index 0000000..b623ae8
--- /dev/null
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/SchemaUtilTest.java
@@ -0,0 +1,71 @@
+// Copyright (C) 2016 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package com.google.gerrit.server.index;
+
+import static com.google.common.truth.Truth.assertThat;
+import static com.google.gerrit.server.index.SchemaUtil.getPersonParts;
+import static com.google.gerrit.server.index.SchemaUtil.schema;
+
+import com.google.gerrit.testutil.GerritBaseTests;
+
+import org.eclipse.jgit.lib.PersonIdent;
+import org.junit.Test;
+
+import java.util.Map;
+
+public class SchemaUtilTest extends GerritBaseTests {
+  static class TestSchemas {
+    static final Schema<String> V1 = schema();
+    static final Schema<String> V2 = schema();
+    static Schema<String> V3 = schema(); // Not final, ignored.
+    private static final Schema<String> V4 = schema();
+
+    // Ignored.
+    static Schema<String> V10 = schema();
+    final Schema<String> V11 = schema();
+  }
+
+  @Test
+  public void schemasFromClassBuildsMap() {
+    Map<Integer, Schema<String>> all =
+        SchemaUtil.schemasFromClass(TestSchemas.class, String.class);
+    assertThat(all.keySet()).containsExactly(1, 2, 4);
+    assertThat(all.get(1)).isEqualTo(TestSchemas.V1);
+    assertThat(all.get(2)).isEqualTo(TestSchemas.V2);
+    assertThat(all.get(4)).isEqualTo(TestSchemas.V4);
+
+    exception.expect(IllegalArgumentException.class);
+    SchemaUtil.schemasFromClass(TestSchemas.class, Object.class);
+  }
+
+  @Test
+  public void getPersonPartsExtractsParts() {
+    // PersonIdent allows empty email, which should be extracted as the empty
+    // string. However, it converts empty names to null internally.
+    assertThat(getPersonParts(new PersonIdent("", ""))).containsExactly("");
+    assertThat(getPersonParts(new PersonIdent("foo bar", "")))
+        .containsExactly("foo", "bar", "");
+
+    assertThat(getPersonParts(new PersonIdent("", "foo@example.com")))
+        .containsExactly(
+            "foo@example.com", "foo", "example.com", "example", "com");
+    assertThat(
+            getPersonParts(new PersonIdent("foO J. bAr", "bA-z@exAmple.cOm")))
+        .containsExactly(
+            "foo", "j", "bar",
+            "ba-z@example.com", "ba-z", "ba", "z",
+            "example.com", "example", "com");
+  }
+}
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeChangeIndex.java
similarity index 88%
rename from gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java
rename to gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeChangeIndex.java
index b3b4cf8..3476e42 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeIndex.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeChangeIndex.java
@@ -12,22 +12,24 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import com.google.common.collect.ImmutableList;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.index.FieldDef;
+import com.google.gerrit.server.index.QueryOptions;
+import com.google.gerrit.server.index.Schema;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeDataSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 import com.google.gwtorm.server.OrmException;
 import com.google.gwtorm.server.ResultSet;
 
 import org.junit.Ignore;
 
 @Ignore
-class FakeIndex implements ChangeIndex {
+class FakeChangeIndex implements ChangeIndex {
   static Schema<ChangeData> V1 = new Schema<>(1,
     ImmutableList.<FieldDef<ChangeData, ?>> of(
       ChangeField.STATUS));
@@ -68,7 +70,7 @@
 
   private final Schema<ChangeData> schema;
 
-  FakeIndex(Schema<ChangeData> schema) {
+  FakeChangeIndex(Schema<ChangeData> schema) {
     this.schema = schema;
   }
 
@@ -90,7 +92,7 @@
   @Override
   public ChangeDataSource getSource(Predicate<ChangeData> p, QueryOptions opts)
       throws QueryParseException {
-    return new FakeIndex.Source(p);
+    return new FakeChangeIndex.Source(p);
   }
 
   @Override
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
similarity index 94%
rename from gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
rename to gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
index 0796430..e88962e 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/FakeQueryBuilder.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/FakeQueryBuilder.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import com.google.gerrit.server.query.OperatorPredicate;
 import com.google.gerrit.server.query.Predicate;
@@ -24,7 +24,7 @@
 
 @Ignore
 public class FakeQueryBuilder extends ChangeQueryBuilder {
-  FakeQueryBuilder(IndexCollection indexes) {
+  FakeQueryBuilder(ChangeIndexCollection indexes) {
     super(
         new FakeQueryBuilder.Definition<>(
           FakeQueryBuilder.class),
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriterTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/IndexRewriterTest.java
similarity index 94%
rename from gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriterTest.java
rename to gerrit-server/src/test/java/com/google/gerrit/server/index/change/IndexRewriterTest.java
index 9716dc5..56be1cf 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/index/IndexRewriterTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/index/change/IndexRewriterTest.java
@@ -12,7 +12,7 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-package com.google.gerrit.server.index;
+package com.google.gerrit.server.index.change;
 
 import static com.google.common.truth.Truth.assertThat;
 import static com.google.gerrit.common.data.GlobalCapability.DEFAULT_MAX_QUERY_LIMIT;
@@ -20,13 +20,15 @@
 import static com.google.gerrit.reviewdb.client.Change.Status.DRAFT;
 import static com.google.gerrit.reviewdb.client.Change.Status.MERGED;
 import static com.google.gerrit.reviewdb.client.Change.Status.NEW;
-import static com.google.gerrit.server.index.IndexedChangeQuery.convertOptions;
+import static com.google.gerrit.server.index.change.IndexedChangeQuery.convertOptions;
 import static com.google.gerrit.server.query.Predicate.and;
 import static com.google.gerrit.server.query.Predicate.or;
 import static org.junit.Assert.assertEquals;
 
 import com.google.common.collect.ImmutableSet;
 import com.google.gerrit.reviewdb.client.Change;
+import com.google.gerrit.server.index.IndexConfig;
+import com.google.gerrit.server.index.QueryOptions;
 import com.google.gerrit.server.query.AndPredicate;
 import com.google.gerrit.server.query.Predicate;
 import com.google.gerrit.server.query.QueryParseException;
@@ -34,7 +36,6 @@
 import com.google.gerrit.server.query.change.ChangeData;
 import com.google.gerrit.server.query.change.ChangeQueryBuilder;
 import com.google.gerrit.server.query.change.OrSource;
-import com.google.gerrit.server.query.change.QueryOptions;
 import com.google.gerrit.testutil.GerritBaseTests;
 
 import org.junit.Before;
@@ -47,15 +48,15 @@
 public class IndexRewriterTest extends GerritBaseTests {
   private static final IndexConfig CONFIG = IndexConfig.createDefault();
 
-  private FakeIndex index;
-  private IndexCollection indexes;
+  private FakeChangeIndex index;
+  private ChangeIndexCollection indexes;
   private ChangeQueryBuilder queryBuilder;
   private IndexRewriter rewrite;
 
   @Before
   public void setUp() throws Exception {
-    index = new FakeIndex(FakeIndex.V2);
-    indexes = new IndexCollection();
+    index = new FakeChangeIndex(FakeChangeIndex.V2);
+    indexes = new ChangeIndexCollection();
     indexes.setSearchIndex(index);
     queryBuilder = new FakeQueryBuilder(indexes);
     rewrite = new IndexRewriter(indexes,
@@ -219,7 +220,7 @@
     Predicate<ChangeData> in = parse("status:merged file:a");
     assertThat(rewrite(in)).isEqualTo(query(in));
 
-    indexes.setSearchIndex(new FakeIndex(FakeIndex.V1));
+    indexes.setSearchIndex(new FakeChangeIndex(FakeChangeIndex.V1));
     Predicate<ChangeData> out = rewrite(in);
     assertThat(out).isInstanceOf(AndPredicate.class);
     assertThat(out.getChildren())
@@ -286,7 +287,7 @@
   }
 
   private static QueryOptions options(int start, int limit) {
-    return QueryOptions.create(CONFIG, start, limit,
+    return IndexedChangeQuery.createOptions(CONFIG, start, limit,
         ImmutableSet.<String> of());
   }
 
diff --git a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
index 53a7c3b..e8d95df 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/server/query/change/AbstractQueryChangesTest.java
@@ -62,8 +62,8 @@
 import com.google.gerrit.server.change.PatchSetInserter;
 import com.google.gerrit.server.git.BatchUpdate;
 import com.google.gerrit.server.git.validators.CommitValidators;
-import com.google.gerrit.server.index.ChangeField;
-import com.google.gerrit.server.index.IndexCollection;
+import com.google.gerrit.server.index.change.ChangeField;
+import com.google.gerrit.server.index.change.ChangeIndexCollection;
 import com.google.gerrit.server.notedb.ChangeNotes;
 import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.RefControl;
@@ -114,7 +114,7 @@
   @Inject protected ChangeQueryBuilder queryBuilder;
   @Inject protected GerritApi gApi;
   @Inject protected IdentifiedUser.GenericFactory userFactory;
-  @Inject protected IndexCollection indexes;
+  @Inject protected ChangeIndexCollection indexes;
   @Inject protected InMemoryDatabase schemaFactory;
   @Inject protected InMemoryRepositoryManager repoManager;
   @Inject protected InternalChangeQuery internalChangeQuery;
diff --git a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
index 3cdc914..eda5562 100644
--- a/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
+++ b/gerrit-server/src/test/java/com/google/gerrit/testutil/InMemoryModule.java
@@ -48,8 +48,8 @@
 import com.google.gerrit.server.git.GitRepositoryManager;
 import com.google.gerrit.server.git.PerThreadRequestScope;
 import com.google.gerrit.server.git.SendEmailExecutor;
-import com.google.gerrit.server.index.ChangeSchemas;
 import com.google.gerrit.server.index.IndexModule.IndexType;
+import com.google.gerrit.server.index.change.ChangeSchemas;
 import com.google.gerrit.server.mail.SignedTokenEmailTokenVerifier;
 import com.google.gerrit.server.notedb.NotesMigration;
 import com.google.gerrit.server.patch.DiffExecutor;