You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by rn...@apache.org on 2023/04/06 11:13:51 UTC

[couchdb] branch import-nouveau-singlelucene created (now eed30eb90)

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

rnewson pushed a change to branch import-nouveau-singlelucene
in repository https://gitbox.apache.org/repos/asf/couchdb.git


      at eed30eb90 flatten to one project, one lucene

This branch includes the following new commits:

     new eed30eb90 flatten to one project, one lucene

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



[couchdb] 01/01: flatten to one project, one lucene

Posted by rn...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

rnewson pushed a commit to branch import-nouveau-singlelucene
in repository https://gitbox.apache.org/repos/asf/couchdb.git

commit eed30eb907cf9b9fc53e22f871422f9df648fd0a
Author: Robert Newson <rn...@apache.org>
AuthorDate: Thu Apr 6 11:49:44 2023 +0100

    flatten to one project, one lucene
---
 dev/run                                            |  25 +-
 nouveau/{server => }/LICENSE                       |   0
 nouveau/{server => }/TODO                          |   0
 nouveau/base/pom.xml                               |  76 ----
 .../org/apache/couchdb/nouveau/LuceneBundle.java   |  28 --
 nouveau/lucene4/pom.xml                            | 143 -------
 nouveau/lucene4/src/main/assembly/dist.xml         |  26 --
 .../couchdb/nouveau/lucene4/Lucene4Bundle.java     |  51 ---
 .../lucene4/core/IndexableFieldDeserializer.java   |  96 -----
 .../lucene4/core/IndexableFieldSerializer.java     |  54 ---
 .../lucene4/core/Lucene4AnalyzerFactory.java       | 142 -------
 .../couchdb/nouveau/lucene4/core/Lucene4Index.java | 414 ---------------------
 .../nouveau/lucene4/core/Lucene4Module.java        |  36 --
 .../nouveau/lucene4/core/Lucene4QueryParser.java   | 155 --------
 .../lucene4/core/ParallelSearcherFactory.java      |  36 --
 .../nouveau/lucene4/core/PerFieldAnalyzer.java     |  39 --
 .../nouveau/lucene4/core/QueryDeserializer.java    |  41 --
 .../nouveau/lucene4/core/QuerySerializer.java      |  88 -----
 .../lucene4/core/SimpleAsciiFoldingAnalyzer.java   |  38 --
 .../apache/couchdb/nouveau/lucene4/core/Utils.java |  32 --
 .../nouveau/lucene4/health/AnalyzeHealthCheck.java |  25 --
 .../nouveau/lucene4/health/IndexHealthCheck.java   |  44 ---
 .../nouveau/lucene4/resources/AnalyzeResource.java |  76 ----
 .../nouveau/lucene4/resources/IndexResource.java   | 139 -------
 .../org.apache.couchdb.nouveau.LuceneBundle        |  16 -
 .../lucene4/core/Lucene4AnalyzerFactoryTest.java   | 255 -------------
 .../nouveau/lucene4/core/Lucene4IndexTest.java     | 111 ------
 nouveau/lucene4/src/test/resources/index.zip       | Bin 1853 -> 0 bytes
 nouveau/lucene9/pom.xml                            | 167 ---------
 nouveau/lucene9/src/main/assembly/dist.xml         |  26 --
 .../couchdb/nouveau/lucene9/Lucene9Bundle.java     |  52 ---
 .../org.apache.couchdb.nouveau.LuceneBundle        |  16 -
 .../nouveau/lucene9/core/CaffeineCacheTest.java    |  98 -----
 nouveau/{server => }/nouveau.yaml                  |   0
 nouveau/pom.xml                                    | 219 ++++++++---
 nouveau/server/pom.xml                             | 133 -------
 .../apache/couchdb/nouveau/NouveauApplication.java |  54 ++-
 .../nouveau/NouveauApplicationConfiguration.java   |   0
 .../java/org/apache/couchdb/nouveau/api/After.java |   0
 .../apache/couchdb/nouveau/api/AnalyzeRequest.java |   0
 .../couchdb/nouveau/api/AnalyzeResponse.java       |   0
 .../couchdb/nouveau/api/DocumentDeleteRequest.java |   0
 .../couchdb/nouveau/api/DocumentUpdateRequest.java |   0
 .../apache/couchdb/nouveau/api/DoubleRange.java    |   0
 .../couchdb/nouveau/api/IndexDefinition.java       |   0
 .../org/apache/couchdb/nouveau/api/IndexInfo.java  |   0
 .../java/org/apache/couchdb/nouveau/api/Range.java |   0
 .../org/apache/couchdb/nouveau/api/SearchHit.java  |   0
 .../apache/couchdb/nouveau/api/SearchRequest.java  |   0
 .../apache/couchdb/nouveau/api/SearchResults.java  |   0
 .../org/apache/couchdb/nouveau/core/IOUtils.java   |   0
 .../org/apache/couchdb/nouveau/core/Index.java     |   0
 .../couchdb/nouveau/core/IndexClosedException.java |   0
 .../apache/couchdb/nouveau/core/IndexFunction.java |   0
 .../apache/couchdb/nouveau/core/IndexLoader.java   |   0
 .../apache/couchdb/nouveau/core/IndexManager.java  |   0
 .../nouveau/core/UpdatesOutOfOrderException.java   |   0
 .../core/UpdatesOutOfOrderExceptionMapper.java     |   0
 .../nouveau/core/ser/AfterDeserializer.java        |   0
 .../couchdb/nouveau/core/ser/AfterSerializer.java  |   0
 .../nouveau/health/BaseAnalyzeHealthCheck.java     |   0
 .../nouveau/health/BaseIndexHealthCheck.java       |   0
 .../lucene9/core/IndexableFieldDeserializer.java   |   0
 .../lucene9/core/IndexableFieldSerializer.java     |   0
 .../lucene9/core/Lucene9AnalyzerFactory.java       |   0
 .../couchdb/nouveau/lucene9/core/Lucene9Index.java |   0
 .../nouveau/lucene9/core/Lucene9Module.java        |   0
 .../nouveau/lucene9/core/Lucene9QueryParser.java   |   0
 .../lucene9/core/NumericRangeQueryProcessor.java   |   0
 .../lucene9/core/ParallelSearcherFactory.java      |   0
 .../nouveau/lucene9/core/QueryDeserializer.java    |   0
 .../nouveau/lucene9/core/QuerySerializer.java      |   0
 .../lucene9/core/SimpleAsciiFoldingAnalyzer.java   |   0
 .../nouveau/lucene9/health/AnalyzeHealthCheck.java |   0
 .../nouveau/lucene9/health/IndexHealthCheck.java   |   0
 .../nouveau/lucene9/resources/AnalyzeResource.java |   0
 .../nouveau/lucene9/resources/IndexResource.java   |   0
 .../nouveau/resources/BaseAnalyzeResource.java     |   0
 .../nouveau/resources/BaseIndexResource.java       |   0
 .../couchdb/nouveau/tasks/CloseAllIndexesTask.java |   0
 nouveau/{server => }/src/main/resources/banner.txt |   0
 .../couchdb/nouveau/api/SearchRequestTest.java     |   0
 .../apache/couchdb/nouveau/core/BaseIndexTest.java |   0
 .../lucene9/core/Lucene9AnalyzerFactoryTest.java   |   0
 .../nouveau/lucene9/core/Lucene9IndexTest.java     |   0
 .../lucene9/core/QuerySerializationTest.java       |   0
 .../resources/fixtures/DocumentUpdateRequest.json  |   0
 .../src/test/resources/fixtures/SearchRequest.json |   0
 88 files changed, 203 insertions(+), 2748 deletions(-)

diff --git a/dev/run b/dev/run
index cb48c0be9..707dc709c 100755
--- a/dev/run
+++ b/dev/run
@@ -466,31 +466,12 @@ def boot_nouveau(ctx):
     if not ctx["with_nouveau"]:
         return
 
-    # generate classpath (the least stupid way Maven can do this apparently)
-    classpath_file = os.path.join(ctx["devdir"], "lib", "nouveau.classpath")
-    p = sp.Popen(
-        "mvn --quiet dependency:build-classpath -D mdep.outputFile=%s" % classpath_file,
-        cwd="nouveau/server",
-        shell=True,
-    )
-    p.wait()
-    with open(classpath_file, "r") as f:
-        classpath = f.read()
-    classpath += ":target/classes"
-
-    home = os.environ["HOME"]
     version = "1.0-SNAPSHOT"
-
     cmd = [
         "java",
         "-server",
-        "-Dnouveau.bundle.4=file://%s/.m2/repository/org/apache/couchdb/nouveau/lucene4/%s/lucene4-%s-dist.jar"
-        % (home, version, version),
-        "-Dnouveau.bundle.9=file://%s/.m2/repository/org/apache/couchdb/nouveau/lucene9/%s/lucene9-%s-dist.jar"
-        % (home, version, version),
-        "-classpath",
-        classpath,
-        "org.apache.couchdb.nouveau.NouveauApplication",
+        "-jar",
+        "target/server-%s-dist.jar" % version,
         "server",
         "nouveau.yaml",
     ]
