4848import org .apache .lucene .search .IndexSearcher ;
4949import org .apache .lucene .search .Query ;
5050import org .apache .lucene .search .ScoreDoc ;
51+ import org .apache .lucene .search .Sort ;
52+ import org .apache .lucene .search .SortField ;
53+ import org .apache .lucene .search .TopDocs ;
54+ import org .apache .lucene .search .TopFieldCollectorManager ;
5155import org .apache .lucene .search .TopScoreDocCollectorManager ;
5256import org .apache .lucene .util .Version ;
5357import org .opengrok .indexer .analysis .AbstractAnalyzer ;
6670import org .opengrok .indexer .util .Statistics ;
6771import org .opengrok .indexer .util .TandemPath ;
6872import org .opengrok .indexer .web .Prefix ;
73+ import org .opengrok .indexer .web .SortOrder ;
6974
7075/**
7176 * This is an encapsulation of the details on how to search in the index database.
@@ -114,6 +119,10 @@ public class SearchEngine {
114119 * Holds value of property type.
115120 */
116121 private String type ;
122+ /**
123+ * Holds value of property sort.
124+ */
125+ private SortOrder sortOrder ;
117126 /**
118127 * Holds value of property indexDatabase.
119128 */
@@ -132,7 +141,6 @@ public class SearchEngine {
132141 int cachePages = RuntimeEnvironment .getInstance ().getCachePages ();
133142 int totalHits = 0 ;
134143 private ScoreDoc [] hits ;
135- private TopScoreDocCollectorManager collectorManager ;
136144 private IndexSearcher searcher ;
137145 boolean allCollected ;
138146 private final ArrayList <SuperIndexSearcher > searcherList = new ArrayList <>();
@@ -181,6 +189,10 @@ private void searchSingleDatabase(boolean paging) throws IOException {
181189 SuperIndexSearcher superIndexSearcher = RuntimeEnvironment .getInstance ().getSuperIndexSearcher ("" );
182190 searcherList .add (superIndexSearcher );
183191 searcher = superIndexSearcher ;
192+ // If a field-based sort is requested, collect all hits (disable paging optimization)
193+ if (sortOrder != SortOrder .RELEVANCY ) {
194+ paging = false ;
195+ }
184196 searchIndex (superIndexSearcher , paging );
185197 }
186198
@@ -205,20 +217,39 @@ private void searchMultiDatabase(List<Project> projectList, boolean paging) thro
205217 }
206218
207219 private void searchIndex (IndexSearcher searcher , boolean paging ) throws IOException {
208- collectorManager = new TopScoreDocCollectorManager (hitsPerPage * cachePages , Short .MAX_VALUE );
220+ Sort luceneSort = null ;
221+ if (getSortOrder () == SortOrder .LASTMODIFIED ) {
222+ luceneSort = new Sort (new SortField (QueryBuilder .DATE , SortField .Type .STRING , true ));
223+ } else if (getSortOrder () == SortOrder .BY_PATH ) {
224+ luceneSort = new Sort (new SortField (QueryBuilder .FULLPATH , SortField .Type .STRING ));
225+ }
226+
227+ int numHits = hitsPerPage * cachePages ;
228+ TopDocs topDocs ;
229+ if (luceneSort == null ) {
230+ topDocs = searcher .search (query , new TopScoreDocCollectorManager (numHits , Short .MAX_VALUE ));
231+ } else {
232+ topDocs = searcher .search (query , new TopFieldCollectorManager (luceneSort , numHits , Short .MAX_VALUE ));
233+ }
234+ hits = topDocs .scoreDocs ;
235+ totalHits = (int ) topDocs .totalHits .value ;
236+
209237 Statistics stat = new Statistics ();
210- hits = searcher .search (query , collectorManager ).scoreDocs ;
211- totalHits = searcher .count (query );
212238 stat .report (LOGGER , Level .FINEST , "search via SearchEngine done" ,
213239 "search.latency" , new String []{"category" , "engine" ,
214240 "outcome" , totalHits > 0 ? "success" : "empty" });
215- if (!paging && totalHits > hitsPerPage * cachePages ) {
216- collectorManager = new TopScoreDocCollectorManager (totalHits , Short .MAX_VALUE );
217- hits = searcher .search (query , collectorManager ).scoreDocs ;
218- stat .report (LOGGER , Level .FINEST , "FULL search via SearchEngine done" ,
219- "search.latency" , new String []{"category" , "engine" ,
220- "outcome" , totalHits > 0 ? "success" : "empty" });
241+
242+ if (!paging && totalHits > numHits ) {
243+ if (luceneSort == null ) {
244+ topDocs = searcher .search (query , new TopScoreDocCollectorManager (totalHits , Short .MAX_VALUE ));
245+ } else {
246+ topDocs = searcher .search (query , new TopFieldCollectorManager (luceneSort , totalHits , Short .MAX_VALUE ));
247+ }
248+ hits = topDocs .scoreDocs ;
221249 }
250+
251+ allCollected = !paging || totalHits <= numHits ;
252+
222253 StoredFields storedFields = searcher .storedFields ();
223254 for (ScoreDoc hit : hits ) {
224255 int docId = hit .doc ;
@@ -414,7 +445,7 @@ public void results(int start, int end, List<Hit> ret) {
414445 // TODO check if below fits for if end=old hits.length, or it should include it
415446 if (end > hits .length && !allCollected ) {
416447 //do the requery, we want more than 5 pages
417- collectorManager = new TopScoreDocCollectorManager (totalHits , Short .MAX_VALUE );
448+ var collectorManager = new TopScoreDocCollectorManager (totalHits , Short .MAX_VALUE );
418449 try {
419450 hits = searcher .search (query , collectorManager ).scoreDocs ;
420451 } catch (Exception e ) { // this exception should never be hit, since search() will hit this before
@@ -646,4 +677,22 @@ public String getType() {
646677 public void setType (String fileType ) {
647678 this .type = fileType ;
648679 }
680+
681+ /**
682+ * Getter for property sort.
683+ *
684+ * @return Value of property sortOrder.
685+ */
686+ public SortOrder getSortOrder () {
687+ return this .sortOrder ;
688+ }
689+
690+ /**
691+ * Setter for property sort.
692+ *
693+ * @param sortOrder New value of property sortOrder.
694+ */
695+ public void setSortOrder (SortOrder sortOrder ) {
696+ this .sortOrder = sortOrder ;
697+ }
649698}
0 commit comments