private void setFacets(IssueQuery query, QueryContext options, Map<String, FilterBuilder> filters, QueryBuilder esQuery, SearchRequestBuilder esSearch) {
if (options.isFacet()) {
// Execute Term aggregations
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.SEVERITY.field(), IssueFilterParameters.SEVERITIES));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.STATUS.field(), IssueFilterParameters.STATUSES));
- esSearch.addAggregation(getResolutionFacet(query, options, filters, esQuery));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.ACTION_PLAN.field(), IssueFilterParameters.ACTION_PLANS));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.PROJECT.field(), IssueFilterParameters.COMPONENT_ROOTS,
- query.componentRoots().toArray()));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.RULE_KEY.field(), IssueFilterParameters.RULES,
- query.rules().toArray()));
- esSearch.addAggregation(getAssigneesFacet(query, options, filters, esQuery));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.COMPONENT.field(), IssueFilterParameters.COMPONENTS,
- query.components().toArray()));
- esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.LANGUAGE.field(), IssueFilterParameters.LANGUAGES,
- query.languages().toArray()));
+ if (options.facets().contains(IssueFilterParameters.SEVERITIES)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.SEVERITY.field(), IssueFilterParameters.SEVERITIES));
+ }
+ if (options.facets().contains(IssueFilterParameters.STATUSES)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.STATUS.field(), IssueFilterParameters.STATUSES));
+ }
+ if (options.facets().contains(IssueFilterParameters.RESOLUTIONS)) {
+ esSearch.addAggregation(getResolutionFacet(query, options, filters, esQuery));
+ }
+ if (options.facets().contains(IssueFilterParameters.ACTION_PLANS)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.ACTION_PLAN.field(), IssueFilterParameters.ACTION_PLANS));
+ }
+ if (options.facets().contains(IssueFilterParameters.COMPONENT_ROOTS)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.PROJECT.field(), IssueFilterParameters.COMPONENT_ROOTS,
+ query.componentRoots().toArray()));
+ }
+ if (options.facets().contains(IssueFilterParameters.RULES)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.RULE_KEY.field(), IssueFilterParameters.RULES,
+ query.rules().toArray()));
+ }
+ if (options.facets().contains(IssueFilterParameters.ASSIGNEES)) {
+ esSearch.addAggregation(getAssigneesFacet(query, options, filters, esQuery));
+ }
+ if (options.facets().contains(IssueFilterParameters.COMPONENTS)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.COMPONENT.field(), IssueFilterParameters.COMPONENTS,
+ query.components().toArray()));
+ }
+ if (options.facets().contains(IssueFilterParameters.LANGUAGES)) {
+ esSearch.addAggregation(stickyFacetBuilder(esQuery, filters, IssueNormalizer.IssueField.LANGUAGE.field(), IssueFilterParameters.LANGUAGES,
+ query.languages().toArray()));
+ }
}
}
return Collections.emptyList();
}
+ @Override
+ @CheckForNull
+ protected Collection<String> possibleFacets() {
+ return Arrays.asList(new String[]{
+ IssueFilterParameters.SEVERITIES,
+ IssueFilterParameters.STATUSES,
+ IssueFilterParameters.RESOLUTIONS,
+ IssueFilterParameters.ACTION_PLANS,
+ IssueFilterParameters.COMPONENT_ROOTS,
+ IssueFilterParameters.RULES,
+ IssueFilterParameters.ASSIGNEES,
+ IssueFilterParameters.COMPONENTS,
+ IssueFilterParameters.LANGUAGES
+ });
+ }
+
@Override
protected void doContextResponse(Request request, QueryContext context, Result<Issue> result, JsonWriter json) {
List<String> issueKeys = newArrayList();
import com.google.common.base.Preconditions;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
Map<String, FilterBuilder> filters = this.getFilters(query, options);
if (options.isFacet()) {
+ Logger.getLogger(this.getClass()).info("Facets = " + options.facets());
for (AggregationBuilder aggregation : getFacets(qb, filters).values()) {
esSearch.addAggregation(aggregation);
}
import org.sonar.server.search.Result;
import org.sonar.server.search.ws.SearchOptions;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
RuleQuery query = createRuleQuery(ruleService.newRuleQuery(), request);
SearchOptions searchOptions = SearchOptions.create(request);
QueryContext queryContext = mapping.newQueryOptions(searchOptions);
- queryContext.setFacet(request.mandatoryParamAsBoolean(PARAM_FACETS));
+ if (Boolean.valueOf(request.paramAsBoolean("facets"))) {
+ queryContext.addFacets(Arrays.asList("languages", "repositories", "tags"));
+ }
Result<Rule> results = ruleService.search(query, queryContext);
private int offset = DEFAULT_OFFSET;
private int limit = DEFAULT_LIMIT;
- private boolean facet = DEFAULT_FACET;
+ private Set<String> facets = newHashSet();
private Set<String> fieldsToReturn = newHashSet();
private boolean scroll = false;
private boolean showFullResult = false;
}
/**
- * Whether or not the search returns facets for the domain. Defaults to {@link #DEFAULT_OFFSET}
+ * Whether or not the search returns facets for the domain. Defaults to {@link #DEFAULT_FACET}
*/
public boolean isFacet() {
- return facet;
+ return !facets.isEmpty();
}
/**
- * Sets whether or not the search returns facets for the domain.
+ * Selects facets to return for the domain.
*/
- public QueryContext setFacet(boolean facet) {
- this.facet = facet;
+ public QueryContext addFacets(Collection<String> facets) {
+ this.facets.addAll(facets);
return this;
}
+ /**
+ * Lists selected facets.
+ */
+ public Collection<String> facets() {
+ return facets;
+ }
+
/**
* Whether or not the search result will be scrollable using an iterator
*/
import java.util.Collection;
import java.util.Iterator;
+import java.util.List;
import java.util.Map;
public abstract class SearchRequestHandler<QUERY, DOMAIN> implements RequestHandler {
@CheckForNull
protected abstract Collection<String> possibleFields();
+ @CheckForNull
+ protected abstract Collection<String> possibleFacets();
+
public final void define(WebService.NewController controller) {
WebService.NewAction action = controller.createAction(this.actionName)
.setHandler(this);
.setExampleValue("20")
.setDefaultValue("100");
- action.createParam(PARAM_FACETS)
- .setDescription("Compute predefined facets")
- .setBooleanPossibleValues()
- .setDefaultValue("false");
+ Collection<String> possibleFacets = possibleFacets();
+ WebService.NewParam paramFacets = action.createParam(PARAM_FACETS)
+ .setDescription("Comma-separated list of the facets to be computed. No facet is computed by default.")
+ .setPossibleValues(possibleFacets);
+ if (possibleFacets != null && possibleFacets.size() > 1) {
+ Iterator<String> it = possibleFacets.iterator();
+ paramFacets.setExampleValue(String.format("%s,%s", it.next(), it.next()));
+ }
Collection<String> possibleFields = possibleFields();
WebService.NewParam paramFields = action.createParam(PARAM_FIELDS)
private QueryContext getQueryContext(Request request) {
int pageSize = request.mandatoryParamAsInt(PARAM_PAGE_SIZE);
- QueryContext queryContext = new QueryContext().addFieldsToReturn(request.paramAsStrings(PARAM_FIELDS))
- .setFacet(request.mandatoryParamAsBoolean(PARAM_FACETS));
+ QueryContext queryContext = new QueryContext().addFieldsToReturn(request.paramAsStrings(PARAM_FIELDS));
+ List<String> facets = request.paramAsStrings(PARAM_FACETS);
+ if(facets != null) {
+ queryContext.addFacets(facets);
+ }
if (pageSize < 1) {
queryContext.setPage(request.mandatoryParamAsInt(PARAM_PAGE), 0).setMaxLimit();
} else {
import org.sonar.server.tester.ServerTester;
import org.sonar.server.user.MockUserSession;
+import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
assertThat(result.getHits()).hasSize(2);
assertThat(result.getFacets()).isEmpty();
- result = service.search(IssueQuery.builder().build(), new QueryContext().setFacet(true));
- assertThat(result.getFacets().keySet()).hasSize(9);
+ result = service.search(IssueQuery.builder().build(), new QueryContext().addFacets(Arrays.asList("actionPlans", "assignees")));
+ assertThat(result.getFacets().keySet()).hasSize(2);
assertThat(result.getFacetKeys("actionPlans")).hasSize(2);
assertThat(result.getFacetKeys("assignees")).hasSize(1);
}
db.issueDao().insert(session, issue);
session.commit();
- WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION).setParam(SearchAction.PARAM_FACETS, "true").execute();
+ WsTester.Result result = wsTester.newGetRequest(IssuesWs.API_ENDPOINT, SearchAction.SEARCH_ACTION)
+ .setParam(SearchAction.PARAM_FACETS, "statuses,severities,resolutions,componentRoots,rules,components,assignees,languages")
+ .execute();
result.assertJson(this.getClass(), "display_facets.json", false);
}
// should not have any facet!
RuleQuery query = new RuleQuery();
- Result result = index.search(query, new QueryContext().setFacet(false));
+ Result result = index.search(query, new QueryContext());
assertThat(result.getFacets()).isEmpty();
// should not have any facet on non matching query!
- result = index.search(new RuleQuery().setQueryText("aeiou"), new QueryContext().setFacet(true));
+ result = index.search(new RuleQuery().setQueryText("aeiou"), new QueryContext().addFacets(Arrays.asList("repositories")));
assertThat(result.getFacets()).isEmpty();
// Repositories Facet is preset
- result = index.search(query, new QueryContext().setFacet(true));
+ result = index.search(query, new QueryContext().addFacets(Arrays.asList("repositories", "tags")));
assertThat(result.getFacets()).isNotNull();
assertThat(result.getFacets()).hasSize(3);
assertThat(index.search(new RuleQuery(), new QueryContext()).getHits()).hasSize(9);
// 1 Facet with no filters at all
- Map<String, Collection<FacetValue>> facets = index.search(new RuleQuery(), new QueryContext().setFacet(true)).getFacets();
+ Map<String, Collection<FacetValue>> facets = index.search(new RuleQuery(), new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags"))).getFacets();
assertThat(facets.keySet()).hasSize(3);
assertThat(facets.get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java", "cobol");
assertThat(facets.get(RuleIndex.FACET_REPOSITORIES)).onProperty("key").containsOnly("xoo", "foo");
// -- lang facet should still have all language
Result<Rule> result = index.search(new RuleQuery()
.setLanguages(ImmutableList.<String>of("cpp"))
- , new QueryContext().setFacet(true));
+ , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
assertThat(result.getHits()).hasSize(3);
assertThat(result.getFacets()).hasSize(3);
assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java", "cobol");
result = index.search(new RuleQuery()
.setLanguages(ImmutableList.<String>of("cpp"))
.setTags(ImmutableList.<String>of("T2"))
- , new QueryContext().setFacet(true));
+ , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
assertThat(result.getHits()).hasSize(1);
assertThat(result.getFacets().keySet()).hasSize(3);
assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java");
result = index.search(new RuleQuery()
.setLanguages(ImmutableList.<String>of("cpp", "java"))
.setTags(ImmutableList.<String>of("T2"))
- , new QueryContext().setFacet(true));
+ , new QueryContext().addFacets(Arrays.asList("languages", "repositories", "tags")));
assertThat(result.getHits()).hasSize(2);
assertThat(result.getFacets().keySet()).hasSize(3);
assertThat(result.getFacets().get(RuleIndex.FACET_LANGUAGES)).onProperty("key").containsOnly("cpp", "java");
public void do_not_request_facets_by_default() throws Exception {
assertThat(options.isFacet()).isFalse();
- options.setFacet(true);
+ options.addFacets(Arrays.asList("polop"));
assertThat(options.isFacet()).isTrue();
}
}