Skip to content

Commit f1de723

Browse files
committed
Allow sorting in the API calls by path and date
Signed-off-by: Bernát Gábor <gaborjbernat@gmail.com>
1 parent 6d2643b commit f1de723

File tree

4 files changed

+67
-10
lines changed

4 files changed

+67
-10
lines changed

apiary.apib

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,10 @@ The repository path is relative to source root.
657657
+ projects (optional, string) - projects to search in
658658
+ maxresults (optional, string) - maximum number of documents whose hits will be returned (default 1000)
659659
+ start (optional, string) - start index from which to return results
660+
+ sort (optional, string) - sort order for results (default: "relevancy"). Possible values are:
661+
- `relevancy` - by relevancy (Lucene score)
662+
- `fullpath` - by file path
663+
- `lastmodtime` - by last modification date of the file.
660664

661665
+ Response 200 (application/json)
662666
+ Body

opengrok-indexer/src/main/java/org/opengrok/indexer/search/SearchEngine.java

Lines changed: 54 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@
4848
import org.apache.lucene.search.IndexSearcher;
4949
import org.apache.lucene.search.Query;
5050
import 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.TopDocsCollector;
54+
import org.apache.lucene.search.TopFieldCollector;
5155
import org.apache.lucene.search.TopScoreDocCollector;
5256
import org.apache.lucene.util.Version;
5357
import org.opengrok.indexer.analysis.AbstractAnalyzer;
@@ -66,6 +70,7 @@
6670
import org.opengrok.indexer.util.Statistics;
6771
import org.opengrok.indexer.util.TandemPath;
6872
import 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,7 @@ public class SearchEngine {
132141
int cachePages = RuntimeEnvironment.getInstance().getCachePages();
133142
int totalHits = 0;
134143
private ScoreDoc[] hits;
135-
private TopScoreDocCollector collector;
144+
private TopDocsCollector<?> collector;
136145
private IndexSearcher searcher;
137146
boolean allCollected;
138147
private final ArrayList<SuperIndexSearcher> searcherList = new ArrayList<>();
@@ -181,6 +190,10 @@ private void searchSingleDatabase(boolean paging) throws IOException {
181190
SuperIndexSearcher superIndexSearcher = RuntimeEnvironment.getInstance().getSuperIndexSearcher("");
182191
searcherList.add(superIndexSearcher);
183192
searcher = superIndexSearcher;
193+
// If a field-based sort is requested, collect all hits (disable paging optimization)
194+
if (sortOrder != SortOrder.RELEVANCY) {
195+
paging = false;
196+
}
184197
searchIndex(superIndexSearcher, paging);
185198
}
186199

@@ -205,16 +218,33 @@ private void searchMultiDatabase(List<Project> projectList, boolean paging) thro
205218
}
206219

