Search API: Query Facet - Add global flag to control if the facet is bounded to the search query or not, closes #50.
This commit is contained in:
parent
40b0dfddec
commit
f4f26d2118
|
@ -58,7 +58,22 @@ public class SearchSourceFacetsBuilder implements ToJson {
|
|||
if (queryFacets == null) {
|
||||
queryFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
queryFacets.add(new FacetQuery(name, query));
|
||||
queryFacets.add(new FacetQuery(name, query, null));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a query facet (which results in a count facet returned) with an option to
|
||||
* be global on the index or bounded by the search query.
|
||||
*
|
||||
* @param name The logical name of the facet, it will be returned under the name
|
||||
* @param query The query facet
|
||||
*/
|
||||
public SearchSourceFacetsBuilder facet(String name, JsonQueryBuilder query, boolean global) {
|
||||
if (queryFacets == null) {
|
||||
queryFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
queryFacets.add(new FacetQuery(name, query, global));
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -78,6 +93,9 @@ public class SearchSourceFacetsBuilder implements ToJson {
|
|||
builder.startObject(facetQuery.name());
|
||||
builder.field("query");
|
||||
facetQuery.queryBuilder().toJson(builder, params);
|
||||
if (facetQuery.global() != null) {
|
||||
builder.field("global", facetQuery.global());
|
||||
}
|
||||
builder.endObject();
|
||||
}
|
||||
}
|
||||
|
@ -88,10 +106,12 @@ public class SearchSourceFacetsBuilder implements ToJson {
|
|||
private static class FacetQuery {
|
||||
private final String name;
|
||||
private final JsonQueryBuilder queryBuilder;
|
||||
private final Boolean global;
|
||||
|
||||
private FacetQuery(String name, JsonQueryBuilder queryBuilder) {
|
||||
private FacetQuery(String name, JsonQueryBuilder queryBuilder, Boolean global) {
|
||||
this.name = name;
|
||||
this.queryBuilder = queryBuilder;
|
||||
this.global = global;
|
||||
}
|
||||
|
||||
public String name() {
|
||||
|
@ -101,5 +121,9 @@ public class SearchSourceFacetsBuilder implements ToJson {
|
|||
public JsonQueryBuilder queryBuilder() {
|
||||
return queryBuilder;
|
||||
}
|
||||
|
||||
public Boolean global() {
|
||||
return this.global;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,7 +36,8 @@ import java.util.List;
|
|||
* facets : {
|
||||
* queryExecution : "collect|idset",
|
||||
* facet1: {
|
||||
* query : { ... }
|
||||
* query : { ... },
|
||||
* global : false
|
||||
* }
|
||||
* }
|
||||
* </pre>
|
||||
|
@ -49,12 +50,12 @@ public class FacetsParseElement implements SearchParseElement {
|
|||
JsonToken token;
|
||||
SearchContextFacets.QueryExecutionType queryExecutionType = SearchContextFacets.QueryExecutionType.COLLECT;
|
||||
List<SearchContextFacets.QueryFacet> queryFacets = null;
|
||||
String topLevelFieldName = null;
|
||||
while ((token = jp.nextToken()) != JsonToken.END_OBJECT) {
|
||||
if (token == JsonToken.FIELD_NAME) {
|
||||
String topLevelFieldName = jp.getCurrentName();
|
||||
|
||||
topLevelFieldName = jp.getCurrentName();
|
||||
} else if (token == JsonToken.VALUE_STRING) {
|
||||
if ("queryExecution".equals(topLevelFieldName)) {
|
||||
jp.nextToken(); // move to value
|
||||
String text = jp.getText();
|
||||
if ("collect".equals(text)) {
|
||||
queryExecutionType = SearchContextFacets.QueryExecutionType.COLLECT;
|
||||
|
@ -63,26 +64,36 @@ public class FacetsParseElement implements SearchParseElement {
|
|||
} else {
|
||||
throw new SearchParseException(context, "Unsupported query type [" + text + "]");
|
||||
}
|
||||
} else {
|
||||
|
||||
jp.nextToken(); // move to START_OBJECT
|
||||
|
||||
jp.nextToken(); // move to FIELD_NAME
|
||||
String facetType = jp.getCurrentName();
|
||||
|
||||
if ("query".equals(facetType)) {
|
||||
}
|
||||
} else if (token == JsonToken.START_OBJECT) {
|
||||
SearchContextFacets.Facet facet = null;
|
||||
boolean global = false;
|
||||
String facetFieldName = null;
|
||||
while ((token = jp.nextToken()) != JsonToken.END_OBJECT) {
|
||||
if (token == JsonToken.FIELD_NAME) {
|
||||
facetFieldName = jp.getCurrentName();
|
||||
} else if (token == JsonToken.START_OBJECT) {
|
||||
if ("query".equals(facetFieldName)) {
|
||||
JsonIndexQueryParser indexQueryParser = (JsonIndexQueryParser) context.queryParser();
|
||||
Query facetQuery = indexQueryParser.parse(jp);
|
||||
|
||||
facet = new SearchContextFacets.QueryFacet(topLevelFieldName, facetQuery);
|
||||
if (queryFacets == null) {
|
||||
queryFacets = Lists.newArrayListWithCapacity(2);
|
||||
}
|
||||
queryFacets.add(new SearchContextFacets.QueryFacet(topLevelFieldName, facetQuery));
|
||||
} else {
|
||||
throw new SearchParseException(context, "Unsupported facet type [" + facetType + "] for facet name [" + topLevelFieldName + "]");
|
||||
queryFacets.add((SearchContextFacets.QueryFacet) facet);
|
||||
}
|
||||
jp.nextToken();
|
||||
} else if (token == JsonToken.VALUE_TRUE) {
|
||||
if ("global".equals(facetFieldName)) {
|
||||
global = true;
|
||||
}
|
||||
} else if (token == JsonToken.VALUE_NUMBER_INT) {
|
||||
global = jp.getIntValue() != 0;
|
||||
}
|
||||
}
|
||||
if (facet == null) {
|
||||
throw new SearchParseException(context, "No facet type found for [" + topLevelFieldName + "]");
|
||||
}
|
||||
facet.global(global);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,7 @@ package org.elasticsearch.search.facets;
|
|||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.search.QueryWrapperFilter;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.apache.lucene.util.OpenBitSet;
|
||||
import org.elasticsearch.ElasticSearchException;
|
||||
import org.elasticsearch.ElasticSearchIllegalStateException;
|
||||
|
@ -38,7 +36,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class FacetsPhase implements SearchPhase {
|
||||
|
||||
|
@ -63,6 +61,15 @@ public class FacetsPhase implements SearchPhase {
|
|||
List<Facet> facets = Lists.newArrayListWithCapacity(2);
|
||||
if (contextFacets.queryFacets() != null) {
|
||||
for (SearchContextFacets.QueryFacet queryFacet : contextFacets.queryFacets()) {
|
||||
if (queryFacet.global()) {
|
||||
try {
|
||||
Query globalQuery = new ConstantScoreQuery(context.filterCache().cache(new QueryWrapperFilter(queryFacet.query())));
|
||||
long count = Lucene.count(context.searcher(), globalQuery, -1.0f);
|
||||
facets.add(new CountFacet(queryFacet.name(), count));
|
||||
} catch (Exception e) {
|
||||
throw new FacetPhaseExecutionException(queryFacet.name(), "Failed to execute global facet [" + queryFacet.query() + "]", e);
|
||||
}
|
||||
} else {
|
||||
Filter facetFilter = new QueryWrapperFilter(queryFacet.query());
|
||||
facetFilter = context.filterCache().cache(facetFilter);
|
||||
long count;
|
||||
|
@ -76,6 +83,7 @@ public class FacetsPhase implements SearchPhase {
|
|||
facets.add(new CountFacet(queryFacet.name(), count));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
context.queryResult().facets(new Facets(facets));
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.apache.lucene.search.Query;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public class SearchContextFacets {
|
||||
|
||||
|
@ -50,7 +50,22 @@ public class SearchContextFacets {
|
|||
return queryFacets;
|
||||
}
|
||||
|
||||
public static class QueryFacet {
|
||||
public static abstract class Facet {
|
||||
private boolean global;
|
||||
|
||||
protected Facet() {
|
||||
}
|
||||
|
||||
public boolean global() {
|
||||
return global;
|
||||
}
|
||||
|
||||
public void global(boolean global) {
|
||||
this.global = global;
|
||||
}
|
||||
}
|
||||
|
||||
public static class QueryFacet extends Facet {
|
||||
private final String name;
|
||||
private final Query query;
|
||||
|
||||
|
|
|
@ -222,7 +222,7 @@ public class TransportTwoServersSearchTests extends AbstractServersTests {
|
|||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(20).explain(true)
|
||||
.facets(facets().facet("all", termQuery("multi", "test")).facet("test1", termQuery("name", "test1")));
|
||||
.facets(facets().facet("all", termQuery("multi", "test"), true).facet("test1", termQuery("name", "test1")));
|
||||
|
||||
SearchResponse searchResponse = client.search(searchRequest("test").source(sourceBuilder)).actionGet();
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(100l));
|
||||
|
|
Loading…
Reference in New Issue