diff --git a/src/main/java/org/codelibs/fess/rank/fusion/RankFusionProcessor.java b/src/main/java/org/codelibs/fess/rank/fusion/RankFusionProcessor.java index 4293f3d6e..e22aa4fac 100644 --- a/src/main/java/org/codelibs/fess/rank/fusion/RankFusionProcessor.java +++ b/src/main/java/org/codelibs/fess/rank/fusion/RankFusionProcessor.java @@ -180,7 +180,7 @@ public class RankFusionProcessor implements AutoCloseable { final var docs = scoreDocMap.values().stream() .sorted((e1, e2) -> Float.compare(toFloat(e2.get(scoreField)), toFloat(e1.get(scoreField)))).toList(); int offset = 0; - for (int i = 0; i < windowSize / 2; i++) { + for (int i = 0; i < windowSize / 2 && i < docs.size(); i++) { if (!mainIdSet.contains(docs.get(i).get(idField))) { offset++; } @@ -193,9 +193,24 @@ public class RankFusionProcessor implements AutoCloseable { if (Relation.EQUAL_TO.toString().equals(mainResult.getAllRecordCountRelation())) { allRecordCount += offset; } - return createResponseList(docs.subList(startPosition, startPosition + pageSize), allRecordCount, - mainResult.getAllRecordCountRelation(), mainResult.getQueryTime(), mainResult.isPartialResults(), - mainResult.getFacetResponse(), startPosition, pageSize, offset); + return createResponseList(extractList(docs, pageSize, startPosition), allRecordCount, mainResult.getAllRecordCountRelation(), + mainResult.getQueryTime(), mainResult.isPartialResults(), mainResult.getFacetResponse(), startPosition, pageSize, offset); + } + + protected List> extractList(final List> docs, final int pageSize, final int startPosition) { + final int size = docs.size(); + if (size == 0) { + return docs; // empty + } + int fromIndex = startPosition; + if (fromIndex >= size) { + fromIndex = size - 1; + } + int toIndex = startPosition + pageSize; + if (toIndex >= size) { + toIndex = size; + } + return docs.subList(fromIndex, toIndex); } protected List> searchWithMainSearcher(final String query, final SearchRequestParams params, diff --git a/src/main/java/org/codelibs/fess/rank/fusion/SearchResult.java b/src/main/java/org/codelibs/fess/rank/fusion/SearchResult.java index c322c9973..406461c6e 100644 --- a/src/main/java/org/codelibs/fess/rank/fusion/SearchResult.java +++ b/src/main/java/org/codelibs/fess/rank/fusion/SearchResult.java @@ -69,6 +69,13 @@ public class SearchResult { return new SearchResultBuilder(); } + @Override + public String toString() { + return "SearchResult [documentList=" + documentList + ", allRecordCount=" + allRecordCount + ", allRecordCountRelation=" + + allRecordCountRelation + ", queryTime=" + queryTime + ", partialResults=" + partialResults + ", facetResponse=" + + facetResponse + "]"; + } + static class SearchResultBuilder { private long allRecordCount; diff --git a/src/test/java/org/codelibs/fess/rank/fusion/RankFusionProcessorTest.java b/src/test/java/org/codelibs/fess/rank/fusion/RankFusionProcessorTest.java index f348e5858..25bb1f71b 100644 --- a/src/test/java/org/codelibs/fess/rank/fusion/RankFusionProcessorTest.java +++ b/src/test/java/org/codelibs/fess/rank/fusion/RankFusionProcessorTest.java @@ -95,7 +95,7 @@ public class RankFusionProcessorTest extends UnitFessTestCase { } } - public void test_1searcher10_1000docs_100size() throws Exception { + public void test_1searcher10_45_45_1000docs_100size() throws Exception { String query = "*"; int allRecordCount = 1000; int pageSize = 100; @@ -191,7 +191,7 @@ public class RankFusionProcessorTest extends UnitFessTestCase { if (rankFusionProcessor.search(query, new TestSearchRequestParams(1000, pageSize, offset), OptionalThing.empty()) instanceof QueryResponseList list) { - assertEquals(pageSize, list.size()); + assertEquals(offset, list.size()); assertEquals(allRecordCount + offset, list.getAllRecordCount()); assertEquals(11, list.getAllPageCount()); assertEquals(1045, list.getCurrentEndRecordNumber()); @@ -208,6 +208,249 @@ public class RankFusionProcessorTest extends UnitFessTestCase { } } + public void test_1searcher0_0docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 0; + int pageSize = 100; + int offset = 0; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(0, list.size()); + assertEquals(0, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(0, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(0, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher0_10docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 10; + int pageSize = 100; + int offset = 0; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(10, list.size()); + assertEquals(10, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(10, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher0_1000docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 1000; + int pageSize = 100; + int offset = 0; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(pageSize, list.size()); + assertEquals(1000, list.getAllRecordCount()); + assertEquals(10, list.getAllPageCount()); + assertEquals(100, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher10_0docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 0; + int pageSize = 100; + int offset = 10; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(10, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(10, list.size()); + assertEquals(10, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(10, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher10_10docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 10; + int pageSize = 100; + int offset = 0; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(10, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(10, list.size()); + assertEquals(10, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(10, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher10_1000docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 1000; + int pageSize = 100; + int offset = 0; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(10, 0, 0)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(pageSize, list.size()); + assertEquals(1000, list.getAllRecordCount()); + assertEquals(10, list.getAllPageCount()); + assertEquals(100, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher1000_0docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 0; + int pageSize = 100; + int offset = 100; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 1000)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(pageSize, list.size()); + assertEquals(100, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(100, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher1000_10docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 10; + int pageSize = 100; + int offset = 90; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 1000)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(pageSize, list.size()); + assertEquals(100, list.getAllRecordCount()); + assertEquals(1, list.getAllPageCount()); + assertEquals(100, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + + public void test_1searcher1000_1000docs_100size() throws Exception { + String query = "*"; + int allRecordCount = 1000; + int pageSize = 100; + int offset = 50; + try (RankFusionProcessor rankFusionProcessor = new RankFusionProcessor()) { + rankFusionProcessor.setSeacher(new TestMainSearcher(allRecordCount)); + rankFusionProcessor.register(new TestSubSearcher(0, 0, 1000)); + rankFusionProcessor.init(); + + if (rankFusionProcessor.search(query, new TestSearchRequestParams(0, pageSize, 0), + OptionalThing.empty()) instanceof QueryResponseList list) { + assertEquals(pageSize, list.size()); + assertEquals(1050, list.getAllRecordCount()); + assertEquals(11, list.getAllPageCount()); + assertEquals(100, list.getCurrentEndRecordNumber()); + assertEquals(1, list.getCurrentPageNumber()); + assertEquals(1, list.getCurrentStartRecordNumber()); + assertEquals(offset, list.getOffset()); + assertEquals(100, list.getPageSize()); + assertEquals(0, list.getStart()); + } else { + fail(); + } + } + } + static class TestMainSearcher extends RankFusionSearcher { private long allRecordCount; @@ -221,7 +464,7 @@ public class RankFusionProcessorTest extends UnitFessTestCase { int start = params.getStartPosition(); int size = params.getPageSize(); SearchResultBuilder builder = SearchResult.create(); - for (int i = start; i < start + size; i++) { + for (int i = start; i < start + size && i < allRecordCount; i++) { Map doc = new HashMap<>(); doc.put(ID_FIELD, Integer.toString(i)); doc.put("score", 1.0f / (i + 1));