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 .TopFieldCollector ;
5154import org .apache .lucene .search .TopScoreDocCollector ;
5255import org .apache .lucene .util .Version ;
5356import org .opengrok .indexer .analysis .AbstractAnalyzer ;
6669import org .opengrok .indexer .util .Statistics ;
6770import org .opengrok .indexer .util .TandemPath ;
6871import org .opengrok .indexer .web .Prefix ;
72+ import org .opengrok .indexer .web .SortOrder ;
6973
7074/**
7175 * This is an encapsulation of the details on how to search in the index database.
@@ -114,6 +118,10 @@ public class SearchEngine {
114118 * Holds value of property type.
115119 */
116120 private String type ;
121+ /**
122+ * Holds value of property sort.
123+ */
124+ private SortOrder sortOrder ;
117125 /**
118126 * Holds value of property indexDatabase.
119127 */
@@ -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,18 +217,42 @@ private void searchMultiDatabase(List<Project> projectList, boolean paging) thro
205217 }
206218
207219 private void searchIndex (IndexSearcher searcher , boolean paging ) throws IOException {
208- collector = TopScoreDocCollector .create (hitsPerPage * cachePages , Short .MAX_VALUE );
220+ // Determine if we need a field-based sort or relevancy (score) sort.
221+ Sort luceneSort = null ;
222+ if (getSortOrder () == SortOrder .LASTMODIFIED ) {
223+ // Descending by date (newest first) - QueryBuilder.DATE is string sortable in index.
224+ luceneSort = new Sort (new SortField (QueryBuilder .DATE , SortField .Type .STRING , true ));
225+ } else if (getSortOrder () == SortOrder .BY_PATH ) {
226+ luceneSort = new Sort (new SortField (QueryBuilder .FULLPATH , SortField .Type .STRING ));
227+ }
228+
209229 Statistics stat = new Statistics ();
210- searcher .search (query , collector );
211- totalHits = collector .getTotalHits ();
212- stat .report (LOGGER , Level .FINEST , "search via SearchEngine done" ,
213- "search.latency" , new String []{"category" , "engine" ,
214- "outcome" , totalHits > 0 ? "success" : "empty" });
215- if (!paging && totalHits > 0 ) {
216- collector = TopScoreDocCollector .create (totalHits , Short .MAX_VALUE );
230+ if (luceneSort == null ) {
231+ collector = TopScoreDocCollector .create (hitsPerPage * cachePages , Short .MAX_VALUE );
217232 searcher .search (query , collector );
233+ totalHits = collector .getTotalHits ();
234+ stat .report (LOGGER , Level .FINEST , "search via SearchEngine done" ,
235+ "search.latency" , new String []{"category" , "engine" ,
236+ "outcome" , totalHits > 0 ? "success" : "empty" });
237+ if (!paging && totalHits > 0 ) {
238+ collector = TopScoreDocCollector .create (totalHits , Short .MAX_VALUE );
239+ searcher .search (query , collector );
240+ }
241+ hits = collector .topDocs ().scoreDocs ;
242+ } else {
243+ // Field based sort; use TopFieldCollector
244+ TopFieldCollector fieldCollector = TopFieldCollector .create (luceneSort , hitsPerPage * cachePages , Short .MAX_VALUE );
245+ searcher .search (query , fieldCollector );
246+ totalHits = fieldCollector .getTotalHits ();
247+ stat .report (LOGGER , Level .FINEST , "search via SearchEngine done (sorted)" ,
248+ "search.latency" , new String []{"category" , "engine" ,
249+ "outcome" , totalHits > 0 ? "success" : "empty" });
250+ if (!paging && totalHits > 0 ) {
251+ fieldCollector = TopFieldCollector .create (luceneSort , totalHits , Short .MAX_VALUE );
252+ searcher .search (query , fieldCollector );
253+ }
254+ hits = fieldCollector .topDocs ().scoreDocs ;
218255 }
219- hits = collector .topDocs ().scoreDocs ;
220256 StoredFields storedFields = searcher .storedFields ();
221257 for (ScoreDoc hit : hits ) {
222258 int docId = hit .doc ;
@@ -645,4 +681,22 @@ public String getType() {
645681 public void setType (String fileType ) {
646682 this .type = fileType ;
647683 }
684+
685+ /**
686+ * Getter for property sort.
687+ *
688+ * @return Value of property sortOrder.
689+ */
690+ public SortOrder getSortOrder () {
691+ return this .sortOrder ;
692+ }
693+
694+ /**
695+ * Setter for property sort.
696+ *
697+ * @param sortOrder New value of property sortOrder.
698+ */
699+ public void setSortOrder (SortOrder sortOrder ) {
700+ this .sortOrder = sortOrder ;
701+ }
648702}
0 commit comments