Sortieren Sie einen Lucene-Index nach einem StoredField oder einer Funktion von docIDJava

Java-Forum
Anonymous
 Sortieren Sie einen Lucene-Index nach einem StoredField oder einer Funktion von docID

Post by Anonymous »

Ich habe viele statische (unveränderliche) Lucene-Indizes, bei denen jedem Dokument ein ganzzahliges StoredField namens „fileId“ zugewiesen wurde (und jeder Index nur ein Segment hat). Ich möchte diese Indizes nun so ändern, dass die Dokumente nach Datei-ID sortiert werden.
Ich habe hier zwei Komponententests für die Indexsortierung gefunden, aber wenn ich wie in den Tests new Sort(new SortField("fileId", INT)) verwende, erhalte ich beim Aufruf von SortingCodecReader.wrap() „IllegalStateException: unerwartete Dokumentwerte vom Typ NONE für Feld ‚fileId‘ (erwartet=NUMERIC). Mit korrektem Dokumentwerttyp neu indizieren.“
Ich denke, das liegt daran, dass „fileId“ kein DocValue-Feld war. Glücklicherweise kann ich die Datei-ID leicht aus der Dokument-ID ermitteln, aber leider bietet SortField keinen Konstruktor zum Sortieren nach etwas basierend auf der Dokument-ID. Also habe ich DocSortField erstellt, das SortField erweitert. Es scheint, als ob es funktionieren sollte, aber aus irgendeinem Grund wurde der Index nach der Codeausführung nicht richtig sortiert (tatsächlich scheint sich die Reihenfolge überhaupt nicht geändert zu haben). Es gibt keine Fehlermeldung, daher habe ich keine Ahnung, wo der Fehler liegt. Ich habe versucht, einen Aufruf von forceMerge(1) hinzuzufügen, um die Sortierung zu erzwingen, aber es hilft nicht.
Meine Version von Lucene ist 9.11.1.

Code: Select all

import org.apache.lucene.index.*;
import org.apache.lucene.search.Sort;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.FSDirectory;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import static org.apache.lucene.index.PostingsEnum.POSITIONS;
import static org.apache.lucene.search.DocIdSetIterator.NO_MORE_DOCS;

public class LuceneIndexSorter {

public static void main(String[] args) throws IOException {
File oldDir = new File("path/to/index");
if (areDocumentsInOrder(oldDir)) {
throw new RuntimeException("Documents already in order");
}
File newDir = new File(oldDir.getParent(), oldDir.getName() + " 2");
Sort indexSort = new Sort(new DocSortField("fileId", LuceneIndexSorter::getFileId));
// The rest comes from https://github.com/apache/lucene-solr/blob/a7bdc6893e21954ed9f6d8bce256a4a9c917310b/lucene/core/src/test/org/apache/lucene/index/TestSortingCodecReader.java
IndexWriterConfig indexWriterConfig = new IndexWriterConfig().setIndexSort(indexSort);
Directory newDirectory = FSDirectory.open(newDir.toPath());
Directory oldDirectory = FSDirectory.open(oldDir.toPath());
IndexWriter indexWriter = new IndexWriter(newDirectory, indexWriterConfig);
try (DirectoryReader indexReader = DirectoryReader.open(oldDirectory)) {
List wrappedCodecReaders = new ArrayList();
for (LeafReaderContext ctx : indexReader.leaves()) {
CodecReader wrap = SortingCodecReader.wrap(SlowCodecReaderWrapper.wrap(ctx.reader()), indexSort);
assert wrap.toString().startsWith("SortingCodecReader(");
wrappedCodecReaders.add(wrap);
}
indexWriter.addIndexes(wrappedCodecReaders.toArray(new CodecReader[0]));
indexWriter.commit(); // This line is needed to prevent "IndexNotFoundException: no segments* file found in MMapDirectory@...", although it's not used in the unit tests
}
// Check if it worked
if (!areDocumentsInOrder(newDir)) {
throw new RuntimeException("Documents weren't correctly sorted"); // Program ends up here with no other output
}
}

private static boolean areDocumentsInOrder(File dir) throws IOException {
FSDirectory directory = FSDirectory.open(dir.toPath());
DirectoryReader indexReader = DirectoryReader.open(directory);
try (LeafReader leafReader = indexReader.leaves().get(0).reader()) {
PostingsEnum postings = leafReader.postings(new Term("tokens", "a"), POSITIONS);
int docId = postings.nextDoc();
List fileIds = new ArrayList();
while (docId != NO_MORE_DOCS) {
fileIds.add(getFileId(docId));
if (fileIds.size() >= 2 && fileIds.get(fileIds.size() - 2) > (fileIds.get(fileIds.size() - 1))) {
return false;
}
docId = postings.nextDoc();
}
return true;
}
}

private static int getFileId(int docId) {
...
}
}

Code: Select all

import org.apache.lucene.index.IndexSorter;
import org.apache.lucene.search.SortField;

import java.util.function.Function;

public class DocSortField extends SortField {
private Function docIdToValue;

public DocSortField(String field, Function docIdToValue) {
super(field, Type.DOC);
this.docIdToValue = docIdToValue;
}

@Override
public IndexSorter getIndexSorter() {
return new DocIdSorter(Provider.NAME, docIdToValue);
}
}

Code: Select all

import org.apache.lucene.index.IndexSorter;
import org.apache.lucene.index.LeafReader;

import java.util.List;
import java.util.function.Function;

public class DocIdSorter implements IndexSorter {
private final String providerName;
private final Function  docIdToValue;

public DocIdSorter(String providerName, Function docIdToValue) {
this.providerName = providerName;
this.docIdToValue = docIdToValue;
}

@Override
public ComparableProvider[] getComparableProviders(List

Quick Reply

Change Text Case: 
   
  • Similar Topics
    Replies
    Views
    Last post