diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/search/SearchRequestBuilder.java b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/search/SearchRequestBuilder.java index d10b32964d5..5f1cd2fafa7 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/search/SearchRequestBuilder.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/client/action/search/SearchRequestBuilder.java @@ -367,6 +367,14 @@ public class SearchRequestBuilder extends BaseRequestBuilder facets; + private byte[] facetsBinary; + private HighlightBuilder highlightBuilder; private TObjectFloatHashMap indexBoost = null; @@ -228,6 +230,14 @@ public class SearchSourceBuilder implements ToXContent { return this; } + /** + * Sets a raw (xcontent / json) facets. + */ + public SearchSourceBuilder facets(byte[] facetsBinary) { + this.facetsBinary = facetsBinary; + return this; + } + public HighlightBuilder highlighter() { if (highlightBuilder == null) { highlightBuilder = new HighlightBuilder(); @@ -463,6 +473,14 @@ public class SearchSourceBuilder implements ToXContent { builder.endObject(); } + if (facetsBinary != null) { + if (XContentFactory.xContentType(facetsBinary) == builder.contentType()) { + builder.rawField("facets", facetsBinary); + } else { + builder.field("facets_binary", facetsBinary); + } + } + if (highlightBuilder != null) { highlightBuilder.toXContent(builder, params); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetBinaryParseElement.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetBinaryParseElement.java new file mode 100644 index 00000000000..84514187f5b --- /dev/null +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetBinaryParseElement.java @@ -0,0 +1,46 @@ +/* + * Licensed to Elastic Search and Shay Banon under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. Elastic Search licenses this + * file to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.search.facet; + +import org.elasticsearch.common.inject.Inject; +import org.elasticsearch.common.xcontent.XContentFactory; +import org.elasticsearch.common.xcontent.XContentParser; +import org.elasticsearch.search.internal.SearchContext; + +/** + * @author kimchy (shay.banon) + */ +public class FacetBinaryParseElement extends FacetParseElement { + + @Inject public FacetBinaryParseElement(FacetProcessors facetProcessors) { + super(facetProcessors); + } + + @Override public void parse(XContentParser parser, SearchContext context) throws Exception { + byte[] facetSource = parser.binaryValue(); + XContentParser fSourceParser = XContentFactory.xContent(facetSource).createParser(facetSource); + try { + fSourceParser.nextToken(); // move past the first START_OBJECT + super.parse(fSourceParser, context); + } finally { + fSourceParser.close(); + } + } +} \ No newline at end of file diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetParseElement.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetParseElement.java index ffa7c198fdf..d7cc10b605e 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetParseElement.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetParseElement.java @@ -83,7 +83,7 @@ public class FacetParseElement implements SearchParseElement { } else { FacetProcessor facetProcessor = facetProcessors.processor(facetFieldName); if (facetProcessor == null) { - throw new SearchParseException(context, "No facet type for [" + facetFieldName + "]"); + throw new SearchParseException(context, "No facet type found for [" + facetFieldName + "]"); } facet = facetProcessor.parse(topLevelFieldName, parser, context); } diff --git a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetPhase.java b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetPhase.java index 2d837da575d..9ca4424b788 100644 --- a/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetPhase.java +++ b/modules/elasticsearch/src/main/java/org/elasticsearch/search/facet/FacetPhase.java @@ -44,12 +44,15 @@ public class FacetPhase implements SearchPhase { private final FacetParseElement facetParseElement; - @Inject public FacetPhase(FacetParseElement facetParseElement) { + private final FacetBinaryParseElement facetBinaryParseElement; + + @Inject public FacetPhase(FacetParseElement facetParseElement, FacetBinaryParseElement facetBinaryParseElement) { this.facetParseElement = facetParseElement; + this.facetBinaryParseElement = facetBinaryParseElement; } @Override public Map parseElements() { - return ImmutableMap.of("facets", facetParseElement); + return ImmutableMap.of("facets", facetParseElement, "facets_binary", facetBinaryParseElement, "facetsBinary", facetBinaryParseElement); } @Override public void preProcess(SearchContext context) { diff --git a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java index dd6dfc5a6cf..ace86b2ae73 100644 --- a/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java +++ b/modules/test/integration/src/test/java/org/elasticsearch/test/integration/search/facet/SimpleFacetsTests.java @@ -26,6 +26,7 @@ import org.elasticsearch.client.Client; import org.elasticsearch.common.joda.time.DateTimeZone; import org.elasticsearch.common.joda.time.format.ISODateTimeFormat; import org.elasticsearch.common.unit.TimeValue; +import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.search.facet.datehistogram.DateHistogramFacet; import org.elasticsearch.search.facet.filter.FilterFacet; import org.elasticsearch.search.facet.histogram.HistogramFacet; @@ -73,6 +74,49 @@ public class SimpleFacetsTests extends AbstractNodesTests { return client("server1"); } + @Test public void testBinaryFacet() throws Exception { + try { + client.admin().indices().prepareDelete("test").execute().actionGet(); + } catch (Exception e) { + // ignore + } + client.admin().indices().prepareCreate("test").execute().actionGet(); + client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet(); + + client.admin().cluster().prepareHealth().setWaitForGreenStatus().execute().actionGet(); + + client.prepareIndex("test", "type1").setSource(jsonBuilder().startObject() + .field("tag", "green") + .endObject()).execute().actionGet(); + client.admin().indices().prepareFlush().setRefresh(true).execute().actionGet(); + + client.prepareIndex("test", "type1").setSource(jsonBuilder().startObject() + .field("tag", "blue") + .endObject()).execute().actionGet(); + + client.admin().indices().prepareRefresh().execute().actionGet(); + + SearchResponse searchResponse = client.prepareSearch() + .setQuery(matchAllQuery()) + .setFacets(XContentFactory.jsonBuilder().startObject() + .startObject("facet1") + .startObject("terms") + .field("field", "tag") + .endObject() + .endObject() + .endObject().copiedBytes()) + .execute().actionGet(); + + assertThat(searchResponse.hits().hits().length, equalTo(2)); + TermsFacet facet = searchResponse.facets().facet("facet1"); + assertThat(facet.name(), equalTo("facet1")); + assertThat(facet.entries().size(), equalTo(2)); + assertThat(facet.entries().get(0).term(), anyOf(equalTo("green"), equalTo("blue"))); + assertThat(facet.entries().get(0).count(), equalTo(1)); + assertThat(facet.entries().get(1).term(), anyOf(equalTo("green"), equalTo("blue"))); + assertThat(facet.entries().get(1).count(), equalTo(1)); + } + @Test public void testSearchFilter() throws Exception { try { client.admin().indices().prepareDelete("test").execute().actionGet(); diff --git a/plugins/lang/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy b/plugins/lang/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy index f0cfba8aa50..07fac1430d2 100644 --- a/plugins/lang/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy +++ b/plugins/lang/groovy/src/main/groovy/org/elasticsearch/groovy/client/GClient.groovy @@ -133,6 +133,12 @@ class GClient { SearchRequestBuilder.metaClass.filter = {Closure c -> delegate.setFilter(new GXContentBuilder().buildAsBytes(c, contentType)) } + SearchRequestBuilder.metaClass.setFacets = {Closure c -> + delegate.setFilter(new GXContentBuilder().buildAsBytes(c, contentType)) + } + SearchRequestBuilder.metaClass.facets = {Closure c -> + delegate.setFilter(new GXContentBuilder().buildAsBytes(c, contentType)) + } MoreLikeThisRequest.metaClass.setSearchSource = {Closure c -> delegate.searchSource(new GXContentBuilder().buildAsBytes(c, contentType))