diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java index 2e575fef165..2f8ef0b806a 100644 --- a/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java +++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/api/SearchHit.java @@ -17,6 +17,7 @@ import com.fasterxml.jackson.databind.annotation.JsonNaming; import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; import java.util.Collection; import java.util.Objects; import org.apache.couchdb.nouveau.core.ser.PrimitiveWrapper; @@ -27,6 +28,9 @@ public class SearchHit { @NotEmpty private String id; + @Positive + private long seq; + @NotNull private PrimitiveWrapper[] order; @@ -35,8 +39,10 @@ public class SearchHit { public SearchHit() {} - public SearchHit(final String id, final PrimitiveWrapper[] order, final Collection fields) { + public SearchHit( + final String id, final long seq, final PrimitiveWrapper[] order, final Collection fields) { this.id = id; + this.seq = seq; this.order = Objects.requireNonNull(order); this.fields = Objects.requireNonNull(fields); } @@ -45,6 +51,10 @@ public String getId() { return id; } + public long getSeq() { + return seq; + } + public PrimitiveWrapper[] getOrder() { return order; } @@ -55,6 +65,6 @@ public Collection getFields() { @Override public String toString() { - return "SearchHit [id=" + id + ", order=" + order + ", fields=" + fields + "]"; + return "SearchHit [id=" + id + ", seq=" + seq + ", order=" + order + ", fields=" + fields + "]"; } } diff --git a/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Index.java b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Index.java index ce7f7d7ec95..0794f33525e 100644 --- a/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Index.java +++ b/nouveau/src/main/java/org/apache/couchdb/nouveau/lucene9/Lucene9Index.java @@ -245,7 +245,7 @@ private void collectHits(final IndexSearcher searcher, final TopDocs topDocs, fi final List fields = new ArrayList(doc.getFields().size()); for (IndexableField field : doc.getFields()) { - if (field.name().equals("_id")) { + if (field.name().startsWith("_")) { continue; } final StoredValue storedValue = field.storedValue(); @@ -265,7 +265,8 @@ private void collectHits(final IndexSearcher searcher, final TopDocs topDocs, fi } final PrimitiveWrapper[] after = toAfter(((FieldDoc) scoreDoc)); - hits.add(new SearchHit(doc.get("_id"), after, fields)); + hits.add(new SearchHit( + doc.get("_id"), doc.getField("_seq").numericValue().longValue(), after, fields)); } searchResults.setTotalHits(topDocs.totalHits.value); @@ -382,6 +383,9 @@ private static Document toDocument(final String docId, final DocumentUpdateReque result.add(new org.apache.lucene.document.StringField("_id", docId, Store.YES)); result.add(new SortedDocValuesField("_id", new BytesRef(docId))); + // seq + result.add(new org.apache.lucene.document.LongField("_seq", request.getSeq(), Store.YES)); + // partition (optional) if (request.hasPartition()) { result.add(new org.apache.lucene.document.StringField("_partition", request.getPartition(), Store.NO)); diff --git a/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/Lucene9IndexTest.java b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/Lucene9IndexTest.java index ece5fb36f1c..c4397611040 100644 --- a/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/Lucene9IndexTest.java +++ b/nouveau/src/test/java/org/apache/couchdb/nouveau/lucene9/Lucene9IndexTest.java @@ -18,6 +18,7 @@ import java.io.IOException; import java.nio.file.Path; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; @@ -74,15 +75,25 @@ public void testSearching(@TempDir Path path) throws IOException { final Index index = setup(path); try { final int count = 100; + List ids = new ArrayList(count); for (int i = 1; i <= count; i++) { final Collection fields = List.of(new StringField("foo", "bar", false)); final DocumentUpdateRequest request = new DocumentUpdateRequest(i - 1, i, null, fields); - index.update("doc" + i, request); + final String id = "doc" + i; + ids.add(id); + index.update(id, request); } + ids.sort(String::compareTo); final SearchRequest request = new SearchRequest(); request.setQuery("*:*"); + request.setLimit(count); final SearchResults results = index.search(request); assertThat(results.getTotalHits()).isEqualTo(count); + for (int i = 0; i < count; i++) { + var hit = results.getHits().get(i); + assertThat(hit.getId()).isEqualTo(ids.get(i)); + assertThat(hit.getSeq()).isEqualTo(Long.parseLong(ids.get(i).substring(3))); + } } finally { cleanup(index); }