All,
On 2025/09/14 16:49:16 Christopher Schultz wrote:
> I've written (with some help from ChatGPT) a short CLI utility to check
> the segments and segment info and optionally force a change to the major
> version. It should only work if the requested version is *higher* than
> the current version AND if all the segments are already compatible. You
> also have to use a command-line argument to enable WRITE mode.
>
> So, you can run it on an index and get info, and verify beforehand that
> it SHOULD work before asking it to actually write to the segment info
> and "forge" the new indexCreatedVersionMajor field.
I have made a few modifications and actually run this on a test index
originally created with Solr/Lucene 7, but running on Solr 8. There were no
issues stopping Solr 8, running this to force the index to move to version 8,
then restarting Solr. Everything works as expected.
My next step is to try running this newly-forged index on Solr 9.
Here is the latest code:
import org.apache.lucene.index.*;
import org.apache.lucene.store.FSDirectory;
import org.apache.lucene.util.Version;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Path;
import java.nio.file.Paths;
public class LuceneIndexUpgrader {
public static void main(String[] args) {
if (args.length < 1) {
System.err.println("Usage: java LuceneIndexUpgrader <path-to-index>
[newMajorVersion] [--write]");
System.exit(1);
}
Path indexPath = null;
Integer newMajorVersion = null;
boolean shouldWrite = false;
// Parse args
for (String arg : args) {
if (arg.equals("--write")) {
shouldWrite = true;
} else if (arg.matches("\\d+")) {
newMajorVersion = Integer.parseInt(arg);
} else if (indexPath == null) {
indexPath = Paths.get(arg);
} else {
System.err.println("Unrecognized argument: " + arg);
System.exit(1);
}
}
if (indexPath == null) {
System.err.println("Error: Index path is required.");
System.exit(1);
}
if (newMajorVersion != null && (newMajorVersion < 1 || newMajorVersion
> 99)) {
System.err.println("Invalid Lucene major version: " +
newMajorVersion);
System.exit(1);
}
// Get Lucene library version
Version luceneVersion = Version.LATEST;
int currentLuceneMajor = luceneVersion.major;
System.out.println("Running with Lucene library version: " +
luceneVersion);
if (newMajorVersion != null && newMajorVersion > currentLuceneMajor) {
System.err.printf(
"Aborting: Requested index version %d is higher than the
current Lucene library version %d%n",
newMajorVersion, currentLuceneMajor
);
System.exit(1);
}
try (FSDirectory directory = FSDirectory.open(indexPath)) {
SegmentInfos segmentInfos =
SegmentInfos.readLatestCommit(directory);
int currentMajorVersion =
segmentInfos.getIndexCreatedVersionMajor();
// Print index-level version info
System.out.println("\nLucene Index Metadata:");
System.out.println("--------------------------------------------------");
System.out.println("Index Created Version Major: " +
currentMajorVersion);
System.out.println("Min Segment Lucene Version: " +
segmentInfos.getMinSegmentLuceneVersion());
System.out.println("\nSegment Details:");
boolean compatible = true;
for (SegmentCommitInfo sci : segmentInfos) {
SegmentInfo si = sci.info;
Version version = si.getVersion();
Version minVersion = si.getMinVersion();
System.out.println("--------------------------------------------------");
System.out.println("Segment name: " + si.name);
System.out.println(" Lucene version: " + version);
System.out.println(" Min Lucene ver: " + minVersion);
if (newMajorVersion != null) {
int actualVersion = minVersion != null ? minVersion.major :
(version != null ? version.major : -1);
if (actualVersion < newMajorVersion) {
System.err.printf(" Incompatible: segment minVersion
%d < requested indexCreatedVersionMajor %d%n",
actualVersion, newMajorVersion);
compatible = false;
}
}
}
if (newMajorVersion != null) {
System.out.printf("\nRequested new indexCreatedVersionMajor:
%d%n", newMajorVersion);
// Check: new version not lower than current
if (newMajorVersion < currentMajorVersion) {
System.err.printf("Aborting: new major version %d is less
than current index version %d%n",
newMajorVersion, currentMajorVersion);
System.exit(1);
}
// Check: new version same as current
if (newMajorVersion.equals(currentMajorVersion)) {
System.out.println("No change needed: index already has the
requested version.");
return;
}
if (!compatible) {
System.err.println("Aborting: Not all segments are
compatible with the requested version.");
System.exit(1);
}
if (shouldWrite) {
// Proceed with update
Field field =
SegmentInfos.class.getDeclaredField("indexCreatedVersionMajor");
field.setAccessible(true);
field.setInt(segmentInfos, newMajorVersion);
segmentInfos.commit(directory);
System.out.printf("Updated indexCreatedVersionMajor to %d
and saved to disk.%n", newMajorVersion);
} else {
System.out.println("Dry run: indexCreatedVersionMajor would
be updated, but --write was not set.");
}
} else {
System.out.println("\n(No version change requested.)");
}
} catch (IOException | NoSuchFieldException | IllegalAccessException e)
{
System.err.println("Error while processing Lucene index: " +
e.getMessage());
e.printStackTrace();
}
}
}