@@ -499,7 +480,7 @@ def boot_nouveau(ctx):
     log = open(logfname, "w")
     return sp.Popen(
         " ".join(cmd),
-        cwd="nouveau/server",
+        cwd="nouveau",
         shell=True,
         stdin=sp.PIPE,
         stdout=log,
diff --git a/nouveau/server/LICENSE b/nouveau/LICENSE
similarity index 100%
rename from nouveau/server/LICENSE
rename to nouveau/LICENSE
diff --git a/nouveau/server/TODO b/nouveau/TODO
similarity index 100%
rename from nouveau/server/TODO
rename to nouveau/TODO
diff --git a/nouveau/base/pom.xml b/nouveau/base/pom.xml
deleted file mode 100644
index d14e49275..000000000
--- a/nouveau/base/pom.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.apache.couchdb.nouveau</groupId>
-  <artifactId>base</artifactId>
-  <name>${project.artifactId}</name>
-  <version>1.0-SNAPSHOT</version>
-  <description>Nouveau Base classes</description>
-  <inceptionYear>2023</inceptionYear>
-
-  <parent>
-    <groupId>org.apache.couchdb.nouveau</groupId>
-    <artifactId>parent</artifactId>
-    <version>1.0-SNAPSHOT</version>
-  </parent>
-
-  <dependencies>
-    <!-- Dropwizard -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.dropwizard.metrics</groupId>
-      <artifactId>metrics-caffeine</artifactId>
-    </dependency>
-
-    <!-- Test -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-testing</artifactId>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>junit</groupId>
-          <artifactId>junit</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-	  <groupId>org.junit.jupiter</groupId>
-	  <artifactId>junit-jupiter</artifactId>
-	  <scope>test</scope>
-	</dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.assertj</groupId>
-      <artifactId>assertj-core</artifactId>
-      <version>3.22.0</version>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <defaultGoal>install</defaultGoal>
-    <plugins>
-     <plugin>
-       <groupId>org.apache.maven.plugins</groupId>
-       <artifactId>maven-jar-plugin</artifactId>
-       <version>3.0.2</version>
-       <executions>
-         <execution>
-           <goals>
-             <goal>test-jar</goal>
-           </goals>
-         </execution>
-       </executions>
-     </plugin>
-    </plugins>
-  </build>
-
-</project>
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/LuceneBundle.java b/nouveau/base/src/main/java/org/apache/couchdb/nouveau/LuceneBundle.java
deleted file mode 100644
index f8408d6fb..000000000
--- a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/LuceneBundle.java
+++ /dev/null
@@ -1,28 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau;
-
-import org.apache.couchdb.nouveau.core.IndexManager;
-
-import io.dropwizard.core.ConfiguredBundle;
-
-public class LuceneBundle implements ConfiguredBundle<NouveauApplicationConfiguration> {
-
-    protected IndexManager indexManager;
-
-    public void setIndexManager(final IndexManager indexManager) {
-        this.indexManager = indexManager;
-    }
-
-}
diff --git a/nouveau/lucene4/pom.xml b/nouveau/lucene4/pom.xml
deleted file mode 100644
index c04bc541e..000000000
--- a/nouveau/lucene4/pom.xml
+++ /dev/null
@@ -1,143 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.apache.couchdb.nouveau</groupId>
-  <artifactId>lucene4</artifactId>
-  <name>${project.artifactId}</name>
-  <version>1.0-SNAPSHOT</version>
-  <description>Lucene 4 index classes</description>
-  <inceptionYear>2023</inceptionYear>
-
-  <parent>
-    <groupId>org.apache.couchdb.nouveau</groupId>
-    <artifactId>parent</artifactId>
-    <version>1.0-SNAPSHOT</version>
-  </parent>
-
-  <properties>
-    <lucene.version>4.6.1</lucene.version>
-  </properties>
-
-  <dependencies>
-
-    <!-- Base -->
-    <dependency>
-      <groupId>org.apache.couchdb.nouveau</groupId>
-      <artifactId>base</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-      <!-- Base tests -->
-    <dependency>
-      <groupId>org.apache.couchdb.nouveau</groupId>
-      <artifactId>base</artifactId>
-      <version>${project.version}</version>
-      <classifier>tests</classifier>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-
-    <!-- Dropwizard -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-core</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-    </dependency>
-
-    <!-- Lucene -->
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-core</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-queryparser</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analyzers-common</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analyzers-stempel</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analyzers-smartcn</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analyzers-kuromoji</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-facet</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-misc</artifactId>
-      <version>${lucene.version}</version>
-      <scope>provided</scope>
-    </dependency>
-
-    <!-- Test -->
-    <dependency>
-	  <groupId>org.junit.jupiter</groupId>
-	  <artifactId>junit-jupiter</artifactId>
-	  <scope>test</scope>
-	</dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.assertj</groupId>
-      <artifactId>assertj-core</artifactId>
-      <version>3.22.0</version>
-      <scope>test</scope>
-    </dependency>
-
-  </dependencies>
-
-  <build>
-    <defaultGoal>install</defaultGoal>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-assembly-plugin</artifactId>
-        <configuration>
-          <descriptors>
-            <descriptor>src/main/assembly/dist.xml</descriptor>
-          </descriptors>
-        </configuration>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>single</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>
diff --git a/nouveau/lucene4/src/main/assembly/dist.xml b/nouveau/lucene4/src/main/assembly/dist.xml
deleted file mode 100644
index 68eaeaff0..000000000
--- a/nouveau/lucene4/src/main/assembly/dist.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-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.
--->
-<assembly>
-  <id>dist</id>
-  <formats>
-    <format>jar</format>
-  </formats>
-  <includeBaseDirectory>false</includeBaseDirectory>
-  <dependencySets>
-    <dependencySet>
-      <outputDirectory>/</outputDirectory>
-      <useProjectArtifact>true</useProjectArtifact>
-      <unpack>true</unpack>
-      <scope>provided</scope>
-    </dependencySet>
-  </dependencySets>
-</assembly>
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/Lucene4Bundle.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/Lucene4Bundle.java
deleted file mode 100644
index 7c89d9c8c..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/Lucene4Bundle.java
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4;
-
-import java.util.concurrent.ForkJoinPool;
-
-import org.apache.couchdb.nouveau.LuceneBundle;
-import org.apache.couchdb.nouveau.NouveauApplicationConfiguration;
-import org.apache.couchdb.nouveau.lucene4.core.Lucene4Module;
-import org.apache.couchdb.nouveau.lucene4.core.ParallelSearcherFactory;
-import org.apache.couchdb.nouveau.lucene4.health.AnalyzeHealthCheck;
-import org.apache.couchdb.nouveau.lucene4.health.IndexHealthCheck;
-import org.apache.couchdb.nouveau.lucene4.resources.AnalyzeResource;
-import org.apache.couchdb.nouveau.lucene4.resources.IndexResource;
-import org.apache.lucene.search.SearcherFactory;
-
-import io.dropwizard.core.setup.Environment;
-
-public final class Lucene4Bundle extends LuceneBundle {
-
-    @Override
-    public void run(final NouveauApplicationConfiguration configuration, final Environment environment) throws Exception {
-
-        // Serialization classes
-        environment.getObjectMapper().registerModule(new Lucene4Module());
-
-        // AnalyzeResource
-        environment.jersey().register(new AnalyzeResource());
-
-        // IndexResource
-        final SearcherFactory searcherFactory = new ParallelSearcherFactory(ForkJoinPool.commonPool());
-        final IndexResource indexResource = new IndexResource(indexManager, searcherFactory);
-        environment.jersey().register(indexResource);
-
-        // Health checks
-        environment.healthChecks().register("analyze4", new AnalyzeHealthCheck());
-        environment.healthChecks().register("index4", new IndexHealthCheck(indexResource));
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldDeserializer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldDeserializer.java
deleted file mode 100644
index 3bb72450b..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldDeserializer.java
+++ /dev/null
@@ -1,96 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.IOException;
-
-import org.apache.lucene.document.DoubleField;
-import org.apache.lucene.document.SortedDocValuesField;
-import org.apache.lucene.document.SortedSetDocValuesField;
-import org.apache.lucene.document.Field.Store;
-import org.apache.lucene.document.StoredField;
-import org.apache.lucene.document.StringField;
-import org.apache.lucene.document.TextField;
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.util.BytesRef;
-
-import com.fasterxml.jackson.core.JsonParseException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.JsonNode;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-
-class IndexableFieldDeserializer extends StdDeserializer<IndexableField> {
-
-    IndexableFieldDeserializer() {
-        this(null);
-    }
-
-    IndexableFieldDeserializer(Class<?> vc) {
-        super(vc);
-    }
-
-    @Override
-    public IndexableField deserialize(final JsonParser parser, final DeserializationContext context)
-            throws IOException, JsonProcessingException {
-        JsonNode node = parser.getCodec().readTree(parser);
-
-        final String type = node.get("@type").asText();
-        final String name = node.get("name").asText();
-
-        switch (type) {
-            case "double":
-                return new DoubleField(name, node.get("value").doubleValue(), asStore(node));
-            case "string":
-                return new StringField(name, node.get("value").asText(), asStore(node));
-            case "text":
-                return new TextField(name, node.get("value").asText(), asStore(node));
-            case "sorted_dv":
-                return new SortedDocValuesField(name, bytesRef(node));
-            case "sorted_set_dv":
-                return new SortedSetDocValuesField(name, bytesRef(node));
-            case "stored":
-                if (node.get("value").isDouble()) {
-                    return new StoredField(name, node.get("value").asDouble());
-                }
-                if (node.get("value").isTextual()) {
-                    final JsonNode value = node.get("value");
-                    if (node.has("encoded") && node.get("encoded").asBoolean()) {
-                        return new StoredField(name, new BytesRef(value.binaryValue()));
-                    } else {
-                        return new StoredField(name, value.asText());
-                    }
-                }
-                throw new JsonParseException(parser, node.get("value") + " not a valid value for a stored field");
-        }
-        throw new JsonParseException(parser, type + " not a valid type of field");
-    }
-
-    private Store asStore(JsonNode node) {
-        if (node.has("stored")) {
-            return node.get("stored").asBoolean() ? Store.YES : Store.NO;
-        }
-        return Store.NO;
-    }
-
-    private BytesRef bytesRef(final JsonNode node) throws IOException {
-        final JsonNode value = node.get("value");
-        if (node.has("encoded") && node.get("encoded").asBoolean()) {
-            return new BytesRef(value.binaryValue());
-        }
-        return new BytesRef(value.asText());
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldSerializer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldSerializer.java
deleted file mode 100644
index 13b83549a..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/IndexableFieldSerializer.java
+++ /dev/null
@@ -1,54 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.util.BytesRef;
-
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-
-class IndexableFieldSerializer extends StdSerializer<IndexableField> {
-
-    IndexableFieldSerializer() {
-        this(null);
-    }
-
-    IndexableFieldSerializer(Class<IndexableField> vc) {
-        super(vc);
-    }
-
-    @Override
-    public void serialize(final IndexableField field, final JsonGenerator gen, final SerializerProvider provider)
-            throws IOException {
-        gen.writeStartObject();
-        gen.writeStringField("@type", "stored");
-        gen.writeStringField("name", field.name());
-        if (field.numericValue() != null) {
-            gen.writeNumberField("value", (double) field.numericValue());
-        } else if (field.stringValue() != null) {
-            gen.writeStringField("value", field.stringValue());
-        } else if (field.binaryValue() != null) {
-            final BytesRef bytesRef = field.binaryValue();
-            gen.writeFieldName("value");
-            gen.writeBinary(bytesRef.bytes, bytesRef.offset, bytesRef.length);
-            gen.writeBooleanField("encoded", true);
-        }
-        gen.writeEndObject();
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactory.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactory.java
deleted file mode 100644
index f41734329..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactory.java
+++ /dev/null
@@ -1,142 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.function.Supplier;
-
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Response.Status;
-
-import org.apache.couchdb.nouveau.api.IndexDefinition;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.ar.ArabicAnalyzer;
-import org.apache.lucene.analysis.bg.BulgarianAnalyzer;
-import org.apache.lucene.analysis.ca.CatalanAnalyzer;
-import org.apache.lucene.analysis.cjk.CJKAnalyzer;
-import org.apache.lucene.analysis.standard.ClassicAnalyzer;
-import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
-import org.apache.lucene.analysis.core.KeywordAnalyzer;
-import org.apache.lucene.analysis.core.SimpleAnalyzer;
-import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
-import org.apache.lucene.analysis.cz.CzechAnalyzer;
-import org.apache.lucene.analysis.da.DanishAnalyzer;
-import org.apache.lucene.analysis.de.GermanAnalyzer;
-import org.apache.lucene.analysis.standard.UAX29URLEmailAnalyzer;
-import org.apache.lucene.analysis.en.EnglishAnalyzer;
-import org.apache.lucene.analysis.es.SpanishAnalyzer;
-import org.apache.lucene.analysis.eu.BasqueAnalyzer;
-import org.apache.lucene.analysis.fa.PersianAnalyzer;
-import org.apache.lucene.analysis.fi.FinnishAnalyzer;
-import org.apache.lucene.analysis.fr.FrenchAnalyzer;
-import org.apache.lucene.analysis.ga.IrishAnalyzer;
-import org.apache.lucene.analysis.gl.GalicianAnalyzer;
-import org.apache.lucene.analysis.hi.HindiAnalyzer;
-import org.apache.lucene.analysis.hu.HungarianAnalyzer;
-import org.apache.lucene.analysis.hy.ArmenianAnalyzer;
-import org.apache.lucene.analysis.id.IndonesianAnalyzer;
-import org.apache.lucene.analysis.it.ItalianAnalyzer;
-import org.apache.lucene.analysis.ja.JapaneseAnalyzer;
-import org.apache.lucene.analysis.lv.LatvianAnalyzer;
-import org.apache.lucene.analysis.nl.DutchAnalyzer;
-import org.apache.lucene.analysis.no.NorwegianAnalyzer;
-import org.apache.lucene.analysis.pl.PolishAnalyzer;
-import org.apache.lucene.analysis.pt.PortugueseAnalyzer;
-import org.apache.lucene.analysis.ro.RomanianAnalyzer;
-import org.apache.lucene.analysis.ru.RussianAnalyzer;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.analysis.sv.SwedishAnalyzer;
-import org.apache.lucene.analysis.th.ThaiAnalyzer;
-import org.apache.lucene.analysis.tr.TurkishAnalyzer;
-
-public final class Lucene4AnalyzerFactory {
-
-    public Lucene4AnalyzerFactory() {
-    }
-
-    public static Analyzer fromDefinition(final IndexDefinition indexDefinition) {
-        final Analyzer defaultAnalyzer = newAnalyzer(indexDefinition.getDefaultAnalyzer());
-        if (!indexDefinition.hasFieldAnalyzers()) {
-            return defaultAnalyzer;
-        }
-        final Map<String, Analyzer> fieldAnalyzers = new HashMap<String, Analyzer>();
-        for (Map.Entry<String, String> entry : indexDefinition.getFieldAnalyzers().entrySet()) {
-            fieldAnalyzers.put(entry.getKey(), newAnalyzer(entry.getValue()));
-        }
-        return new PerFieldAnalyzer(defaultAnalyzer, fieldAnalyzers);
-    }
-
-    private enum KnownAnalyzer {
-        // TODO support stopword list configuration
-        arabic(() -> new ArabicAnalyzer(Utils.LUCENE_VERSION)),
-        armenian(() -> new ArmenianAnalyzer(Utils.LUCENE_VERSION)),
-        basque(() -> new BasqueAnalyzer(Utils.LUCENE_VERSION)),
-        bulgarian(() -> new BulgarianAnalyzer(Utils.LUCENE_VERSION)),
-        catalan(() -> new CatalanAnalyzer(Utils.LUCENE_VERSION)),
-        chinese(() -> new SmartChineseAnalyzer(Utils.LUCENE_VERSION)),
-        cjk(() -> new CJKAnalyzer(Utils.LUCENE_VERSION)),
-        classic(() -> new ClassicAnalyzer(Utils.LUCENE_VERSION)),
-        czech(() -> new CzechAnalyzer(Utils.LUCENE_VERSION)),
-        danish(() -> new DanishAnalyzer(Utils.LUCENE_VERSION)),
-        dutch(() -> new DutchAnalyzer(Utils.LUCENE_VERSION)),
-        email(() -> new UAX29URLEmailAnalyzer(Utils.LUCENE_VERSION)),
-        english(() -> new EnglishAnalyzer(Utils.LUCENE_VERSION)),
-        finnish(() -> new FinnishAnalyzer(Utils.LUCENE_VERSION)),
-        french(() -> new FrenchAnalyzer(Utils.LUCENE_VERSION)),
-        galician(() -> new GalicianAnalyzer(Utils.LUCENE_VERSION)),
-        german(() -> new GermanAnalyzer(Utils.LUCENE_VERSION)),
-        hindi(() -> new HindiAnalyzer(Utils.LUCENE_VERSION)),
-        hungarian(() -> new HungarianAnalyzer(Utils.LUCENE_VERSION)),
-        indonesian(() -> new IndonesianAnalyzer(Utils.LUCENE_VERSION)),
-        irish(() -> new IrishAnalyzer(Utils.LUCENE_VERSION)),
-        italian(() -> new ItalianAnalyzer(Utils.LUCENE_VERSION)),
-        japanese(() -> new JapaneseAnalyzer(Utils.LUCENE_VERSION)),
-        keyword(() -> new KeywordAnalyzer()),
-        latvian(() -> new LatvianAnalyzer(Utils.LUCENE_VERSION)),
-        norwegian(() -> new NorwegianAnalyzer(Utils.LUCENE_VERSION)),
-        persian(() -> new PersianAnalyzer(Utils.LUCENE_VERSION)),
-        polish(() -> new PolishAnalyzer(Utils.LUCENE_VERSION)),
-        portugese(() -> new PortugueseAnalyzer(Utils.LUCENE_VERSION)),
-        romanian(() -> new RomanianAnalyzer(Utils.LUCENE_VERSION)),
-        russian(() -> new RussianAnalyzer(Utils.LUCENE_VERSION)),
-        simple(() -> new SimpleAnalyzer(Utils.LUCENE_VERSION)),
-        simple_asciifolding(() -> new SimpleAsciiFoldingAnalyzer(Utils.LUCENE_VERSION)),
-        spanish(() -> new SpanishAnalyzer(Utils.LUCENE_VERSION)),
-        standard(() -> new StandardAnalyzer(Utils.LUCENE_VERSION)),
-        swedish(() -> new SwedishAnalyzer(Utils.LUCENE_VERSION)),
-        thai(() -> new ThaiAnalyzer(Utils.LUCENE_VERSION)),
-        turkish(() -> new TurkishAnalyzer(Utils.LUCENE_VERSION)),
-        whitespace(() -> new WhitespaceAnalyzer(Utils.LUCENE_VERSION));
-
-        private final Supplier<? extends Analyzer> supplier;
-
-        private KnownAnalyzer(final Supplier<? extends Analyzer> supplier) {
-            this.supplier = supplier;
-        }
-
-        private Analyzer newInstance() {
-            return supplier.get();
-        }
-    }
-
-    public static Analyzer newAnalyzer(final String name) {
-        try {
-            return KnownAnalyzer.valueOf(name).newInstance();
-        } catch (IllegalArgumentException e) {
-            throw new WebApplicationException(name + " is not a valid analyzer name", Status.BAD_REQUEST);
-        }
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Index.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Index.java
deleted file mode 100644
index 19412f88e..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Index.java
+++ /dev/null
@@ -1,414 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.nio.file.NoSuchFileException;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Map.Entry;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Response.Status;
-
-import org.apache.couchdb.nouveau.api.After;
-import org.apache.couchdb.nouveau.api.DocumentDeleteRequest;
-import org.apache.couchdb.nouveau.api.DocumentUpdateRequest;
-import org.apache.couchdb.nouveau.api.DoubleRange;
-import org.apache.couchdb.nouveau.api.SearchHit;
-import org.apache.couchdb.nouveau.api.SearchRequest;
-import org.apache.couchdb.nouveau.api.SearchResults;
-import org.apache.couchdb.nouveau.core.IOUtils;
-import org.apache.couchdb.nouveau.core.Index;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.document.Document;
-import org.apache.lucene.document.Field.Store;
-import org.apache.lucene.document.StringField;
-import org.apache.lucene.facet.params.FacetSearchParams;
-import org.apache.lucene.facet.range.RangeAccumulator;
-import org.apache.lucene.facet.range.RangeFacetRequest;
-import org.apache.lucene.facet.search.CountFacetRequest;
-import org.apache.lucene.facet.search.FacetRequest;
-import org.apache.lucene.facet.search.FacetResult;
-import org.apache.lucene.facet.search.FacetResultNode;
-import org.apache.lucene.facet.search.FacetsCollector;
-import org.apache.lucene.facet.sortedset.SortedSetDocValuesAccumulator;
-import org.apache.lucene.facet.sortedset.SortedSetDocValuesReaderState;
-import org.apache.lucene.facet.taxonomy.CategoryPath;
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.index.Term;
-import org.apache.lucene.queryparser.classic.ParseException;
-import org.apache.lucene.search.FieldDoc;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.MultiCollector;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.ScoreDoc;
-import org.apache.lucene.search.SearcherManager;
-import org.apache.lucene.search.Sort;
-import org.apache.lucene.search.SortField;
-import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.TopDocs;
-import org.apache.lucene.search.TopFieldCollector;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.util.BytesRef;
-
-public class Lucene4Index extends Index<IndexableField> {
-
-    private static final Sort DEFAULT_SORT = new Sort(SortField.FIELD_SCORE,
-            new SortField("_id", SortField.Type.STRING));
-    private static final Pattern SORT_FIELD_RE = Pattern.compile("^([-+])?([\\.\\w]+)(?:<(\\w+)>)?$");
-
-    private final Analyzer analyzer;
-    private final IndexWriter writer;
-    private final SearcherManager searcherManager;
-
-    public Lucene4Index(final Analyzer analyzer, final IndexWriter writer, final long updateSeq,
-            final SearcherManager searcherManager) {
-        super(updateSeq);
-        this.analyzer = Objects.requireNonNull(analyzer);
-        this.writer = Objects.requireNonNull(writer);
-        this.searcherManager = Objects.requireNonNull(searcherManager);
-    }
-
-    @Override
-    public int doNumDocs() throws IOException {
-        return writer.numDocs();
-    }
-
-    @Override
-    public long doDiskSize() throws IOException {
-        final Directory dir = writer.getDirectory();
-        long result = 0;
-        for (final String name : dir.listAll()) {
-            try {
-                result += dir.fileLength(name);
-            } catch (final FileNotFoundException | NoSuchFileException e) {
-                // deleted while we were looping.
-            }
-        }
-        return result;
-    }
-
-    @Override
-    public void doUpdate(final String docId, final DocumentUpdateRequest<IndexableField> request) throws IOException {
-        final Term docIdTerm = docIdTerm(docId);
-        final Document doc = toDocument(docId, request);
-        writer.updateDocument(docIdTerm, doc);
-    }
-
-    @Override
-    public void doDelete(final String docId, final DocumentDeleteRequest request) throws IOException {
-        final Query query = docIdQuery(docId);
-        writer.deleteDocuments(query);
-    }
-
-    @Override
-    public boolean doCommit(final long updateSeq) throws IOException {
-        if (!writer.hasUncommittedChanges()) {
-            return false;
-        }
-        writer.setCommitData(Collections.singletonMap("update_seq", Long.toString(updateSeq)));
-        writer.commit();
-        return true;
-    }
-
-    @Override
-    public void doClose() throws IOException {
-        IOUtils.runAll(
-                () -> {
-                    searcherManager.close();
-                },
-                () -> {
-                    writer.rollback();
-                },
-                () -> {
-                    if (isDeleteOnClose()) {
-                        var dir = writer.getDirectory();
-                        for (final String name : dir.listAll()) {
-                            dir.deleteFile(name);
-                        }
-                    }
-                });
-    }
-
-    @Override
-    public SearchResults<IndexableField> doSearch(final SearchRequest request) throws IOException {
-        final Query query;
-        try {
-            query = newQueryParser().parse(request);
-        } catch (final ParseException e) {
-            throw new WebApplicationException(e.getMessage(), e, Status.BAD_REQUEST);
-        }
-
-        // Construct Collectors.
-        var hitCollector = hitCollector(request);
-
-        searcherManager.maybeRefreshBlocking();
-        final IndexSearcher searcher = searcherManager.acquire();
-        try {
-            FacetsCollector countsCollector = null;
-            if (request.hasCounts()) {
-                countsCollector = countsCollector(searcher.getIndexReader(), request.getCounts());
-            }
-            FacetsCollector rangesCollector = null;
-            if (request.hasRanges()) {
-                rangesCollector = rangesCollector(searcher.getIndexReader(), request.getRanges());
-            }
-
-            searcher.search(query, MultiCollector.wrap(hitCollector, countsCollector, rangesCollector));
-            return toSearchResults(request, searcher, hitCollector, countsCollector, rangesCollector);
-        } catch (IllegalStateException e) {
-            throw new WebApplicationException(e.getMessage(), e, Status.BAD_REQUEST);
-        } finally {
-            searcherManager.release(searcher);
-        }
-    }
-
-    private TopFieldCollector hitCollector(final SearchRequest searchRequest) throws IOException {
-        final Sort sort = toSort(searchRequest);
-
-        final After after = searchRequest.getAfter();
-        final FieldDoc fieldDoc;
-        if (after != null) {
-            fieldDoc = toFieldDoc(after);
-            if (getLastSortField(sort).getReverse()) {
-                fieldDoc.doc = 0;
-            } else {
-                fieldDoc.doc = Integer.MAX_VALUE;
-            }
-        } else {
-            fieldDoc = null;
-        }
-
-        return TopFieldCollector.create(
-                sort,
-                searchRequest.getLimit(),
-                fieldDoc,
-                true,
-                false,
-                false,
-                false);
-    }
-
-    private FacetsCollector countsCollector(final IndexReader reader, List<String> counts) throws IOException {
-        final SortedSetDocValuesReaderState state;
-        try {
-            state = new SortedSetDocValuesReaderState(reader);
-        } catch (final IllegalArgumentException e) {
-            if (e.getMessage().contains("was not indexed with SortedSetDocValues")) {
-                return null;
-            }
-            throw e;
-        }
-        final FacetRequest[] facetRequests = new FacetRequest[counts.size()];
-        for (int i = 0; i < facetRequests.length; i++) {
-            facetRequests[i] = new CountFacetRequest(new CategoryPath(counts.get(i)), Integer.MAX_VALUE);
-        }
-        var facetSearchParams = new FacetSearchParams(facetRequests);
-        var acc = new SortedSetDocValuesAccumulator(state, facetSearchParams);
-        return FacetsCollector.create(acc);
-    }
-
-    private FacetsCollector rangesCollector(final IndexReader reader, Map<String, List<DoubleRange>> ranges)
-            throws IOException {
-        final List<FacetRequest> facetRequests = new ArrayList<FacetRequest>(ranges.size());
-        for (final Entry<String, List<DoubleRange>> e : ranges.entrySet()) {
-            final org.apache.lucene.facet.range.DoubleRange[] out = new org.apache.lucene.facet.range.DoubleRange[e
-                    .getValue().size()];
-            for (int i = 0; i < out.length; i++) {
-                final DoubleRange in = e.getValue().get(i);
-                out[i] = new org.apache.lucene.facet.range.DoubleRange(
-                        in.getLabel(),
-                        in.getMin(),
-                        in.isMinInclusive(),
-                        in.getMax(),
-                        in.isMaxInclusive());
-            }
-            facetRequests.add(new RangeFacetRequest<org.apache.lucene.facet.range.DoubleRange>(
-                    e.getKey(), out));
-        }
-        var acc = new RangeAccumulator(facetRequests);
-        return FacetsCollector.create(acc);
-    }
-
-    private SortField getLastSortField(final Sort sort) {
-        final SortField[] sortFields = sort.getSort();
-        return sortFields[sortFields.length - 1];
-    }
-
-    private SearchResults<IndexableField> toSearchResults(final SearchRequest searchRequest, final IndexSearcher searcher,
-        TopFieldCollector hitCollector, FacetsCollector countsCollector, FacetsCollector rangesCollector) throws IOException {
-        final SearchResults<IndexableField> result = new SearchResults<IndexableField>();
-        collectHits(searcher, hitCollector.topDocs(), result);
-        if (searchRequest.hasCounts()) {
-            result.setCounts(convertFacets(countsCollector));
-        }
-        if (searchRequest.hasRanges()) {
-            result.setRanges(convertFacets(rangesCollector));
-        }
-        return result;
-    }
-
-    private void collectHits(final IndexSearcher searcher, final TopDocs topDocs, final SearchResults<IndexableField> searchResults)
-            throws IOException {
-        final List<SearchHit<IndexableField>> hits = new ArrayList<SearchHit<IndexableField>>(topDocs.scoreDocs.length);
-
-        for (final ScoreDoc scoreDoc : topDocs.scoreDocs) {
-            final Document doc = searcher.doc(scoreDoc.doc);
-
-            final List<IndexableField> fields = new ArrayList<IndexableField>(doc.getFields().size());
-            for (IndexableField field : doc.getFields()) {
-                if (!field.name().equals("_id")) {
-                    fields.add(field);
-                }
-            }
-
-            final After after = toAfter(((FieldDoc)scoreDoc));
-            hits.add(new SearchHit<IndexableField>(doc.get("_id"), after, fields));
-        }
-
-        searchResults.setTotalHits(topDocs.totalHits);
-        searchResults.setHits(hits);
-    }
-
-    private Map<String,Map<String,Number>> convertFacets(final FacetsCollector fc) throws IOException {
-        if (fc == null) {
-            return null;
-        }
-        final Map<String,Map<String,Number>> result = new HashMap<String,Map<String,Number>>();
-        for (final FacetResult facetResult : fc.getFacetResults()) {
-            final FacetResultNode node = facetResult.getFacetResultNode();
-            final Map<String, Number> m = result.computeIfAbsent(node.label.components[0], (k) -> new HashMap<String, Number>());
-            for (final FacetResultNode n : node.subResults) {
-                m.put(n.label.components[1], n.value);
-            }
-        }
-        return result;
-    }
-
-    // Ensure _id is final sort field so we can paginate.
-    private Sort toSort(final SearchRequest searchRequest) {
-        if (!searchRequest.hasSort()) {
-            return DEFAULT_SORT;
-        }
-
-        final List<String> sort = new ArrayList<String>(searchRequest.getSort());
-        final String last = sort.get(sort.size() - 1);
-        // Append _id field if not already present.
-        switch (last) {
-            case "-_id<string>":
-            case "_id<string>":
-                break;
-            default:
-                sort.add("_id<string>");
-        }
-        return convertSort(sort);
-    }
-
-    private Sort convertSort(final List<String> sort) {
-        final SortField[] fields = new SortField[sort.size()];
-        for (int i = 0; i < sort.size(); i++) {
-            fields[i] = convertSortField(sort.get(i));
-        }
-        return new Sort(fields);
-    }
-
-    private SortField convertSortField(final String sortString) {
-        final Matcher m = SORT_FIELD_RE.matcher(sortString);
-        if (!m.matches()) {
-            throw new WebApplicationException(
-                    sortString + " is not a valid sort parameter", Status.BAD_REQUEST);
-        }
-        final boolean reverse = "-".equals(m.group(1));
-        SortField.Type type = SortField.Type.DOUBLE;
-        if ("string".equals(m.group(3))) {
-            type = SortField.Type.STRING;
-        }
-        return new SortField(m.group(2), type, reverse);
-    }
-
-    private static Document toDocument(final String docId, final DocumentUpdateRequest<IndexableField> request) throws IOException {
-        final Document result = new Document();
-
-        // id
-        result.add(new StringField("_id", docId, Store.YES));
-
-        // partition (optional)
-        if (request.hasPartition()) {
-            result.add(new StringField("_partition", request.getPartition(), Store.NO));
-        }
-
-        for (IndexableField field : request.getFields()) {
-            // Underscore-prefix is reserved.
-            if (field.name().startsWith("_")) {
-                continue;
-            }
-            result.add(field);
-        }
-
-        return result;
-    }
-
-    private FieldDoc toFieldDoc(final After after) {
-        final Object[] fields = Arrays.copyOf(after.getFields(), after.getFields().length);
-        for (int i = 0; i < fields.length; i++) {
-            if (fields[i] instanceof byte[]) {
-                fields[i] = new BytesRef((byte[])fields[i]);
-            }
-        }
-        return new FieldDoc(0, Float.NaN, fields);
-    }
-
-    private After toAfter(final FieldDoc fieldDoc) {
-        final Object[] fields = Arrays.copyOf(fieldDoc.fields, fieldDoc.fields.length);
-        for (int i = 0; i < fields.length; i++) {
-            if (fields[i] instanceof BytesRef) {
-                fields[i] = toBytes((BytesRef)fields[i]);
-            }
-        }
-        return new After(fields);
-    }
-
-    private static byte[] toBytes(final BytesRef bytesRef) {
-        return Arrays.copyOfRange(bytesRef.bytes, bytesRef.offset, bytesRef.offset + bytesRef.length);
-    }
-
-    private static Query docIdQuery(final String docId) {
-        return new TermQuery(docIdTerm(docId));
-    }
-
-    private static Term docIdTerm(final String docId) {
-        return new Term("_id", docId);
-    }
-
-    public Lucene4QueryParser newQueryParser() {
-        return new Lucene4QueryParser("default", analyzer);
-    }
-
-    @Override
-    public String toString() {
-        return "Lucene4Index [analyzer=" + analyzer + ", writer=" + writer + ", searcherManager=" + searcherManager + "]";
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Module.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Module.java
deleted file mode 100644
index c080f16b4..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4Module.java
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.search.Query;
-
-import com.fasterxml.jackson.core.Version;
-import com.fasterxml.jackson.databind.module.SimpleModule;
-
-public class Lucene4Module extends SimpleModule {
-
-    public Lucene4Module() {
-        super("lucene4", Version.unknownVersion());
-
-        // IndexableField
-        addSerializer(IndexableField.class, new IndexableFieldSerializer());
-        addDeserializer(IndexableField.class, new IndexableFieldDeserializer());
-
-        // Query
-        addSerializer(Query.class, new QuerySerializer());
-        addDeserializer(Query.class, new QueryDeserializer());
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4QueryParser.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4QueryParser.java
deleted file mode 100644
index 3753973a3..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4QueryParser.java
+++ /dev/null
@@ -1,155 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.util.regex.Pattern;
-
-import org.apache.couchdb.nouveau.api.SearchRequest;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.queryparser.classic.ParseException;
-import org.apache.lucene.queryparser.classic.QueryParser;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.NumericRangeQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.TermQuery;
-import org.apache.lucene.search.BooleanClause.Occur;
-
-import org.apache.lucene.analysis.core.KeywordAnalyzer;
-
-class Lucene4QueryParser extends QueryParser {
-
-    private static final Pattern DOUBLE_REGEX;
-
-    static {
-        final String Digits = "(\\p{Digit}+)";
-        final String HexDigits = "(\\p{XDigit}+)";
-        // an exponent is 'e' or 'E' followed by an optionally
-        // signed decimal integer.
-        final String Exp = "[eE][+-]?" + Digits;
-        final String fpRegex = ("[\\x00-\\x20]*" + // Optional leading "whitespace"
-                "[+-]?(" + // Optional sign character
-                "NaN|" + // "NaN" string
-                "Infinity|" + // "Infinity" string
-
-                // A decimal floating-point string representing a finite positive
-                // number without a leading sign has at most five basic pieces:
-                // Digits . Digits ExponentPart FloatTypeSuffix
-                //
-                // Since this method allows integer-only strings as input
-                // in addition to strings of floating-point literals, the
-                // two sub-patterns below are simplifications of the grammar
-                // productions from section 3.10.2 of
-                // The Java Language Specification.
-
-                // Digits ._opt Digits_opt ExponentPart_opt FloatTypeSuffix_opt
-                "(((" + Digits + "(\\.)?(" + Digits + "?)(" + Exp + ")?)|" +
-
-                // . Digits ExponentPart_opt FloatTypeSuffix_opt
-                "(\\.(" + Digits + ")(" + Exp + ")?)|" +
-
-                // Hexadecimal strings
-                "((" +
-                // 0[xX] HexDigits ._opt BinaryExponent FloatTypeSuffix_opt
-                "(0[xX]" + HexDigits + "(\\.)?)|" +
-
-                // 0[xX] HexDigits_opt . HexDigits BinaryExponent FloatTypeSuffix_opt
-                "(0[xX]" + HexDigits + "?(\\.)" + HexDigits + ")" +
-
-                ")[pP][+-]?" + Digits + "))" +
-                "[fFdD]?))" +
-                "[\\x00-\\x20]*");// Optional trailing "whitespace"
-
-        DOUBLE_REGEX = Pattern.compile(fpRegex);
-    }
-
-    Lucene4QueryParser(final String defaultField, final Analyzer analyzer) {
-        super(Utils.LUCENE_VERSION, defaultField, analyzer);
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getFieldQuery(String field, String queryText, boolean quoted)
-            throws ParseException {
-        if (!quoted && isNumber(queryText)) {
-            return new TermQuery(Utils.doubleToTerm(field, Double.parseDouble(queryText)));
-        }
-        return super.getFieldQuery(field, queryText, quoted);
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getFuzzyQuery(String field, String termStr, float minSimilarity)
-            throws ParseException {
-        setLowercaseExpandedTerms(field);
-        return super.getFuzzyQuery(field, termStr, minSimilarity);
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getPrefixQuery(String field, String termStr) throws ParseException {
-        setLowercaseExpandedTerms(field);
-        return super.getPrefixQuery(field, termStr);
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getRangeQuery(String field, String lower, String upper,
-            boolean startInclusive, boolean endInclusive) throws ParseException {
-        if (isNumber(lower) && isNumber(upper)) {
-            return NumericRangeQuery.newDoubleRange(field, 8, Double.parseDouble(lower),
-                    Double.parseDouble(upper), startInclusive, endInclusive);
-        }
-        setLowercaseExpandedTerms(field);
-        return super.getRangeQuery(field, lower, upper, startInclusive, endInclusive);
-
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getRegexpQuery(String field, String termStr) throws ParseException {
-        setLowercaseExpandedTerms(field);
-        return super.getRegexpQuery(field, termStr);
-    }
-
-    @Override
-    protected org.apache.lucene.search.Query getWildcardQuery(String field, String termStr) throws ParseException {
-        setLowercaseExpandedTerms(field);
-        return super.getWildcardQuery(field, termStr);
-    }
-
-    private static boolean isNumber(String str) {
-        return DOUBLE_REGEX.matcher(str).matches();
-    }
-
-    private void setLowercaseExpandedTerms(String field) {
-        Analyzer analyzer = getAnalyzer();
-        if (analyzer instanceof PerFieldAnalyzer) {
-            setLowercaseExpandedTerms(((PerFieldAnalyzer) analyzer).getWrappedAnalyzer(field));
-        } else {
-            setLowercaseExpandedTerms(analyzer);
-        }
-    }
-
-    private void setLowercaseExpandedTerms(Analyzer analyzer) {
-        setLowercaseExpandedTerms(!(analyzer instanceof KeywordAnalyzer));
-    }
-
-    public Query parse(SearchRequest searchRequest) throws ParseException {
-        final Query q = (Query) parse(searchRequest.getQuery());
-        if (searchRequest.hasPartition()) {
-            final BooleanQuery result = new BooleanQuery();
-            result.add(new TermQuery(new org.apache.lucene.index.Term("_partition",
-                    searchRequest.getPartition())), Occur.MUST);
-            result.add(q, Occur.MUST);
-            return result;
-        }
-        return q;
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/ParallelSearcherFactory.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/ParallelSearcherFactory.java
deleted file mode 100644
index cd1334494..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/ParallelSearcherFactory.java
+++ /dev/null
@@ -1,36 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.IOException;
-import java.util.concurrent.ExecutorService;
-
-import org.apache.lucene.index.IndexReader;
-import org.apache.lucene.search.IndexSearcher;
-import org.apache.lucene.search.SearcherFactory;
-
-public class ParallelSearcherFactory extends SearcherFactory {
-
-    private ExecutorService executorService;
-
-    public ParallelSearcherFactory(ExecutorService executorService) {
-        this.executorService = executorService;
-    }
-
-    @Override
-    public IndexSearcher newSearcher(final IndexReader reader) throws IOException {
-        return new IndexSearcher(reader, executorService);
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/PerFieldAnalyzer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/PerFieldAnalyzer.java
deleted file mode 100644
index 1952d9e32..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/PerFieldAnalyzer.java
+++ /dev/null
@@ -1,39 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.util.Map;
-
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.AnalyzerWrapper;
-
-// This only exists because PerFieldAnalyzerWrapper#getWrappedAnalyzer is protected
-public class PerFieldAnalyzer extends AnalyzerWrapper {
-
-    private final Analyzer defaultAnalyzer;
-    private final Map<String, Analyzer> fieldAnalyzers;
-
-    public PerFieldAnalyzer(Analyzer defaultAnalyzer,
-            Map<String, Analyzer> fieldAnalyzers) {
-        super(Analyzer.PER_FIELD_REUSE_STRATEGY);
-        this.defaultAnalyzer = defaultAnalyzer;
-        this.fieldAnalyzers = fieldAnalyzers;
-    }
-
-    @Override
-    protected Analyzer getWrappedAnalyzer(String fieldName) {
-        return fieldAnalyzers.getOrDefault(fieldName, defaultAnalyzer);
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QueryDeserializer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QueryDeserializer.java
deleted file mode 100644
index ca222605c..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QueryDeserializer.java
+++ /dev/null
@@ -1,41 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.IOException;
-
-import org.apache.lucene.search.Query;
-
-import com.fasterxml.jackson.core.JacksonException;
-import com.fasterxml.jackson.core.JsonParser;
-import com.fasterxml.jackson.databind.DeserializationContext;
-import com.fasterxml.jackson.databind.deser.std.StdDeserializer;
-
-class QueryDeserializer extends StdDeserializer<Query> {
-
-    QueryDeserializer() {
-        this(null);
-    }
-
-    QueryDeserializer(Class<?> vc) {
-        super(vc);
-    }
-
-    @Override
-    public Query deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JacksonException {
-        // TODO Auto-generated method stub
-        throw new UnsupportedOperationException("Unimplemented method 'deserialize'");
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QuerySerializer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QuerySerializer.java
deleted file mode 100644
index 7c814f3ed..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/QuerySerializer.java
+++ /dev/null
@@ -1,88 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.IOException;
-
-import org.apache.lucene.index.Term;
-import org.apache.lucene.search.BooleanClause;
-import org.apache.lucene.search.BooleanQuery;
-import org.apache.lucene.search.MatchAllDocsQuery;
-import org.apache.lucene.search.PhraseQuery;
-import org.apache.lucene.search.Query;
-import org.apache.lucene.search.TermQuery;
-
-import com.fasterxml.jackson.core.JsonGenerationException;
-import com.fasterxml.jackson.core.JsonGenerator;
-import com.fasterxml.jackson.databind.SerializerProvider;
-import com.fasterxml.jackson.databind.ser.std.StdSerializer;
-
-class QuerySerializer extends StdSerializer<Query> {
-
-    QuerySerializer() {
-        this(null);
-    }
-
-    QuerySerializer(Class<Query> vc) {
-        super(vc);
-    }
-
-    @Override
-    public void serialize(final Query query, final JsonGenerator gen, final SerializerProvider provider)
-            throws IOException {
-        if (query instanceof TermQuery) {
-            final TermQuery termQuery = (TermQuery) query;
-            gen.writeStartObject();
-            gen.writeStringField("@type", "term");
-            gen.writeStringField("field", termQuery.getTerm().field());
-            gen.writeStringField("term", termQuery.getTerm().text());
-            gen.writeEndObject();
-        } else if (query instanceof MatchAllDocsQuery) {
-            gen.writeStartObject();
-            gen.writeStringField("@type", "match_all");
-            gen.writeEndObject();
-        } else if (query instanceof PhraseQuery) {
-            final PhraseQuery phraseQuery = (PhraseQuery) query;
-            gen.writeStartObject();
-            gen.writeStringField("@type", "phrase");
-            final Term[] terms = phraseQuery.getTerms();
-            gen.writeStringField("field", terms[0].field());
-            gen.writeFieldName("terms");
-            gen.writeStartArray();
-            for (final Term term : terms) {
-                gen.writeString(term.text());
-            }
-            gen.writeEndArray();
-            gen.writeEndObject();
-        } else if (query instanceof BooleanQuery) {
-            final BooleanQuery booleanQuery = (BooleanQuery) query;
-            gen.writeStartObject();
-            gen.writeStringField("@type", "boolean");
-            gen.writeFieldName("clauses");
-            gen.writeStartArray();
-            for (final BooleanClause clause : booleanQuery.clauses()) {
-                gen.writeStartObject();
-                gen.writeFieldName("query");
-                serialize(clause.getQuery(), gen, provider);
-                gen.writeStringField("occur", clause.getOccur().name().toLowerCase());
-                gen.writeEndObject();
-            }
-            gen.writeEndArray();
-            gen.writeEndObject();
-        } else {
-            throw new JsonGenerationException(query.getClass() + " not supported", gen);
-        }
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/SimpleAsciiFoldingAnalyzer.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/SimpleAsciiFoldingAnalyzer.java
deleted file mode 100644
index 568e6f3ff..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/SimpleAsciiFoldingAnalyzer.java
+++ /dev/null
@@ -1,38 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import java.io.Reader;
-
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.core.LetterTokenizer;
-import org.apache.lucene.analysis.core.LowerCaseFilter;
-import org.apache.lucene.analysis.miscellaneous.ASCIIFoldingFilter;
-import org.apache.lucene.util.Version;
-
-class SimpleAsciiFoldingAnalyzer extends Analyzer {
-
-    private Version version;
-
-    SimpleAsciiFoldingAnalyzer(final Version version) {
-        this.version = version;
-    }
-
-    @Override
-    protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
-        var tokenizer = new LetterTokenizer(version, reader);
-        return new TokenStreamComponents(tokenizer, new ASCIIFoldingFilter(new LowerCaseFilter(version, tokenizer)));
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Utils.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Utils.java
deleted file mode 100644
index 2fdc2cf02..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/core/Utils.java
+++ /dev/null
@@ -1,32 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import org.apache.lucene.index.Term;
-import org.apache.lucene.util.BytesRef;
-import org.apache.lucene.util.NumericUtils;
-import org.apache.lucene.util.Version;
-
-public class Utils {
-
-    public static final Version LUCENE_VERSION = Version.LUCENE_46;
-
-    static Term doubleToTerm(String field, Double value) {
-        var bytesRef = new BytesRef();
-        var asLong = NumericUtils.doubleToSortableLong(value);
-        NumericUtils.longToPrefixCoded(asLong, 0, bytesRef);
-        return new Term(field, bytesRef);
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/AnalyzeHealthCheck.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/AnalyzeHealthCheck.java
deleted file mode 100644
index 6f2cfc424..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/AnalyzeHealthCheck.java
+++ /dev/null
@@ -1,25 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.health;
-
-import org.apache.couchdb.nouveau.health.BaseAnalyzeHealthCheck;
-import org.apache.couchdb.nouveau.lucene4.resources.AnalyzeResource;
-
-public class AnalyzeHealthCheck extends BaseAnalyzeHealthCheck {
-
-    public AnalyzeHealthCheck() {
-        super(new AnalyzeResource());
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/IndexHealthCheck.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/IndexHealthCheck.java
deleted file mode 100644
index 6fa5657d4..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/health/IndexHealthCheck.java
+++ /dev/null
@@ -1,44 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.health;
-
-import java.util.Collections;
-
-import org.apache.couchdb.nouveau.api.DocumentUpdateRequest;
-import org.apache.couchdb.nouveau.health.BaseIndexHealthCheck;
-import org.apache.couchdb.nouveau.lucene4.resources.IndexResource;
-import org.apache.lucene.index.IndexableField;
-
-public class IndexHealthCheck extends BaseIndexHealthCheck<IndexableField> {
-
-    public IndexHealthCheck(IndexResource indexResource) {
-        super(indexResource);
-    }
-
-    @Override
-    protected String generateIndexName() {
-        return "___test4";
-    }
-
-    @Override
-    protected DocumentUpdateRequest<IndexableField>  generateDocumentUpdateRequest() {
-        return new DocumentUpdateRequest<IndexableField>(1, null, Collections.emptyList());
-    }
-
-    @Override
-    protected int getLuceneMajor() {
-        return 4;
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/AnalyzeResource.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/AnalyzeResource.java
deleted file mode 100644
index eebb3c090..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/AnalyzeResource.java
+++ /dev/null
@@ -1,76 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.resources;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotNull;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.WebApplicationException;
-import jakarta.ws.rs.core.Response.Status;
-import jakarta.ws.rs.core.MediaType;
-
-import org.apache.couchdb.nouveau.api.AnalyzeRequest;
-import org.apache.couchdb.nouveau.api.AnalyzeResponse;
-import org.apache.couchdb.nouveau.lucene4.core.Lucene4AnalyzerFactory;
-import org.apache.couchdb.nouveau.resources.BaseAnalyzeResource;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.TokenStream;
-import org.apache.lucene.analysis.tokenattributes.CharTermAttribute;
-
-import com.codahale.metrics.annotation.ExceptionMetered;
-import com.codahale.metrics.annotation.Metered;
-import com.codahale.metrics.annotation.ResponseMetered;
-
-@Path("/4/analyze")
-@Metered
-@ResponseMetered
-@ExceptionMetered(cause = IOException.class)
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class AnalyzeResource extends BaseAnalyzeResource {
-
-    @Override
-    @POST
-    public AnalyzeResponse analyzeText(@NotNull @Valid AnalyzeRequest request) throws IOException {
-        try {
-            final List<String> tokens = tokenize(Lucene4AnalyzerFactory.newAnalyzer(request.getAnalyzer()),
-                    request.getText());
-            return new AnalyzeResponse(tokens);
-        } catch (IllegalArgumentException e) {
-            throw new WebApplicationException(request.getAnalyzer() + " not a valid analyzer",
-                    Status.BAD_REQUEST);
-        }
-    }
-
-    private List<String> tokenize(final Analyzer analyzer, final String text) throws IOException {
-        final List<String> result = new ArrayList<String>(10);
-        try (final TokenStream tokenStream = analyzer.tokenStream("default", text)) {
-            tokenStream.reset();
-            while (tokenStream.incrementToken()) {
-                final CharTermAttribute term = tokenStream.getAttribute(CharTermAttribute.class);
-                result.add(term.toString());
-            }
-            tokenStream.end();
-        }
-        return result;
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/IndexResource.java b/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/IndexResource.java
deleted file mode 100644
index 02abd203c..000000000
--- a/nouveau/lucene4/src/main/java/org/apache/couchdb/nouveau/lucene4/resources/IndexResource.java
+++ /dev/null
@@ -1,139 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.resources;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.Map;
-
-import jakarta.validation.Valid;
-import jakarta.validation.constraints.NotNull;
-import jakarta.ws.rs.Consumes;
-import jakarta.ws.rs.DELETE;
-import jakarta.ws.rs.GET;
-import jakarta.ws.rs.POST;
-import jakarta.ws.rs.PUT;
-import jakarta.ws.rs.Path;
-import jakarta.ws.rs.PathParam;
-import jakarta.ws.rs.Produces;
-import jakarta.ws.rs.core.MediaType;
-
-import org.apache.couchdb.nouveau.api.DocumentDeleteRequest;
-import org.apache.couchdb.nouveau.api.DocumentUpdateRequest;
-import org.apache.couchdb.nouveau.api.IndexDefinition;
-import org.apache.couchdb.nouveau.api.IndexInfo;
-import org.apache.couchdb.nouveau.api.SearchRequest;
-import org.apache.couchdb.nouveau.api.SearchResults;
-import org.apache.couchdb.nouveau.core.IndexLoader;
-import org.apache.couchdb.nouveau.core.IndexManager;
-import org.apache.couchdb.nouveau.lucene4.core.Lucene4AnalyzerFactory;
-import org.apache.couchdb.nouveau.lucene4.core.Lucene4Index;
-import org.apache.couchdb.nouveau.lucene4.core.Utils;
-import org.apache.couchdb.nouveau.resources.BaseIndexResource;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.search.SearcherFactory;
-import org.apache.lucene.search.SearcherManager;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.FSDirectory;
-
-import com.codahale.metrics.annotation.ExceptionMetered;
-import com.codahale.metrics.annotation.Metered;
-import com.codahale.metrics.annotation.ResponseMetered;;
-
-@Path("/4/index/{name}")
-@Metered
-@ResponseMetered
-@ExceptionMetered(cause = IOException.class)
-@Consumes(MediaType.APPLICATION_JSON)
-@Produces(MediaType.APPLICATION_JSON)
-public class IndexResource extends BaseIndexResource<IndexableField> {
-
-    private final SearcherFactory searcherFactory;
-
-    public IndexResource(final IndexManager indexManager, final SearcherFactory searcherFactory) {
-        super(indexManager);
-        this.searcherFactory = searcherFactory;
-    }
-
-    @PUT
-    @Override
-    public void createIndex(@PathParam("name") String name, @NotNull @Valid IndexDefinition indexDefinition)
-            throws IOException {
-        super.createIndex(name, indexDefinition);
-    }
-
-    @DELETE
-    @Path("/doc/{docId}")
-    @Override
-    public void deleteDoc(@PathParam("name") String name, @PathParam("docId") String docId,
-            @NotNull @Valid DocumentDeleteRequest request) throws Exception {
-        super.deleteDoc(name, docId, request);
-    }
-
-    @DELETE
-    @Override
-    public void deletePath(@PathParam("name") String path, @Valid List<String> exclusions) throws IOException {
-        super.deletePath(path, exclusions);
-    }
-
-    @GET
-    @Override
-    public IndexInfo indexInfo(@PathParam("name") String name) throws Exception {
-        return super.indexInfo(name);
-    }
-
-    @POST
-    @Path("/search")
-    @Override
-    public SearchResults<IndexableField> searchIndex(@PathParam("name") String name,
-            @NotNull @Valid SearchRequest request)
-            throws Exception {
-        return super.searchIndex(name, request);
-    }
-
-    @PUT
-    @Path("/doc/{docId}")
-    @Override
-    public void updateDoc(@PathParam("name") String name, @PathParam("docId") String docId,
-            @NotNull @Valid DocumentUpdateRequest<IndexableField> request)
-            throws Exception {
-        super.updateDoc(name, docId, request);
-    }
-
-    @Override
-    protected IndexLoader<IndexableField> indexLoader() {
-        return (path, indexDefinition) -> {
-            final Analyzer analyzer = Lucene4AnalyzerFactory.fromDefinition(indexDefinition);
-            final Directory dir = FSDirectory.open(path.toFile());
-            final IndexWriterConfig config = new IndexWriterConfig(Utils.LUCENE_VERSION, analyzer);
-            config.setUseCompoundFile(false);
-            final IndexWriter writer = new IndexWriter(dir, config);
-            final long updateSeq = getUpdateSeq(writer);
-            final SearcherManager searcherManager = new SearcherManager(writer, true, searcherFactory);
-            return new Lucene4Index(analyzer, writer, updateSeq, searcherManager);
-        };
-    }
-
-    private static long getUpdateSeq(final IndexWriter writer) throws IOException {
-        final Map<String, String> commitData = writer.getCommitData();
-        if (commitData == null) {
-            return 0L;
-        }
-        return Long.parseLong(commitData.getOrDefault("update_seq", "0"));
-    }
-
-}
diff --git a/nouveau/lucene4/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle b/nouveau/lucene4/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle
deleted file mode 100644
index 8fe744dd9..000000000
--- a/nouveau/lucene4/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle
+++ /dev/null
@@ -1,16 +0,0 @@
-#  Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  See the NOTICE file distributed with
-#  this work for additional information regarding copyright ownership.
-#  The ASF licenses this file to You under the Apache License, Version 2.0
-#  (the "License"); you may not use this file except in compliance with
-#  the License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-org.apache.couchdb.nouveau.lucene4.Lucene4Bundle
diff --git a/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactoryTest.java b/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactoryTest.java
deleted file mode 100644
index 3a41189bd..000000000
--- a/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4AnalyzerFactoryTest.java
+++ /dev/null
@@ -1,255 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.analysis.ar.ArabicAnalyzer;
-import org.apache.lucene.analysis.bg.BulgarianAnalyzer;
-import org.apache.lucene.analysis.ca.CatalanAnalyzer;
-import org.apache.lucene.analysis.cjk.CJKAnalyzer;
-import org.apache.lucene.analysis.standard.ClassicAnalyzer;
-import org.apache.lucene.analysis.cn.smart.SmartChineseAnalyzer;
-import org.apache.lucene.analysis.core.KeywordAnalyzer;
-import org.apache.lucene.analysis.core.SimpleAnalyzer;
-import org.apache.lucene.analysis.core.WhitespaceAnalyzer;
-import org.apache.lucene.analysis.cz.CzechAnalyzer;
-import org.apache.lucene.analysis.da.DanishAnalyzer;
-import org.apache.lucene.analysis.de.GermanAnalyzer;
-import org.apache.lucene.analysis.standard.UAX29URLEmailAnalyzer;
-import org.apache.lucene.analysis.en.EnglishAnalyzer;
-import org.apache.lucene.analysis.es.SpanishAnalyzer;
-import org.apache.lucene.analysis.eu.BasqueAnalyzer;
-import org.apache.lucene.analysis.fa.PersianAnalyzer;
-import org.apache.lucene.analysis.fi.FinnishAnalyzer;
-import org.apache.lucene.analysis.fr.FrenchAnalyzer;
-import org.apache.lucene.analysis.ga.IrishAnalyzer;
-import org.apache.lucene.analysis.gl.GalicianAnalyzer;
-import org.apache.lucene.analysis.hi.HindiAnalyzer;
-import org.apache.lucene.analysis.hu.HungarianAnalyzer;
-import org.apache.lucene.analysis.hy.ArmenianAnalyzer;
-import org.apache.lucene.analysis.id.IndonesianAnalyzer;
-import org.apache.lucene.analysis.it.ItalianAnalyzer;
-import org.apache.lucene.analysis.ja.JapaneseAnalyzer;
-import org.apache.lucene.analysis.lv.LatvianAnalyzer;
-import org.apache.lucene.analysis.nl.DutchAnalyzer;
-import org.apache.lucene.analysis.no.NorwegianAnalyzer;
-import org.apache.lucene.analysis.pl.PolishAnalyzer;
-import org.apache.lucene.analysis.pt.PortugueseAnalyzer;
-import org.apache.lucene.analysis.ro.RomanianAnalyzer;
-import org.apache.lucene.analysis.ru.RussianAnalyzer;
-import org.apache.lucene.analysis.standard.StandardAnalyzer;
-import org.apache.lucene.analysis.sv.SwedishAnalyzer;
-import org.apache.lucene.analysis.th.ThaiAnalyzer;
-import org.apache.lucene.analysis.tr.TurkishAnalyzer;
-import org.junit.jupiter.api.Test;
-
-public class Lucene4AnalyzerFactoryTest {
-
-    @Test
-    public void testkeyword() throws Exception {
-        assertAnalyzer("keyword", KeywordAnalyzer.class);
-    }
-
-    @Test
-    public void testsimple() throws Exception {
-        assertAnalyzer("simple", SimpleAnalyzer.class);
-    }
-
-    @Test
-    public void testwhitespace() throws Exception {
-        assertAnalyzer("whitespace", WhitespaceAnalyzer.class);
-    }
-
-    @Test
-    public void testarabic() throws Exception {
-        assertAnalyzer("arabic", ArabicAnalyzer.class);
-    }
-
-    @Test
-    public void testbulgarian() throws Exception {
-        assertAnalyzer("bulgarian", BulgarianAnalyzer.class);
-    }
-
-    @Test
-    public void testcatalan() throws Exception {
-        assertAnalyzer("catalan", CatalanAnalyzer.class);
-    }
-
-    @Test
-    public void testcjk() throws Exception {
-        assertAnalyzer("cjk", CJKAnalyzer.class);
-    }
-
-    @Test
-    public void testchinese() throws Exception {
-        assertAnalyzer("chinese", SmartChineseAnalyzer.class);
-    }
-
-    @Test
-    public void testczech() throws Exception {
-        assertAnalyzer("czech", CzechAnalyzer.class);
-    }
-
-    @Test
-    public void testdanish() throws Exception {
-        assertAnalyzer("danish", DanishAnalyzer.class);
-    }
-
-    @Test
-    public void testgerman() throws Exception {
-        assertAnalyzer("german", GermanAnalyzer.class);
-    }
-
-    @Test
-    public void testenglish() throws Exception {
-        assertAnalyzer("english", EnglishAnalyzer.class);
-    }
-
-    @Test
-    public void testspanish() throws Exception {
-        assertAnalyzer("spanish", SpanishAnalyzer.class);
-    }
-
-    @Test
-    public void testbasque() throws Exception {
-        assertAnalyzer("basque", BasqueAnalyzer.class);
-    }
-
-    @Test
-    public void testpersian() throws Exception {
-        assertAnalyzer("persian", PersianAnalyzer.class);
-    }
-
-    @Test
-    public void testfinnish() throws Exception {
-        assertAnalyzer("finnish", FinnishAnalyzer.class);
-    }
-
-    @Test
-    public void testfrench() throws Exception {
-        assertAnalyzer("french", FrenchAnalyzer.class);
-    }
-
-    @Test
-    public void testirish() throws Exception {
-        assertAnalyzer("irish", IrishAnalyzer.class);
-    }
-
-    @Test
-    public void testgalician() throws Exception {
-        assertAnalyzer("galician", GalicianAnalyzer.class);
-    }
-
-    @Test
-    public void testhindi() throws Exception {
-        assertAnalyzer("hindi", HindiAnalyzer.class);
-    }
-
-    @Test
-    public void testhungarian() throws Exception {
-        assertAnalyzer("hungarian", HungarianAnalyzer.class);
-    }
-
-    @Test
-    public void testarmenian() throws Exception {
-        assertAnalyzer("armenian", ArmenianAnalyzer.class);
-    }
-
-    @Test
-    public void testindonesian() throws Exception {
-        assertAnalyzer("indonesian", IndonesianAnalyzer.class);
-    }
-
-    @Test
-    public void testitalian() throws Exception {
-        assertAnalyzer("italian", ItalianAnalyzer.class);
-    }
-
-    @Test
-    public void testjapanese() throws Exception {
-        assertAnalyzer("japanese", JapaneseAnalyzer.class);
-    }
-
-    @Test
-    public void testlatvian() throws Exception {
-        assertAnalyzer("latvian", LatvianAnalyzer.class);
-    }
-
-    @Test
-    public void testdutch() throws Exception {
-        assertAnalyzer("dutch", DutchAnalyzer.class);
-    }
-
-    @Test
-    public void testnorwegian() throws Exception {
-        assertAnalyzer("norwegian", NorwegianAnalyzer.class);
-    }
-
-    @Test
-    public void testpolish() throws Exception {
-        assertAnalyzer("polish", PolishAnalyzer.class);
-    }
-
-    @Test
-    public void testportugese() throws Exception {
-        assertAnalyzer("portugese", PortugueseAnalyzer.class);
-    }
-
-    @Test
-    public void testromanian() throws Exception {
-        assertAnalyzer("romanian", RomanianAnalyzer.class);
-    }
-
-    @Test
-    public void testrussian() throws Exception {
-        assertAnalyzer("russian", RussianAnalyzer.class);
-    }
-
-    @Test
-    public void testclassic() throws Exception {
-        assertAnalyzer("classic", ClassicAnalyzer.class);
-    }
-
-    @Test
-    public void teststandard() throws Exception {
-        assertAnalyzer("standard", StandardAnalyzer.class);
-    }
-
-    @Test
-    public void testemail() throws Exception {
-        assertAnalyzer("email", UAX29URLEmailAnalyzer.class);
-    }
-
-    @Test
-    public void testswedish() throws Exception {
-        assertAnalyzer("swedish", SwedishAnalyzer.class);
-    }
-
-    @Test
-    public void testthai() throws Exception {
-        assertAnalyzer("thai", ThaiAnalyzer.class);
-    }
-
-    @Test
-    public void testturkish() throws Exception {
-        assertAnalyzer("turkish", TurkishAnalyzer.class);
-    }
-
-    private void assertAnalyzer(final String name, final Class<? extends Analyzer> clazz) throws Exception {
-        assertThat(Lucene4AnalyzerFactory.newAnalyzer(name)).isInstanceOf(clazz);
-    }
-
-}
diff --git a/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4IndexTest.java b/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4IndexTest.java
deleted file mode 100644
index 519c6411d..000000000
--- a/nouveau/lucene4/src/test/java/org/apache/couchdb/nouveau/lucene4/core/Lucene4IndexTest.java
+++ /dev/null
@@ -1,111 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene4.core;
-
-import static org.assertj.core.api.Assertions.assertThat;
-
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collection;
-import java.util.List;
-import java.util.Map;
-
-import org.apache.couchdb.nouveau.api.DocumentUpdateRequest;
-import org.apache.couchdb.nouveau.api.DoubleRange;
-import org.apache.couchdb.nouveau.api.SearchRequest;
-import org.apache.couchdb.nouveau.api.SearchResults;
-import org.apache.couchdb.nouveau.core.BaseIndexTest;
-import org.apache.couchdb.nouveau.core.Index;
-import org.apache.couchdb.nouveau.core.IndexLoader;
-import org.apache.lucene.analysis.Analyzer;
-import org.apache.lucene.document.DoubleDocValuesField;
-import org.apache.lucene.document.Field.Store;
-import org.apache.lucene.document.SortedSetDocValuesField;
-import org.apache.lucene.document.StringField;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.index.IndexableField;
-import org.apache.lucene.search.SearcherManager;
-import org.apache.lucene.store.Directory;
-import org.apache.lucene.store.FSDirectory;
-import org.apache.lucene.util.BytesRef;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-public class Lucene4IndexTest extends BaseIndexTest<IndexableField> {
-
-    @Override
-    protected IndexLoader<IndexableField> indexLoader() {
-        return (path, indexDefinition) -> {
-            final Analyzer analyzer = Lucene4AnalyzerFactory.fromDefinition(indexDefinition);
-            final Directory dir = FSDirectory.open(path.toFile());
-            final IndexWriterConfig config = new IndexWriterConfig(Utils.LUCENE_VERSION, analyzer);
-            config.setUseCompoundFile(false);
-            final IndexWriter writer = new IndexWriter(dir, config);
-            final SearcherManager searcherManager = new SearcherManager(writer, true, null);
-            return new Lucene4Index(analyzer, writer, 0L, searcherManager);
-        };
-    }
-
-    protected IndexableField stringField(final String name, final String value) {
-        return new StringField(name, value, Store.NO);
-    }
-
-    @Test
-    public void testCounts(@TempDir Path path) throws IOException {
-        Index<IndexableField> index = setup(path);
-        try {
-            final int count = 100;
-            for (int i = 1; i <= count; i++) {
-                final Collection<IndexableField> fields = List
-                        .of(new SortedSetDocValuesField("$facets_sorted_doc_values", new BytesRef("bar\u001Fbaz")));
-                final DocumentUpdateRequest<IndexableField> request = new DocumentUpdateRequest<IndexableField>(i, null,
-                        fields);
-                index.update("doc" + i, request);
-            }
-            final SearchRequest request = new SearchRequest();
-            request.setQuery("*:*");
-            request.setCounts(List.of("bar"));
-            final SearchResults<IndexableField> results = index.search(request);
-            assertThat(results.getCounts()).isEqualTo(Map.of("bar", Map.of("baz", (double) count)));
-        } finally {
-            cleanup(index);
-        }
-    }
-
-    @Test
-    public void testRanges(@TempDir Path path) throws IOException {
-        Index<IndexableField> index = setup(path);
-        try {
-            final int count = 100;
-            for (int i = 1; i <= count; i++) {
-                final Collection<IndexableField> fields = List.of(new DoubleDocValuesField("bar", i));
-                final DocumentUpdateRequest<IndexableField> request = new DocumentUpdateRequest<IndexableField>(i, null,
-                        fields);
-                index.update("doc" + i, request);
-            }
-            final SearchRequest request = new SearchRequest();
-            request.setQuery("*:*");
-            request.setRanges(Map.of("bar",
-                    List.of(new DoubleRange("low", 0.0, true, (double) count / 2, true),
-                            new DoubleRange("high", (double) count / 2, true, (double) count, true))));
-            final SearchResults<IndexableField> results = index.search(request);
-            assertThat(results.getRanges()).isEqualTo(
-                    Map.of("bar", Map.of("low", (double) count / 2, "high", (double) count / 2 + 1)));
-        } finally {
-            cleanup(index);
-        }
-    }
-
-}
diff --git a/nouveau/lucene4/src/test/resources/index.zip b/nouveau/lucene4/src/test/resources/index.zip
deleted file mode 100644
index 86fd09b65..000000000
Binary files a/nouveau/lucene4/src/test/resources/index.zip and /dev/null differ
diff --git a/nouveau/lucene9/pom.xml b/nouveau/lucene9/pom.xml
deleted file mode 100644
index 9047633aa..000000000
--- a/nouveau/lucene9/pom.xml
+++ /dev/null
@@ -1,167 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.apache.couchdb.nouveau</groupId>
-  <artifactId>lucene9</artifactId>
-  <name>${project.artifactId}</name>
-  <version>1.0-SNAPSHOT</version>
-  <description>Lucene 9 index classes</description>
-  <inceptionYear>2023</inceptionYear>
-
-  <parent>
-    <groupId>org.apache.couchdb.nouveau</groupId>
-    <artifactId>parent</artifactId>
-    <version>1.0-SNAPSHOT</version>
-  </parent>
-
-  <properties>
-    <lucene.version>9.5.0</lucene.version>
-  </properties>
-
-  <dependencies>
-
-    <!-- Base -->
-    <dependency>
-      <groupId>org.apache.couchdb.nouveau</groupId>
-      <artifactId>base</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <!-- Base tests -->
-    <dependency>
-      <groupId>org.apache.couchdb.nouveau</groupId>
-      <artifactId>base</artifactId>
-      <version>${project.version}</version>
-      <classifier>tests</classifier>
-      <type>test-jar</type>
-      <scope>test</scope>
-    </dependency>
-
-    <!-- Dropwizard -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-core</artifactId>
-    </dependency>
-
-    <dependency>
-      <groupId>com.fasterxml.jackson.core</groupId>
-      <artifactId>jackson-databind</artifactId>
-    </dependency>
-
-    <!-- Lucene -->
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-core</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-queryparser</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analysis-common</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analysis-stempel</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analysis-smartcn</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-analysis-kuromoji</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-facet</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-    <dependency>
-      <groupId>org.apache.lucene</groupId>
-      <artifactId>lucene-misc</artifactId>
-      <version>${lucene.version}</version>
-    </dependency>
-
-    <!-- Test -->
-    <dependency>
-	  <groupId>org.junit.jupiter</groupId>
-	  <artifactId>junit-jupiter</artifactId>
-	  <scope>test</scope>
-	</dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.assertj</groupId>
-      <artifactId>assertj-core</artifactId>
-      <version>3.22.0</version>
-      <scope>test</scope>
-    </dependency>
-
-  </dependencies>
-
-  <build>
-    <defaultGoal>install</defaultGoal>
-    <plugins>
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-shade-plugin</artifactId>
-        <configuration>
-          <shadedArtifactAttached>true</shadedArtifactAttached>
-          <shadedClassifierName>dist</shadedClassifierName>
-          <createSourcesJar>true</createSourcesJar>
-          <shadeSourcesContent>true</shadeSourcesContent>
-          <filters>
-            <filter>
-              <artifact>*:*</artifact>
-              <excludes>
-                <exclude>module-info.class</exclude>
-                <exclude>module-info.java</exclude>
-                <exclude>META-INF/LICENSE.txt</exclude>
-                <exclude>META-INF/NOTICE.txt</exclude>
-                <exclude>META-INF/MANIFEST.MF</exclude>
-                <exclude>overview.html</exclude>
-                <exclude>**/package.html</exclude>
-              </excludes>
-            </filter>
-          </filters>
-          <artifactSet>
-            <includes>
-              <include>org.apache.lucene:*</include>
-              <include>com.carrotsearch:hppc</include>
-            </includes>
-          </artifactSet>
-          <transformers>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
-              <manifestEntries>
-                <Multi-Release>true</Multi-Release>
-              </manifestEntries>
-            </transformer>
-            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
-              <resource>META-INF/versions</resource>
-            </transformer>
-          </transformers>
-        </configuration>
-        <executions>
-          <execution>
-            <phase>package</phase>
-            <goals>
-              <goal>shade</goal>
-            </goals>
-          </execution>
-        </executions>
-      </plugin>
-    </plugins>
-  </build>
-</project>
diff --git a/nouveau/lucene9/src/main/assembly/dist.xml b/nouveau/lucene9/src/main/assembly/dist.xml
deleted file mode 100644
index 68eaeaff0..000000000
--- a/nouveau/lucene9/src/main/assembly/dist.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<!--
-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.
--->
-<assembly>
-  <id>dist</id>
-  <formats>
-    <format>jar</format>
-  </formats>
-  <includeBaseDirectory>false</includeBaseDirectory>
-  <dependencySets>
-    <dependencySet>
-      <outputDirectory>/</outputDirectory>
-      <useProjectArtifact>true</useProjectArtifact>
-      <unpack>true</unpack>
-      <scope>provided</scope>
-    </dependencySet>
-  </dependencySets>
-</assembly>
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Bundle.java b/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Bundle.java
deleted file mode 100644
index 4aec993aa..000000000
--- a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Bundle.java
+++ /dev/null
@@ -1,52 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene9;
-
-import java.util.concurrent.ForkJoinPool;
-
-import org.apache.couchdb.nouveau.LuceneBundle;
-import org.apache.couchdb.nouveau.NouveauApplicationConfiguration;
-import org.apache.couchdb.nouveau.lucene9.core.Lucene9Module;
-import org.apache.couchdb.nouveau.lucene9.core.ParallelSearcherFactory;
-import org.apache.couchdb.nouveau.lucene9.health.AnalyzeHealthCheck;
-import org.apache.couchdb.nouveau.lucene9.health.IndexHealthCheck;
-import org.apache.couchdb.nouveau.lucene9.resources.AnalyzeResource;
-import org.apache.couchdb.nouveau.lucene9.resources.IndexResource;
-import org.apache.lucene.search.SearcherFactory;
-
-import io.dropwizard.core.setup.Environment;
-
-public final class Lucene9Bundle extends LuceneBundle {
-
-    @Override
-    public void run(final NouveauApplicationConfiguration configuration, final Environment environment)
-            throws Exception {
-
-        // Serialization classes
-        environment.getObjectMapper().registerModule(new Lucene9Module());
-
-        // AnalyzeResource
-        environment.jersey().register(new AnalyzeResource());
-
-        // IndexResource
-        final SearcherFactory searcherFactory = new ParallelSearcherFactory(ForkJoinPool.commonPool());
-        final IndexResource indexResource = new IndexResource(indexManager, searcherFactory);
-        environment.jersey().register(indexResource);
-
-        // Health checks
-        environment.healthChecks().register("analyze9", new AnalyzeHealthCheck());
-        environment.healthChecks().register("index9", new IndexHealthCheck(indexResource));
-    }
-
-}
diff --git a/nouveau/lucene9/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle b/nouveau/lucene9/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle
deleted file mode 100644
index 64ad96f64..000000000
--- a/nouveau/lucene9/src/main/resources/META-INF/services/org.apache.couchdb.nouveau.LuceneBundle
+++ /dev/null
@@ -1,16 +0,0 @@
-#  Licensed to the Apache Software Foundation (ASF) under one or more
-#  contributor license agreements.  See the NOTICE file distributed with
-#  this work for additional information regarding copyright ownership.
-#  The ASF licenses this file to You under the Apache License, Version 2.0
-#  (the "License"); you may not use this file except in compliance with
-#  the License.  You may obtain a copy of the License at
-#
-#       http://www.apache.org/licenses/LICENSE-2.0
-#
-#  Unless required by applicable law or agreed to in writing, software
-#  distributed under the License is distributed on an "AS IS" BASIS,
-#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-#  See the License for the specific language governing permissions and
-#  limitations under the License.
-
-org.apache.couchdb.nouveau.lucene9.Lucene9Bundle
diff --git a/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/CaffeineCacheTest.java b/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/CaffeineCacheTest.java
deleted file mode 100644
index cfc5ded86..000000000
--- a/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/CaffeineCacheTest.java
+++ /dev/null
@@ -1,98 +0,0 @@
-//
-// 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 org.apache.couchdb.nouveau.lucene9.core;
-
-import static org.assertj.core.api.Assertions.*;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.Random;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.atomic.AtomicBoolean;
-
-import org.apache.lucene.document.Document;
-import org.apache.lucene.index.IndexWriter;
-import org.apache.lucene.index.IndexWriterConfig;
-import org.apache.lucene.store.FSDirectory;
-import org.junit.jupiter.api.Tag;
-import org.junit.jupiter.api.Test;
-import org.junit.jupiter.api.io.TempDir;
-
-import com.github.benmanes.caffeine.cache.CacheLoader;
-import com.github.benmanes.caffeine.cache.Caffeine;
-import com.github.benmanes.caffeine.cache.LoadingCache;
-import com.github.benmanes.caffeine.cache.RemovalListener;
-import com.github.benmanes.caffeine.cache.Scheduler;
-
-public class CaffeineCacheTest {
-
-    @Test
-    public void testCaffeine(@TempDir Path tmpDir) throws Exception {
-        final AtomicBoolean failed = new AtomicBoolean();
-
-        final CacheLoader<Integer, IndexWriter> loader = (n) -> {
-            var dir = FSDirectory.open(tmpDir.resolve("index-" + n));
-            var conf = new IndexWriterConfig();
-            var writer = new IndexWriter(dir, conf);
-            writer.setLiveCommitData(Collections.singletonMap("foo", "bar").entrySet());
-            writer.commit();
-            return writer;
-        };
-
-        RemovalListener<Integer, IndexWriter> evictor = (n, writer, cause) -> {
-            try {
-                writer.close();
-            } catch (IOException e) {
-                failed.set(true);
-                e.printStackTrace();
-            }
-        };
-
-        final LoadingCache<Integer, IndexWriter> cache = Caffeine.newBuilder()
-                .expireAfterAccess(1, TimeUnit.SECONDS)
-                .maximumSize(10)
-                .evictionListener(evictor)
-                .scheduler(Scheduler.systemScheduler())
-                .build(loader);
-
-        final int nThreads = 20;
-        final Thread[] threads = new Thread[nThreads];
-        for (int i = 0; i < nThreads; i++) {
-            threads[i] = new Thread(() -> {
-                final Random testRandom = new Random();
-                for (int j = 0; j < 10000; j++) {
-                    final IndexWriter writer = cache.get(testRandom.nextInt(15));
-                    try {
-                        writer.addDocument(new Document());
-                        writer.commit();
-                    } catch (IOException e) {
-                        failed.set(true);
-                        return;
-                    }
-                }
-            });
-            threads[i].start();
-        }
-
-        for (int i = 0; i < nThreads; i++) {
-            threads[i].join();
-        }
-
-        cache.invalidateAll();
-
-        assertThat(failed).isFalse();
-    }
-}
diff --git a/nouveau/server/nouveau.yaml b/nouveau/nouveau.yaml
similarity index 100%
rename from nouveau/server/nouveau.yaml
rename to nouveau/nouveau.yaml
diff --git a/nouveau/pom.xml b/nouveau/pom.xml
index cf0c08a57..cf8a3be69 100644
--- a/nouveau/pom.xml
+++ b/nouveau/pom.xml
@@ -14,23 +14,23 @@
 <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.couchdb.nouveau</groupId>
-  <artifactId>parent</artifactId>
+  <artifactId>server</artifactId>
   <version>1.0-SNAPSHOT</version>
-  <packaging>pom</packaging>
   <name>${project.artifactId}</name>
   <description>Full-text indexing for CouchDB</description>
   <inceptionYear>2022</inceptionYear>
 
   <properties>
     <argLine>-Duser.language=en -Duser.region=US -Duser.timezone=UTC</argLine>
+    <dropwizard.version>4.0.0</dropwizard.version>
+    <junit5.version>5.8.2</junit5.version>
+    <lucene.version>9.5.0</lucene.version>
     <maven.compiler.source>11</maven.compiler.source>
     <maven.compiler.target>11</maven.compiler.target>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
-    <dropwizard.version>4.0.0</dropwizard.version>
-    <junit5.version>5.8.2</junit5.version>
-    <slf4j.version>1.7.32</slf4j.version>
     <project.tests.exclude>SlowTest</project.tests.exclude>
+    <slf4j.version>1.7.32</slf4j.version>
   </properties>
 
   <dependencyManagement>
@@ -52,46 +52,179 @@
 	</dependencies>
   </dependencyManagement>
 
-  <modules>
-    <module>base</module>
-    <module>lucene4</module>
-    <module>lucene9</module>
-    <module>server</module>
-  </modules>
+  <dependencies>
+
+    <!-- Dropwizard -->
+    <dependency>
+      <groupId>io.dropwizard</groupId>
+      <artifactId>dropwizard-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.dropwizard</groupId>
+      <artifactId>dropwizard-http2</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>com.fasterxml.jackson.module</groupId>
+      <artifactId>jackson-module-afterburner</artifactId>
+    </dependency>
+
+    <!-- Dropwizard metrics -->
+    <dependency>
+        <groupId>io.dropwizard.metrics</groupId>
+        <artifactId>metrics-core</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-caffeine</artifactId>
+    </dependency>
+    <dependency>
+      <groupId>io.dropwizard.metrics</groupId>
+      <artifactId>metrics-jersey2</artifactId>
+    </dependency>
+
+    <!-- Lucene -->
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-core</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-queryparser</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-analysis-common</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-analysis-stempel</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-analysis-smartcn</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-analysis-kuromoji</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-facet</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.lucene</groupId>
+      <artifactId>lucene-misc</artifactId>
+      <version>${lucene.version}</version>
+    </dependency>
+
+    <!-- Test -->
+    <dependency>
+      <groupId>io.dropwizard</groupId>
+      <artifactId>dropwizard-testing</artifactId>
+      <scope>test</scope>
+      <exclusions>
+        <exclusion>
+          <groupId>junit</groupId>
+          <artifactId>junit</artifactId>
+        </exclusion>
+      </exclusions>
+    </dependency>
+    <dependency>
+	  <groupId>org.junit.jupiter</groupId>
+	  <artifactId>junit-jupiter</artifactId>
+	  <scope>test</scope>
+	</dependency>
+    <dependency>
+      <groupId>org.junit.jupiter</groupId>
+      <artifactId>junit-jupiter-engine</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.assertj</groupId>
+      <artifactId>assertj-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+    <dependency>
+      <groupId>org.mockito</groupId>
+      <artifactId>mockito-core</artifactId>
+      <scope>test</scope>
+    </dependency>
+  </dependencies>
 
   <build>
-    <pluginManagement>
-      <plugins>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-		  <artifactId>maven-surefire-plugin</artifactId>
-		  <version>2.22.2</version>
-          <configuration>
-            <excludedGroups>${project.tests.exclude}</excludedGroups>
-          </configuration>
-	    </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-assembly-plugin</artifactId>
-          <version>3.4.2</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-dependency-plugin</artifactId>
-          <version>3.5.0</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-jar-plugin</artifactId>
-          <version>3.3.0</version>
-        </plugin>
-        <plugin>
-          <groupId>org.apache.maven.plugins</groupId>
-          <artifactId>maven-shade-plugin</artifactId>
-          <version>3.4.1</version>
-        </plugin>
-      </plugins>
-    </pluginManagement>
+    <defaultGoal>package</defaultGoal>
+    <plugins>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-shade-plugin</artifactId>
+        <version>3.4.1</version>
+        <configuration>
+          <shadedArtifactAttached>true</shadedArtifactAttached>
+          <shadedClassifierName>dist</shadedClassifierName>
+          <createDependencyReducedPom>true</createDependencyReducedPom>
+          <filters>
+            <filter>
+              <artifact>*:*</artifact>
+              <excludes>
+                <exclude>META-INF/*.DSA</exclude>
+                <exclude>META-INF/*.RSA</exclude>
+                <exclude>META-INF/*.SF</exclude>
+              </excludes>
+            </filter>
+          </filters>
+          <transformers>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
+              <mainClass>org.apache.couchdb.nouveau.NouveauApplication</mainClass>
+              <manifestEntries>
+                <Multi-Release>true</Multi-Release>
+              </manifestEntries>
+            </transformer>
+            <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
+              <resource>META-INF/versions</resource>
+            </transformer>
+          </transformers>
+        </configuration>
+        <executions>
+          <execution>
+            <phase>package</phase>
+            <goals>
+              <goal>shade</goal>
+            </goals>
+          </execution>
+        </executions>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+		<artifactId>maven-surefire-plugin</artifactId>
+		<version>2.22.2</version>
+        <configuration>
+          <excludedGroups>${project.tests.exclude}</excludedGroups>
+        </configuration>
+	  </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-assembly-plugin</artifactId>
+        <version>3.4.2</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-dependency-plugin</artifactId>
+        <version>3.5.0</version>
+      </plugin>
+      <plugin>
+        <groupId>org.apache.maven.plugins</groupId>
+        <artifactId>maven-jar-plugin</artifactId>
+        <version>3.3.0</version>
+      </plugin>
+    </plugins>
   </build>
 
   <profiles>
diff --git a/nouveau/server/pom.xml b/nouveau/server/pom.xml
deleted file mode 100644
index 4c8c343ec..000000000
--- a/nouveau/server/pom.xml
+++ /dev/null
@@ -1,133 +0,0 @@
-<!--
- 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.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-  <modelVersion>4.0.0</modelVersion>
-  <groupId>org.apache.couchdb.nouveau</groupId>
-  <artifactId>server</artifactId>
-  <version>1.0-SNAPSHOT</version>
-  <name>${project.artifactId}</name>
-  <description>Full-text indexing for CouchDB</description>
-  <inceptionYear>2022</inceptionYear>
-
-  <parent>
-    <groupId>org.apache.couchdb.nouveau</groupId>
-    <artifactId>parent</artifactId>
-    <version>1.0-SNAPSHOT</version>
-  </parent>
-
-  <dependencies>
-
-    <!-- Base -->
-    <dependency>
-      <groupId>org.apache.couchdb.nouveau</groupId>
-      <artifactId>base</artifactId>
-      <version>${project.version}</version>
-    </dependency>
-
-    <!-- Dropwizard -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-http2</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>com.fasterxml.jackson.module</groupId>
-      <artifactId>jackson-module-afterburner</artifactId>
-    </dependency>
-
-    <!-- Dropwizard metrics -->
-    <dependency>
-        <groupId>io.dropwizard.metrics</groupId>
-        <artifactId>metrics-core</artifactId>
-    </dependency>
-    <dependency>
-      <groupId>io.dropwizard.metrics</groupId>
-      <artifactId>metrics-jersey2</artifactId>
-    </dependency>
-
-    <!-- Test -->
-    <dependency>
-      <groupId>io.dropwizard</groupId>
-      <artifactId>dropwizard-testing</artifactId>
-      <scope>test</scope>
-      <exclusions>
-        <exclusion>
-          <groupId>junit</groupId>
-          <artifactId>junit</artifactId>
-        </exclusion>
-      </exclusions>
-    </dependency>
-    <dependency>
-	  <groupId>org.junit.jupiter</groupId>
-	  <artifactId>junit-jupiter</artifactId>
-	  <scope>test</scope>
-	</dependency>
-    <dependency>
-      <groupId>org.junit.jupiter</groupId>
-      <artifactId>junit-jupiter-engine</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.assertj</groupId>
-      <artifactId>assertj-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-    <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <scope>test</scope>
-    </dependency>
-  </dependencies>
-
-  <build>
-    <defaultGoal>package</defaultGoal>
-    <plugins>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-release-plugin</artifactId>
-        <version>3.0.0-M5</version>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-jar-plugin</artifactId>
-        <version>2.4</version>
-        <configuration>
-          <archive>
-            <manifest>
-              <addDefaultImplementationEntries>true</addDefaultImplementationEntries>
-            </manifest>
-          </archive>
-        </configuration>
-      </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-		<artifactId>maven-surefire-plugin</artifactId>
-	  </plugin>
-
-      <plugin>
-        <groupId>org.apache.maven.plugins</groupId>
-        <artifactId>maven-javadoc-plugin</artifactId>
-        <version>3.4.0</version>
-      </plugin>
-
-    </plugins>
-  </build>
-
-</project>
diff --git a/nouveau/server/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java
similarity index 63%
rename from nouveau/server/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java
index 82bbbdc7c..d553d72b3 100644
--- a/nouveau/server/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java
+++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/NouveauApplication.java
@@ -13,23 +13,24 @@
 
 package org.apache.couchdb.nouveau;
 
-import java.net.MalformedURLException;
-import java.net.URL;
-import java.net.URLClassLoader;
-import java.util.ServiceLoader;
+import java.util.concurrent.ForkJoinPool;
 
 import org.apache.couchdb.nouveau.core.IndexManager;
 import org.apache.couchdb.nouveau.core.UpdatesOutOfOrderExceptionMapper;
+import org.apache.couchdb.nouveau.lucene9.core.Lucene9Module;
+import org.apache.couchdb.nouveau.lucene9.core.ParallelSearcherFactory;
+import org.apache.couchdb.nouveau.lucene9.health.AnalyzeHealthCheck;
+import org.apache.couchdb.nouveau.lucene9.health.IndexHealthCheck;
+import org.apache.couchdb.nouveau.lucene9.resources.AnalyzeResource;
+import org.apache.couchdb.nouveau.lucene9.resources.IndexResource;
 import org.apache.couchdb.nouveau.tasks.CloseAllIndexesTask;
+import org.apache.lucene.search.SearcherFactory;
 
 import io.dropwizard.core.Application;
-import io.dropwizard.core.setup.Bootstrap;
 import io.dropwizard.core.setup.Environment;
 
 public class NouveauApplication extends Application<NouveauApplicationConfiguration> {
 
-    private IndexManager indexManager;
-
     public static void main(String[] args) throws Exception {
         new NouveauApplication().run(args);
     }
@@ -39,34 +40,12 @@ public class NouveauApplication extends Application<NouveauApplicationConfigurat
         return "Nouveau";
     }
 
-    @Override
-    public void initialize(Bootstrap<NouveauApplicationConfiguration> bootstrap) {
-        indexManager = new IndexManager();
-
-        // Find Lucene bundles
-        for (String name : System.getProperties().stringPropertyNames()) {
-            if (name.startsWith("nouveau.bundle.")) {
-                try {
-                    ClassLoader classLoader = URLClassLoader
-                            .newInstance(new URL[] { new URL(System.getProperty(name)) });
-                    final ServiceLoader<LuceneBundle> bundleLoader = ServiceLoader.load(LuceneBundle.class,
-                            classLoader);
-                    for (final LuceneBundle bundle : bundleLoader) {
-                        bundle.setIndexManager(indexManager);
-                        bootstrap.addBundle(bundle);
-                    }
-                } catch (final MalformedURLException e) {
-                    throw new Error(e);
-                }
-            }
-        }
-    }
-
     @Override
     public void run(NouveauApplicationConfiguration configuration, Environment environment) throws Exception {
         environment.jersey().register(new UpdatesOutOfOrderExceptionMapper());
 
         // configure index manager
+        final IndexManager indexManager = new IndexManager();
         indexManager.setCommitIntervalSeconds(configuration.getCommitIntervalSeconds());
         indexManager.setIdleSeconds(configuration.getIdleSeconds());
         indexManager.setLockCount(configuration.getLockCount());
@@ -77,6 +56,21 @@ public class NouveauApplication extends Application<NouveauApplicationConfigurat
         indexManager.setRootDir(configuration.getRootDir());
         environment.lifecycle().manage(indexManager);
 
+        // Serialization classes
+        environment.getObjectMapper().registerModule(new Lucene9Module());
+
+        // AnalyzeResource
+        environment.jersey().register(new AnalyzeResource());
+
+        // IndexResource
+        final SearcherFactory searcherFactory = new ParallelSearcherFactory(ForkJoinPool.commonPool());
+        final IndexResource indexResource = new IndexResource(indexManager, searcherFactory);
+        environment.jersey().register(indexResource);
+
+        // Health checks
+        environment.healthChecks().register("analyze9", new AnalyzeHealthCheck());
+        environment.healthChecks().register("index9", new IndexHealthCheck(indexResource));
+
         // configure tasks
         environment.admin().addTask(new CloseAllIndexesTask(indexManager));
     }
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/NouveauApplicationConfiguration.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/NouveauApplicationConfiguration.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/NouveauApplicationConfiguration.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/NouveauApplicationConfiguration.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/After.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/After.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/After.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/After.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeRequest.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeRequest.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeRequest.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeRequest.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeResponse.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeResponse.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeResponse.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/AnalyzeResponse.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DocumentDeleteRequest.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/DocumentDeleteRequest.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DocumentDeleteRequest.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/DocumentDeleteRequest.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DocumentUpdateRequest.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/DocumentUpdateRequest.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DocumentUpdateRequest.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/DocumentUpdateRequest.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DoubleRange.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/DoubleRange.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/DoubleRange.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/DoubleRange.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexDefinition.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/IndexInfo.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexInfo.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/IndexInfo.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/IndexInfo.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/Range.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/Range.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/Range.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/Range.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchRequest.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchRequest.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchRequest.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchRequest.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchResults.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchResults.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/api/SearchResults.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchResults.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IOUtils.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IOUtils.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IOUtils.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/IOUtils.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/Index.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/Index.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/Index.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexClosedException.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexClosedException.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexClosedException.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexClosedException.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexFunction.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexFunction.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexFunction.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexFunction.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexLoader.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexLoader.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexLoader.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexLoader.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/IndexManager.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderException.java
diff --git a/nouveau/server/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderExceptionMapper.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderExceptionMapper.java
similarity index 100%
rename from nouveau/server/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderExceptionMapper.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/UpdatesOutOfOrderExceptionMapper.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterDeserializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterDeserializer.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterDeserializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterDeserializer.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterSerializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterSerializer.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterSerializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/core/ser/AfterSerializer.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/health/BaseAnalyzeHealthCheck.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/health/BaseAnalyzeHealthCheck.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/health/BaseAnalyzeHealthCheck.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/health/BaseAnalyzeHealthCheck.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/health/BaseIndexHealthCheck.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/health/BaseIndexHealthCheck.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/health/BaseIndexHealthCheck.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/health/BaseIndexHealthCheck.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldDeserializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldDeserializer.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldDeserializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldDeserializer.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldSerializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldSerializer.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldSerializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/IndexableFieldSerializer.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactory.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactory.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactory.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactory.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Index.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Index.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Index.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Index.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Module.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Module.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Module.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9Module.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9QueryParser.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9QueryParser.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9QueryParser.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9QueryParser.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/NumericRangeQueryProcessor.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/NumericRangeQueryProcessor.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/NumericRangeQueryProcessor.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/NumericRangeQueryProcessor.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/ParallelSearcherFactory.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/ParallelSearcherFactory.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/ParallelSearcherFactory.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/ParallelSearcherFactory.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QueryDeserializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QueryDeserializer.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QueryDeserializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QueryDeserializer.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializer.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializer.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/SimpleAsciiFoldingAnalyzer.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/SimpleAsciiFoldingAnalyzer.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/core/SimpleAsciiFoldingAnalyzer.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/core/SimpleAsciiFoldingAnalyzer.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/health/AnalyzeHealthCheck.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/health/AnalyzeHealthCheck.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/health/AnalyzeHealthCheck.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/health/AnalyzeHealthCheck.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/health/IndexHealthCheck.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/health/IndexHealthCheck.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/health/IndexHealthCheck.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/health/IndexHealthCheck.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/AnalyzeResource.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/AnalyzeResource.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/AnalyzeResource.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/AnalyzeResource.java
diff --git a/nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/IndexResource.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/IndexResource.java
similarity index 100%
rename from nouveau/lucene9/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/IndexResource.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/resources/IndexResource.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/resources/BaseAnalyzeResource.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/resources/BaseAnalyzeResource.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/resources/BaseAnalyzeResource.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/resources/BaseAnalyzeResource.java
diff --git a/nouveau/base/src/main/java/org/apache/couchdb/nouveau/resources/BaseIndexResource.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/resources/BaseIndexResource.java
similarity index 100%
rename from nouveau/base/src/main/java/org/apache/couchdb/nouveau/resources/BaseIndexResource.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/resources/BaseIndexResource.java
diff --git a/nouveau/server/src/main/java/org/apache/couchdb/nouveau/tasks/CloseAllIndexesTask.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/tasks/CloseAllIndexesTask.java
similarity index 100%
rename from nouveau/server/src/main/java/org/apache/couchdb/nouveau/tasks/CloseAllIndexesTask.java
rename to nouveau/src/main/java/org/apache/couchdb/nouveau/tasks/CloseAllIndexesTask.java
diff --git a/nouveau/server/src/main/resources/banner.txt b/nouveau/src/main/resources/banner.txt
similarity index 100%
rename from nouveau/server/src/main/resources/banner.txt
rename to nouveau/src/main/resources/banner.txt
diff --git a/nouveau/base/src/test/java/org/apache/couchdb/nouveau/api/SearchRequestTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/api/SearchRequestTest.java
similarity index 100%
rename from nouveau/base/src/test/java/org/apache/couchdb/nouveau/api/SearchRequestTest.java
rename to nouveau/src/test/java/org/apache/couchdb/nouveau/api/SearchRequestTest.java
diff --git a/nouveau/base/src/test/java/org/apache/couchdb/nouveau/core/BaseIndexTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/core/BaseIndexTest.java
similarity index 100%
rename from nouveau/base/src/test/java/org/apache/couchdb/nouveau/core/BaseIndexTest.java
rename to nouveau/src/test/java/org/apache/couchdb/nouveau/core/BaseIndexTest.java
diff --git a/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactoryTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactoryTest.java
similarity index 100%
rename from nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactoryTest.java
rename to nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9AnalyzerFactoryTest.java
diff --git a/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9IndexTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9IndexTest.java
similarity index 100%
rename from nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9IndexTest.java
rename to nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/Lucene9IndexTest.java
diff --git a/nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializationTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializationTest.java
similarity index 100%
rename from nouveau/lucene9/src/test/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializationTest.java
rename to nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/core/QuerySerializationTest.java
diff --git a/nouveau/base/src/test/resources/fixtures/DocumentUpdateRequest.json b/nouveau/src/test/resources/fixtures/DocumentUpdateRequest.json
similarity index 100%
rename from nouveau/base/src/test/resources/fixtures/DocumentUpdateRequest.json
rename to nouveau/src/test/resources/fixtures/DocumentUpdateRequest.json
diff --git a/nouveau/base/src/test/resources/fixtures/SearchRequest.json b/nouveau/src/test/resources/fixtures/SearchRequest.json
similarity index 100%
rename from nouveau/base/src/test/resources/fixtures/SearchRequest.json
rename to nouveau/src/test/resources/fixtures/SearchRequest.json