207220
private void searchIndex(IndexSearcher searcher, boolean paging) throws IOException {
208-
collector = TopScoreDocCollector.create(hitsPerPage * cachePages, Short.MAX_VALUE);
209-
Statistics stat = new Statistics();
221+
Sort luceneSort = null;
222+
if (getSortOrder() == SortOrder.LASTMODIFIED) {
223+
luceneSort = new Sort(new SortField(QueryBuilder.DATE, SortField.Type.STRING, true));
224+
} else if (getSortOrder() == SortOrder.BY_PATH) {
225+
luceneSort = new Sort(new SortField(QueryBuilder.FULLPATH, SortField.Type.STRING));
226+
}
227+
if (luceneSort == null) {
228+
collector = TopScoreDocCollector.create(hitsPerPage * cachePages, Short.MAX_VALUE);
229+
} else {
230+
collector = TopFieldCollector.create(luceneSort, hitsPerPage * cachePages, Short.MAX_VALUE);
231+
}
210232
searcher.search(query, collector);
211233
totalHits = collector.getTotalHits();
234+
Statistics stat = new Statistics();
212235
stat.report(LOGGER, Level.FINEST, "search via SearchEngine done",
213236
"search.latency", new String[]{"category", "engine",
214237
"outcome", totalHits > 0 ? "success" : "empty"});
215-
if (!paging && totalHits > 0) {
216-
collector = TopScoreDocCollector.create(totalHits, Short.MAX_VALUE);
217-
searcher.search(query, collector);
238+
if (luceneSort == null) {
239+
if (!paging && totalHits > 0) {
240+
collector = TopScoreDocCollector.create(totalHits, Short.MAX_VALUE);
241+
searcher.search(query, collector);
242+
}
243+
} else {
244+
if (!paging && totalHits > 0) {
245+
collector = TopFieldCollector.create(luceneSort, totalHits, Short.MAX_VALUE);
246+
searcher.search(query, collector);
247+
}
218248
}
219249
hits = collector.topDocs().scoreDocs;
220250
StoredFields storedFields = searcher.storedFields();
@@ -645,4 +675,22 @@ public String getType() {
645675
public void setType(String fileType) {
646676
this.type = fileType;
647677
}
678+
679+
/**
680+
* Getter for property sort.
681+
*
682+
* @return Value of property sortOrder.
683+
*/
684+
public SortOrder getSortOrder() {
685+
return this.sortOrder;
686+
}
687+
688+
/**
689+
* Setter for property sort.
690+
*
691+
* @param sortOrder New value of property sortOrder.
692+
*/
693+
public void setSortOrder(SortOrder sortOrder) {
694+
this.sortOrder = sortOrder;
695+
}
648696
}

opengrok-web/src/main/java/org/opengrok/web/api/v1/controller/SearchController.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.opengrok.indexer.search.Hit;
4040
import org.opengrok.indexer.search.SearchEngine;
4141
import org.opengrok.indexer.web.QueryParameters;
42+
import org.opengrok.indexer.web.SortOrder;
4243
import org.opengrok.web.PageConfig;
4344
import org.opengrok.web.api.v1.filter.CorsEnable;
4445
import org.opengrok.web.api.v1.suggester.provider.service.SuggesterService;
@@ -58,6 +59,7 @@ public class SearchController {
5859
public static final String PATH = "search";
5960

6061
private static final int MAX_RESULTS = 1000;
62+
private static final String DEFAULT_SORT_ORDER = "relevancy";
6163

6264
private final SuggesterService suggester;
6365

@@ -81,9 +83,10 @@ public SearchResult search(
8183
@QueryParam("projects") final List<String> projects,
8284
@QueryParam("maxresults") // Akin to QueryParameters.COUNT_PARAM
8385
@DefaultValue(MAX_RESULTS + "") final int maxResults,
84-
@QueryParam(QueryParameters.START_PARAM) @DefaultValue(0 + "") final int startDocIndex
86+
@QueryParam(QueryParameters.START_PARAM) @DefaultValue(0 + "") final int startDocIndex,
87+
@QueryParam(QueryParameters.SORT_PARAM) @DefaultValue(DEFAULT_SORT_ORDER) final String sort
8588
) {
86-
try (SearchEngineWrapper engine = new SearchEngineWrapper(full, def, symbol, path, hist, type)) {
89+
try (SearchEngineWrapper engine = new SearchEngineWrapper(full, def, symbol, path, hist, type, SortOrder.get(sort))) {
8790

8891
if (!engine.isValid()) {
8992
throw new WebApplicationException("Invalid request", Response.Status.BAD_REQUEST);
@@ -119,14 +122,16 @@ private SearchEngineWrapper(
119122
final String symbol,
120123
final String path,
121124
final String hist,
122-
final String type
125+
final String type,
126+
final SortOrder sortOrder
123127
) {
124128
engine.setFreetext(full);
125129
engine.setDefinition(def);
126130
engine.setSymbol(symbol);
127131
engine.setFile(path);
128132
engine.setHistory(hist);
129133
engine.setType(type);
134+
engine.setSortOrder(sortOrder);
130135
}
131136

132137
public List<Hit> search(

opengrok-web/src/main/java/org/opengrok/web/api/v1/filter/IncomingFilter.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ public class IncomingFilter implements ContainerRequestFilter, ConfigurationChan
6666
/**
6767
* Endpoint paths that are exempted from this filter.
6868
* @see SearchController#search(HttpServletRequest, String, String, String, String, String, String,
69-
* java.util.List, int, int)
69+
* java.util.List, int, int, String)
7070
* @see SuggesterController#getSuggestions(org.opengrok.web.api.v1.suggester.model.SuggesterQueryData)
7171
* @see SuggesterController#getConfig()
7272
*/

0 commit comments

Comments
 (0)