refactoring of facets to be more open for different facet types
This commit is contained in:
parent
d9d9304f47
commit
88ba980f79
|
@ -254,7 +254,7 @@ public class SearchRequestBuilder {
|
|||
* @param name The logical name of the facet, it will be returned under the name
|
||||
* @param query The query facet
|
||||
*/
|
||||
public SearchRequestBuilder addQueryFacet(String name, XContentQueryBuilder query) {
|
||||
public SearchRequestBuilder addFacetQuery(String name, XContentQueryBuilder query) {
|
||||
facetsBuilder().queryFacet(name, query);
|
||||
return this;
|
||||
}
|
||||
|
@ -263,22 +263,21 @@ public class SearchRequestBuilder {
|
|||
* 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
|
||||
* @param global Should the facet be executed globally or not
|
||||
* @param name The logical name of the facet, it will be returned under the name
|
||||
* @param query The query facet
|
||||
*/
|
||||
public SearchRequestBuilder addQueryFacet(String name, XContentQueryBuilder query, boolean global) {
|
||||
facetsBuilder().queryFacet(name, query, global);
|
||||
public SearchRequestBuilder addFacetGlobalQuery(String name, XContentQueryBuilder query) {
|
||||
facetsBuilder().queryFacetGlobal(name, query);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchRequestBuilder addTermFacet(String name, String fieldName, int size) {
|
||||
facetsBuilder().termFacet(name, fieldName, size);
|
||||
public SearchRequestBuilder addFacetTerms(String name, String fieldName, int size) {
|
||||
facetsBuilder().termsFacet(name, fieldName, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchRequestBuilder addTermFacet(String name, String fieldName, int size, boolean global) {
|
||||
facetsBuilder().termFacet(name, fieldName, size, global);
|
||||
public SearchRequestBuilder addFacetGlobalTerms(String name, String fieldName, int size) {
|
||||
facetsBuilder().termsFacetGlobal(name, fieldName, size);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
|
|
@ -20,8 +20,8 @@
|
|||
package org.elasticsearch.search.builder;
|
||||
|
||||
import org.elasticsearch.index.query.xcontent.XContentQueryBuilder;
|
||||
import org.elasticsearch.search.facets.collector.query.QueryFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.collector.term.TermFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.query.QueryFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.terms.TermFacetCollectorParser;
|
||||
import org.elasticsearch.util.xcontent.ToXContent;
|
||||
import org.elasticsearch.util.xcontent.builder.XContentBuilder;
|
||||
|
||||
|
@ -39,7 +39,7 @@ import static org.elasticsearch.util.collect.Lists.*;
|
|||
public class SearchSourceFacetsBuilder implements ToXContent {
|
||||
|
||||
private List<QueryFacet> queryFacets;
|
||||
private List<TermFacet> termFacets;
|
||||
private List<TermsFacet> termsFacets;
|
||||
|
||||
/**
|
||||
* Adds a query facet (which results in a count facet returned).
|
||||
|
@ -48,7 +48,11 @@ public class SearchSourceFacetsBuilder implements ToXContent {
|
|||
* @param query The query facet
|
||||
*/
|
||||
public SearchSourceFacetsBuilder queryFacet(String name, XContentQueryBuilder query) {
|
||||
return queryFacet(name, query, null);
|
||||
if (queryFacets == null) {
|
||||
queryFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
queryFacets.add(new QueryFacet(name, query, false));
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -59,28 +63,32 @@ public class SearchSourceFacetsBuilder implements ToXContent {
|
|||
* @param query The query facet
|
||||
* @param global Should the facet be executed globally or not
|
||||
*/
|
||||
public SearchSourceFacetsBuilder queryFacet(String name, XContentQueryBuilder query, Boolean global) {
|
||||
public SearchSourceFacetsBuilder queryFacetGlobal(String name, XContentQueryBuilder query) {
|
||||
if (queryFacets == null) {
|
||||
queryFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
queryFacets.add(new QueryFacet(name, query, global));
|
||||
queryFacets.add(new QueryFacet(name, query, true));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchSourceFacetsBuilder termFacet(String name, String fieldName, int size) {
|
||||
return termFacet(name, fieldName, size, null);
|
||||
public SearchSourceFacetsBuilder termsFacet(String name, String fieldName, int size) {
|
||||
if (termsFacets == null) {
|
||||
termsFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
termsFacets.add(new TermsFacet(name, fieldName, size, false));
|
||||
return this;
|
||||
}
|
||||
|
||||
public SearchSourceFacetsBuilder termFacet(String name, String fieldName, int size, Boolean global) {
|
||||
if (termFacets == null) {
|
||||
termFacets = newArrayListWithCapacity(2);
|
||||
public SearchSourceFacetsBuilder termsFacetGlobal(String name, String fieldName, int size) {
|
||||
if (termsFacets == null) {
|
||||
termsFacets = newArrayListWithCapacity(2);
|
||||
}
|
||||
termFacets.add(new TermFacet(name, fieldName, size, global));
|
||||
termsFacets.add(new TermsFacet(name, fieldName, size, true));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
if (queryFacets == null && termFacets == null) {
|
||||
if (queryFacets == null && termsFacets == null) {
|
||||
return;
|
||||
}
|
||||
builder.field("facets");
|
||||
|
@ -98,17 +106,17 @@ public class SearchSourceFacetsBuilder implements ToXContent {
|
|||
builder.endObject();
|
||||
}
|
||||
}
|
||||
if (termFacets != null) {
|
||||
for (TermFacet termFacet : termFacets) {
|
||||
builder.startObject(termFacet.name());
|
||||
if (termsFacets != null) {
|
||||
for (TermsFacet termsFacet : termsFacets) {
|
||||
builder.startObject(termsFacet.name());
|
||||
|
||||
builder.startObject(TermFacetCollectorParser.NAME);
|
||||
builder.field("field", termFacet.fieldName());
|
||||
builder.field("size", termFacet.size());
|
||||
builder.field("field", termsFacet.fieldName());
|
||||
builder.field("size", termsFacet.size());
|
||||
builder.endObject();
|
||||
|
||||
if (termFacet.global() != null) {
|
||||
builder.field("global", termFacet.global());
|
||||
if (termsFacet.global() != null) {
|
||||
builder.field("global", termsFacet.global());
|
||||
}
|
||||
|
||||
builder.endObject();
|
||||
|
@ -118,13 +126,13 @@ public class SearchSourceFacetsBuilder implements ToXContent {
|
|||
builder.endObject();
|
||||
}
|
||||
|
||||
private static class TermFacet {
|
||||
private static class TermsFacet {
|
||||
private final String name;
|
||||
private final String fieldName;
|
||||
private final int size;
|
||||
private final Boolean global;
|
||||
|
||||
private TermFacet(String name, String fieldName, int size, Boolean global) {
|
||||
private TermsFacet(String name, String fieldName, int size, Boolean global) {
|
||||
this.name = name;
|
||||
this.fieldName = fieldName;
|
||||
this.size = size;
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.elasticsearch.search.dfs.AggregatedDfs;
|
|||
import org.elasticsearch.search.dfs.DfsSearchResult;
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.search.facets.Facets;
|
||||
import org.elasticsearch.search.facets.internal.InternalFacet;
|
||||
import org.elasticsearch.search.facets.InternalFacet;
|
||||
import org.elasticsearch.search.fetch.FetchSearchResult;
|
||||
import org.elasticsearch.search.fetch.FetchSearchResultProvider;
|
||||
import org.elasticsearch.search.internal.InternalSearchHit;
|
||||
|
|
|
@ -32,24 +32,24 @@ public interface Facet {
|
|||
/**
|
||||
* Count type facet.
|
||||
*/
|
||||
COUNT((byte) 0),
|
||||
MULTI_COUNT((byte) 1);
|
||||
TERMS(0),
|
||||
QUERY(1);
|
||||
|
||||
byte id;
|
||||
int id;
|
||||
|
||||
Type(byte id) {
|
||||
Type(int id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte id() {
|
||||
public int id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static Type fromId(byte id) {
|
||||
public static Type fromId(int id) {
|
||||
if (id == 0) {
|
||||
return COUNT;
|
||||
return TERMS;
|
||||
} else if (id == 1) {
|
||||
return MULTI_COUNT;
|
||||
return QUERY;
|
||||
} else {
|
||||
throw new ElasticSearchIllegalArgumentException("No match for id [" + id + "]");
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@
|
|||
|
||||
package org.elasticsearch.search.facets;
|
||||
|
||||
import org.elasticsearch.search.facets.internal.InternalFacet;
|
||||
import org.elasticsearch.search.facets.query.InternalQueryFacet;
|
||||
import org.elasticsearch.search.facets.terms.InternalTermsFacet;
|
||||
import org.elasticsearch.util.collect.ImmutableList;
|
||||
import org.elasticsearch.util.io.stream.StreamInput;
|
||||
import org.elasticsearch.util.io.stream.StreamOutput;
|
||||
|
@ -32,8 +33,6 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.elasticsearch.search.facets.internal.InternalCountFacet.*;
|
||||
import static org.elasticsearch.search.facets.internal.InternalMultiCountFacet.*;
|
||||
import static org.elasticsearch.util.collect.Lists.*;
|
||||
import static org.elasticsearch.util.collect.Maps.*;
|
||||
|
||||
|
@ -98,10 +97,10 @@ public class Facets implements Streamable, ToXContent, Iterable<Facet> {
|
|||
}
|
||||
|
||||
/**
|
||||
* A specific count facet against the registered facet name.
|
||||
* Returns the facet by name already casted to the specified type.
|
||||
*/
|
||||
public CountFacet countFacet(String name) {
|
||||
return (CountFacet) facet(name);
|
||||
public <T extends Facet> T facet(Class<T> facetType, String name) {
|
||||
return facetType.cast(facet(name));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -132,11 +131,11 @@ public class Facets implements Streamable, ToXContent, Iterable<Facet> {
|
|||
} else {
|
||||
facets = newArrayListWithCapacity(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
byte id = in.readByte();
|
||||
if (id == Facet.Type.COUNT.id()) {
|
||||
facets.add(readCountFacet(in));
|
||||
} else if (id == Facet.Type.MULTI_COUNT.id()) {
|
||||
facets.add(readMultiCountFacet(in));
|
||||
int id = in.readVInt();
|
||||
if (id == Facet.Type.TERMS.id()) {
|
||||
facets.add(InternalTermsFacet.readTermsFacet(in));
|
||||
} else if (id == Facet.Type.QUERY.id()) {
|
||||
facets.add(InternalQueryFacet.readCountFacet(in));
|
||||
} else {
|
||||
throw new IOException("Can't handle facet type with id [" + id + "]");
|
||||
}
|
||||
|
@ -147,7 +146,7 @@ public class Facets implements Streamable, ToXContent, Iterable<Facet> {
|
|||
@Override public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeVInt(facets.size());
|
||||
for (Facet facet : facets) {
|
||||
out.writeByte(facet.type().id());
|
||||
out.writeVInt(facet.type().id());
|
||||
((InternalFacet) facet).writeTo(out);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,8 +23,8 @@ import org.elasticsearch.search.SearchParseElement;
|
|||
import org.elasticsearch.search.SearchParseException;
|
||||
import org.elasticsearch.search.facets.collector.FacetCollector;
|
||||
import org.elasticsearch.search.facets.collector.FacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.collector.query.QueryFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.collector.term.TermFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.query.QueryFacetCollectorParser;
|
||||
import org.elasticsearch.search.facets.terms.TermFacetCollectorParser;
|
||||
import org.elasticsearch.search.internal.SearchContext;
|
||||
import org.elasticsearch.util.MapBuilder;
|
||||
import org.elasticsearch.util.collect.ImmutableMap;
|
||||
|
|
|
@ -17,9 +17,8 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.internal;
|
||||
package org.elasticsearch.search.facets;
|
||||
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.util.io.stream.Streamable;
|
||||
import org.elasticsearch.util.xcontent.ToXContent;
|
||||
|
|
@ -17,10 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.internal;
|
||||
package org.elasticsearch.search.facets.query;
|
||||
|
||||
import org.elasticsearch.search.facets.CountFacet;
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.search.facets.InternalFacet;
|
||||
import org.elasticsearch.util.io.stream.StreamInput;
|
||||
import org.elasticsearch.util.io.stream.StreamOutput;
|
||||
import org.elasticsearch.util.xcontent.builder.XContentBuilder;
|
||||
|
@ -30,23 +30,23 @@ import java.io.IOException;
|
|||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
*/
|
||||
public class InternalCountFacet implements CountFacet, InternalFacet {
|
||||
public class InternalQueryFacet implements QueryFacet, InternalFacet {
|
||||
|
||||
private String name;
|
||||
|
||||
private long count;
|
||||
|
||||
private InternalCountFacet() {
|
||||
private InternalQueryFacet() {
|
||||
|
||||
}
|
||||
|
||||
public InternalCountFacet(String name, long count) {
|
||||
public InternalQueryFacet(String name, long count) {
|
||||
this.name = name;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
@Override public Type type() {
|
||||
return Type.COUNT;
|
||||
return Type.QUERY;
|
||||
}
|
||||
|
||||
@Override public Type getType() {
|
||||
|
@ -86,18 +86,21 @@ public class InternalCountFacet implements CountFacet, InternalFacet {
|
|||
int count = 0;
|
||||
for (Facet facet : facets) {
|
||||
if (facet.name().equals(name)) {
|
||||
count += ((InternalCountFacet) facet).count();
|
||||
count += ((QueryFacet) facet).count();
|
||||
}
|
||||
}
|
||||
return new InternalCountFacet(name, count);
|
||||
return new InternalQueryFacet(name, count);
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.field(name, count);
|
||||
builder.startObject(name);
|
||||
builder.field("_type", "query");
|
||||
builder.field("count", count);
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
public static CountFacet readCountFacet(StreamInput in) throws IOException {
|
||||
InternalCountFacet result = new InternalCountFacet();
|
||||
public static QueryFacet readCountFacet(StreamInput in) throws IOException {
|
||||
InternalQueryFacet result = new InternalQueryFacet();
|
||||
result.readFrom(in);
|
||||
return result;
|
||||
}
|
||||
|
@ -111,5 +114,4 @@ public class InternalCountFacet implements CountFacet, InternalFacet {
|
|||
out.writeUTF(name);
|
||||
out.writeVLong(count);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -17,14 +17,16 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets;
|
||||
package org.elasticsearch.search.facets.query;
|
||||
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
|
||||
/**
|
||||
* A count facet is a facet that holds a count.
|
||||
* A query facets returns the count (number of hits) for a facet based on a query.
|
||||
*
|
||||
* @author kimchy (shay.banon)
|
||||
*/
|
||||
public interface CountFacet extends Facet {
|
||||
public interface QueryFacet extends Facet {
|
||||
|
||||
/**
|
||||
* The count of the facet.
|
||||
|
@ -35,4 +37,4 @@ public interface CountFacet extends Facet {
|
|||
* The count of the facet.
|
||||
*/
|
||||
long getCount();
|
||||
}
|
||||
}
|
|
@ -17,14 +17,13 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.collector.query;
|
||||
package org.elasticsearch.search.facets.query;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.*;
|
||||
import org.elasticsearch.index.cache.filter.FilterCache;
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.search.facets.collector.FacetCollector;
|
||||
import org.elasticsearch.search.facets.internal.InternalCountFacet;
|
||||
import org.elasticsearch.util.lucene.docset.DocSet;
|
||||
import org.elasticsearch.util.lucene.docset.DocSets;
|
||||
|
||||
|
@ -72,6 +71,6 @@ public class QueryFacetCollector extends FacetCollector {
|
|||
}
|
||||
|
||||
@Override public Facet facet() {
|
||||
return new InternalCountFacet(name, count);
|
||||
return new InternalQueryFacet(name, count);
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.collector.query;
|
||||
package org.elasticsearch.search.facets.query;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.elasticsearch.index.query.xcontent.XContentIndexQueryParser;
|
|
@ -17,10 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.internal;
|
||||
package org.elasticsearch.search.facets.terms;
|
||||
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.search.facets.MultiCountFacet;
|
||||
import org.elasticsearch.search.facets.InternalFacet;
|
||||
import org.elasticsearch.util.BoundedTreeSet;
|
||||
import org.elasticsearch.util.ThreadLocals;
|
||||
import org.elasticsearch.util.collect.ImmutableList;
|
||||
|
@ -40,24 +40,21 @@ import java.util.List;
|
|||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
*/
|
||||
public class InternalMultiCountFacet<T extends Comparable> implements InternalFacet, MultiCountFacet<T> {
|
||||
public class InternalTermsFacet implements InternalFacet, TermsFacet {
|
||||
|
||||
private String name;
|
||||
|
||||
private int requiredSize;
|
||||
|
||||
private Collection<Entry<T>> entries = ImmutableList.of();
|
||||
|
||||
private ValueType valueType;
|
||||
private Collection<Entry> entries = ImmutableList.of();
|
||||
|
||||
private ComparatorType comparatorType;
|
||||
|
||||
private InternalMultiCountFacet() {
|
||||
private InternalTermsFacet() {
|
||||
}
|
||||
|
||||
public InternalMultiCountFacet(String name, ValueType valueType, ComparatorType comparatorType, int requiredSize, Collection<Entry<T>> entries) {
|
||||
public InternalTermsFacet(String name, ComparatorType comparatorType, int requiredSize, Collection<Entry> entries) {
|
||||
this.name = name;
|
||||
this.valueType = valueType;
|
||||
this.comparatorType = comparatorType;
|
||||
this.requiredSize = requiredSize;
|
||||
this.entries = entries;
|
||||
|
@ -72,130 +69,96 @@ public class InternalMultiCountFacet<T extends Comparable> implements InternalFa
|
|||
}
|
||||
|
||||
@Override public Type type() {
|
||||
return Type.MULTI_COUNT;
|
||||
return Type.TERMS;
|
||||
}
|
||||
|
||||
@Override public Type getType() {
|
||||
return type();
|
||||
}
|
||||
|
||||
public ValueType valueType() {
|
||||
return valueType;
|
||||
}
|
||||
|
||||
public ValueType getValueType() {
|
||||
return valueType();
|
||||
}
|
||||
|
||||
@Override public List<Entry<T>> entries() {
|
||||
@Override public List<Entry> entries() {
|
||||
return Lists.newArrayList(this);
|
||||
}
|
||||
|
||||
@Override public List<Entry<T>> getEntries() {
|
||||
@Override public List<Entry> getEntries() {
|
||||
return Lists.newArrayList(this);
|
||||
}
|
||||
|
||||
@Override public Iterator<Entry<T>> iterator() {
|
||||
@Override public Iterator<Entry> iterator() {
|
||||
return entries.iterator();
|
||||
}
|
||||
|
||||
private static ThreadLocal<ThreadLocals.CleanableValue<TObjectIntHashMap<Object>>> aggregateCache = new ThreadLocal<ThreadLocals.CleanableValue<TObjectIntHashMap<Object>>>() {
|
||||
@Override protected ThreadLocals.CleanableValue<TObjectIntHashMap<Object>> initialValue() {
|
||||
return new ThreadLocals.CleanableValue<TObjectIntHashMap<java.lang.Object>>(new TObjectIntHashMap<Object>());
|
||||
private static ThreadLocal<ThreadLocals.CleanableValue<TObjectIntHashMap<String>>> aggregateCache = new ThreadLocal<ThreadLocals.CleanableValue<TObjectIntHashMap<String>>>() {
|
||||
@Override protected ThreadLocals.CleanableValue<TObjectIntHashMap<String>> initialValue() {
|
||||
return new ThreadLocals.CleanableValue<TObjectIntHashMap<String>>(new TObjectIntHashMap<String>());
|
||||
}
|
||||
};
|
||||
|
||||
@Override public Facet aggregate(Iterable<Facet> facets) {
|
||||
TObjectIntHashMap<Object> aggregated = aggregateCache.get().get();
|
||||
TObjectIntHashMap<String> aggregated = aggregateCache.get().get();
|
||||
aggregated.clear();
|
||||
|
||||
for (Facet facet : facets) {
|
||||
if (!facet.name().equals(name)) {
|
||||
continue;
|
||||
}
|
||||
MultiCountFacet<T> mFacet = (MultiCountFacet<T>) facet;
|
||||
for (Entry<T> entry : mFacet) {
|
||||
aggregated.adjustOrPutValue(entry.value(), entry.count(), entry.count());
|
||||
TermsFacet mFacet = (TermsFacet) facet;
|
||||
for (Entry entry : mFacet) {
|
||||
aggregated.adjustOrPutValue(entry.term(), entry.count(), entry.count());
|
||||
}
|
||||
}
|
||||
|
||||
BoundedTreeSet<Entry<T>> ordered = new BoundedTreeSet<Entry<T>>(comparatorType.comparator(), requiredSize);
|
||||
for (TObjectIntIterator<Object> it = aggregated.iterator(); it.hasNext();) {
|
||||
BoundedTreeSet<Entry> ordered = new BoundedTreeSet<Entry>(comparatorType.comparator(), requiredSize);
|
||||
for (TObjectIntIterator<String> it = aggregated.iterator(); it.hasNext();) {
|
||||
it.advance();
|
||||
ordered.add(new Entry<T>((T) it.key(), it.value()));
|
||||
ordered.add(new Entry(it.key(), it.value()));
|
||||
}
|
||||
|
||||
return new InternalMultiCountFacet<T>(name, valueType, comparatorType, requiredSize, ordered);
|
||||
return new InternalTermsFacet(name, comparatorType, requiredSize, ordered);
|
||||
}
|
||||
|
||||
@Override public void toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||
builder.startArray(name());
|
||||
for (Entry<T> entry : entries) {
|
||||
builder.startObject(name);
|
||||
builder.field("_type", "terms");
|
||||
builder.startArray("terms");
|
||||
for (Entry entry : entries) {
|
||||
builder.startObject();
|
||||
builder.field("value", entry.value());
|
||||
builder.field("term", entry.term());
|
||||
builder.field("count", entry.count());
|
||||
builder.endObject();
|
||||
}
|
||||
builder.endArray();
|
||||
builder.endObject();
|
||||
}
|
||||
|
||||
public static InternalMultiCountFacet readMultiCountFacet(StreamInput in) throws IOException {
|
||||
InternalMultiCountFacet facet = new InternalMultiCountFacet();
|
||||
public static InternalTermsFacet readTermsFacet(StreamInput in) throws IOException {
|
||||
InternalTermsFacet facet = new InternalTermsFacet();
|
||||
facet.readFrom(in);
|
||||
return facet;
|
||||
}
|
||||
|
||||
@Override public void readFrom(StreamInput in) throws IOException {
|
||||
name = in.readUTF();
|
||||
valueType = ValueType.fromId(in.readByte());
|
||||
comparatorType = ComparatorType.fromId(in.readByte());
|
||||
requiredSize = in.readVInt();
|
||||
|
||||
int size = in.readVInt();
|
||||
entries = new ArrayList<Entry<T>>(size);
|
||||
entries = new ArrayList<Entry>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
Object value = null;
|
||||
if (valueType == ValueType.STRING) {
|
||||
value = in.readUTF();
|
||||
} else if (valueType == ValueType.SHORT) {
|
||||
value = in.readShort();
|
||||
} else if (valueType == ValueType.INT) {
|
||||
value = in.readInt();
|
||||
} else if (valueType == ValueType.LONG) {
|
||||
value = in.readLong();
|
||||
} else if (valueType == ValueType.FLOAT) {
|
||||
value = in.readFloat();
|
||||
} else if (valueType == ValueType.DOUBLE) {
|
||||
value = in.readDouble();
|
||||
}
|
||||
|
||||
entries.add(new Entry<T>((T) value, in.readVInt()));
|
||||
entries.add(new Entry(in.readUTF(), in.readVInt()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void writeTo(StreamOutput out) throws IOException {
|
||||
out.writeUTF(name);
|
||||
out.writeByte(valueType.id());
|
||||
out.writeByte(comparatorType.id());
|
||||
|
||||
out.writeVInt(requiredSize);
|
||||
|
||||
out.writeVInt(entries.size());
|
||||
for (Entry<T> entry : entries) {
|
||||
if (valueType == ValueType.STRING) {
|
||||
out.writeUTF((String) entry.value());
|
||||
} else if (valueType == ValueType.SHORT) {
|
||||
out.writeShort((Short) entry.value());
|
||||
} else if (valueType == ValueType.INT) {
|
||||
out.writeInt((Integer) entry.value());
|
||||
} else if (valueType == ValueType.LONG) {
|
||||
out.writeLong((Long) entry.value());
|
||||
} else if (valueType == ValueType.FLOAT) {
|
||||
out.writeFloat((Float) entry.value());
|
||||
} else if (valueType == ValueType.DOUBLE) {
|
||||
out.writeDouble((Double) entry.value());
|
||||
}
|
||||
for (Entry entry : entries) {
|
||||
out.writeUTF(entry.term());
|
||||
out.writeVInt(entry.count());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.collector.term;
|
||||
package org.elasticsearch.search.facets.terms;
|
||||
|
||||
import org.apache.lucene.index.IndexReader;
|
||||
import org.apache.lucene.search.Scorer;
|
||||
|
@ -26,9 +26,7 @@ import org.elasticsearch.index.field.FieldData;
|
|||
import org.elasticsearch.index.mapper.FieldMapper;
|
||||
import org.elasticsearch.index.mapper.MapperService;
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
import org.elasticsearch.search.facets.MultiCountFacet;
|
||||
import org.elasticsearch.search.facets.collector.FacetCollector;
|
||||
import org.elasticsearch.search.facets.internal.InternalMultiCountFacet;
|
||||
import org.elasticsearch.util.BoundedTreeSet;
|
||||
import org.elasticsearch.util.ThreadLocals;
|
||||
import org.elasticsearch.util.collect.ImmutableList;
|
||||
|
@ -104,15 +102,15 @@ public class TermFacetCollector extends FacetCollector {
|
|||
TObjectIntHashMap<String> facets = aggregator.facets();
|
||||
if (facets.isEmpty()) {
|
||||
pushFacets(facets);
|
||||
return new InternalMultiCountFacet<String>(name, MultiCountFacet.ValueType.STRING, MultiCountFacet.ComparatorType.COUNT, size, ImmutableList.<MultiCountFacet.Entry<String>>of());
|
||||
return new InternalTermsFacet(name, InternalTermsFacet.ComparatorType.COUNT, size, ImmutableList.<InternalTermsFacet.Entry>of());
|
||||
} else {
|
||||
BoundedTreeSet<MultiCountFacet.Entry<String>> ordered = new BoundedTreeSet<MultiCountFacet.Entry<String>>(MultiCountFacet.ComparatorType.COUNT.comparator(), size);
|
||||
BoundedTreeSet<InternalTermsFacet.Entry> ordered = new BoundedTreeSet<InternalTermsFacet.Entry>(InternalTermsFacet.ComparatorType.COUNT.comparator(), size);
|
||||
for (TObjectIntIterator<String> it = facets.iterator(); it.hasNext();) {
|
||||
it.advance();
|
||||
ordered.add(new MultiCountFacet.Entry<String>(it.key(), it.value()));
|
||||
ordered.add(new InternalTermsFacet.Entry(it.key(), it.value()));
|
||||
}
|
||||
pushFacets(facets);
|
||||
return new InternalMultiCountFacet<String>(name, MultiCountFacet.ValueType.STRING, MultiCountFacet.ComparatorType.COUNT, size, ordered);
|
||||
return new InternalTermsFacet(name, InternalTermsFacet.ComparatorType.COUNT, size, ordered);
|
||||
}
|
||||
}
|
||||
|
|
@ -17,7 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets.collector.term;
|
||||
package org.elasticsearch.search.facets.terms;
|
||||
|
||||
import org.elasticsearch.search.facets.collector.FacetCollector;
|
||||
import org.elasticsearch.search.facets.collector.FacetCollectorParser;
|
||||
|
@ -31,7 +31,7 @@ import java.io.IOException;
|
|||
*/
|
||||
public class TermFacetCollectorParser implements FacetCollectorParser {
|
||||
|
||||
public static final String NAME = "term";
|
||||
public static final String NAME = "terms";
|
||||
|
||||
@Override public String name() {
|
||||
return NAME;
|
|
@ -17,9 +17,10 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
package org.elasticsearch.search.facets;
|
||||
package org.elasticsearch.search.facets.terms;
|
||||
|
||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||
import org.elasticsearch.search.facets.Facet;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
@ -27,7 +28,7 @@ import java.util.List;
|
|||
/**
|
||||
* @author kimchy (Shay Banon)
|
||||
*/
|
||||
public interface MultiCountFacet<T extends Comparable> extends Facet, Iterable<MultiCountFacet.Entry<T>> {
|
||||
public interface TermsFacet extends Facet, Iterable<TermsFacet.Entry> {
|
||||
|
||||
public static enum ComparatorType {
|
||||
COUNT((byte) 0, new Comparator<Entry>() {
|
||||
|
@ -35,7 +36,7 @@ public interface MultiCountFacet<T extends Comparable> extends Facet, Iterable<M
|
|||
@Override public int compare(Entry o1, Entry o2) {
|
||||
int i = o2.count() - o1.count();
|
||||
if (i == 0) {
|
||||
i = o2.value().compareTo(o1.value());
|
||||
i = o2.term().compareTo(o1.term());
|
||||
if (i == 0) {
|
||||
i = System.identityHashCode(o2) - System.identityHashCode(o1);
|
||||
}
|
||||
|
@ -43,10 +44,10 @@ public interface MultiCountFacet<T extends Comparable> extends Facet, Iterable<M
|
|||
return i;
|
||||
}
|
||||
}),
|
||||
VALUE((byte) 1, new Comparator<Entry>() {
|
||||
TERM((byte) 1, new Comparator<Entry>() {
|
||||
|
||||
@Override public int compare(Entry o1, Entry o2) {
|
||||
int i = o2.value().compareTo(o1.value());
|
||||
int i = o2.term().compareTo(o1.term());
|
||||
if (i == 0) {
|
||||
i = o2.count() - o1.count();
|
||||
if (i == 0) {
|
||||
|
@ -78,83 +79,28 @@ public interface MultiCountFacet<T extends Comparable> extends Facet, Iterable<M
|
|||
if (id == 0) {
|
||||
return COUNT;
|
||||
} else if (id == 1) {
|
||||
return VALUE;
|
||||
return TERM;
|
||||
}
|
||||
throw new ElasticSearchIllegalArgumentException("No type argument match for multi count comparator [" + id + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public static enum ValueType {
|
||||
STRING((byte) 0),
|
||||
SHORT((byte) 1),
|
||||
INT((byte) 2),
|
||||
LONG((byte) 3),
|
||||
FLOAT((byte) 4),
|
||||
DOUBLE((byte) 5);
|
||||
public class Entry {
|
||||
|
||||
private final byte id;
|
||||
|
||||
ValueType(byte id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public byte id() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public static ValueType fromId(byte id) {
|
||||
if (id == 0) {
|
||||
return STRING;
|
||||
} else if (id == 1) {
|
||||
return SHORT;
|
||||
} else if (id == 2) {
|
||||
return INT;
|
||||
} else if (id == 3) {
|
||||
return LONG;
|
||||
} else if (id == 4) {
|
||||
return FLOAT;
|
||||
} else if (id == 5) {
|
||||
return DOUBLE;
|
||||
}
|
||||
throw new ElasticSearchIllegalArgumentException("No type argument match for multi count facet [" + id + "]");
|
||||
}
|
||||
}
|
||||
|
||||
public class Entry<T extends Comparable> {
|
||||
|
||||
private T value;
|
||||
private String term;
|
||||
private int count;
|
||||
|
||||
public Entry(T value, int count) {
|
||||
this.value = value;
|
||||
public Entry(String term, int count) {
|
||||
this.term = term;
|
||||
this.count = count;
|
||||
}
|
||||
|
||||
public T value() {
|
||||
return value;
|
||||
public String term() {
|
||||
return term;
|
||||
}
|
||||
|
||||
public T getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public String valueAsString() {
|
||||
return value.toString();
|
||||
}
|
||||
|
||||
public String getValueAsString() {
|
||||
return valueAsString();
|
||||
}
|
||||
|
||||
public Number valueAsNumber() {
|
||||
if (value instanceof Number) {
|
||||
return (Number) value;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public Number getValueAsNumber() {
|
||||
return valueAsNumber();
|
||||
public String getTerm() {
|
||||
return term;
|
||||
}
|
||||
|
||||
public int count() {
|
||||
|
@ -166,12 +112,7 @@ public interface MultiCountFacet<T extends Comparable> extends Facet, Iterable<M
|
|||
}
|
||||
}
|
||||
|
||||
List<Entry> entries();
|
||||
|
||||
ValueType valueType();
|
||||
|
||||
ValueType getValueType();
|
||||
|
||||
List<Entry<T>> entries();
|
||||
|
||||
List<Entry<T>> getEntries();
|
||||
}
|
||||
List<Entry> getEntries();
|
||||
}
|
|
@ -30,6 +30,7 @@ import org.elasticsearch.search.controller.SearchPhaseController;
|
|||
import org.elasticsearch.search.controller.ShardDoc;
|
||||
import org.elasticsearch.search.dfs.AggregatedDfs;
|
||||
import org.elasticsearch.search.dfs.DfsSearchResult;
|
||||
import org.elasticsearch.search.facets.query.QueryFacet;
|
||||
import org.elasticsearch.search.fetch.FetchSearchRequest;
|
||||
import org.elasticsearch.search.fetch.FetchSearchResult;
|
||||
import org.elasticsearch.search.fetch.QueryFetchSearchResult;
|
||||
|
@ -150,8 +151,8 @@ public class SingleInstanceEmbeddedSearchTests extends AbstractNodesTests {
|
|||
searchSource().query(wildcardQuery("name", "te*"))
|
||||
.facets(facets().queryFacet("age2", termQuery("age", 2)).queryFacet("age1", termQuery("age", 1)))
|
||||
));
|
||||
assertThat(queryResult.facets().countFacet("age2").count(), equalTo(4l));
|
||||
assertThat(queryResult.facets().countFacet("age1").count(), equalTo(1l));
|
||||
assertThat(queryResult.facets().facet(QueryFacet.class, "age2").count(), equalTo(4l));
|
||||
assertThat(queryResult.facets().facet(QueryFacet.class, "age1").count(), equalTo(1l));
|
||||
}
|
||||
|
||||
@Test public void testQueryFetchKeepAliveTimeout() throws Exception {
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.elasticsearch.client.Requests;
|
|||
import org.elasticsearch.search.Scroll;
|
||||
import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.builder.SearchSourceBuilder;
|
||||
import org.elasticsearch.search.facets.query.QueryFacet;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.elasticsearch.util.Unicode;
|
||||
import org.elasticsearch.util.collect.Sets;
|
||||
|
@ -253,14 +254,14 @@ public class TransportTwoServersSearchTests extends AbstractNodesTests {
|
|||
SearchSourceBuilder sourceBuilder = searchSource()
|
||||
.query(termQuery("multi", "test"))
|
||||
.from(0).size(20).explain(true)
|
||||
.facets(facets().queryFacet("all", termQuery("multi", "test"), true).queryFacet("test1", termQuery("name", "test1")));
|
||||
.facets(facets().queryFacetGlobal("all", termQuery("multi", "test")).queryFacet("test1", termQuery("name", "test1")));
|
||||
|
||||
SearchResponse searchResponse = client.search(searchRequest("test").source(sourceBuilder)).actionGet();
|
||||
assertThat("Failures " + Arrays.toString(searchResponse.shardFailures()), searchResponse.shardFailures().length, equalTo(0));
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(100l));
|
||||
|
||||
assertThat(searchResponse.facets().countFacet("test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().countFacet("all").count(), equalTo(100l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "all").count(), equalTo(100l));
|
||||
}
|
||||
|
||||
@Test public void testSimpleFacetsTwice() throws Exception {
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.elasticsearch.search.controller.SearchPhaseController;
|
|||
import org.elasticsearch.search.controller.ShardDoc;
|
||||
import org.elasticsearch.search.dfs.AggregatedDfs;
|
||||
import org.elasticsearch.search.dfs.DfsSearchResult;
|
||||
import org.elasticsearch.search.facets.query.QueryFacet;
|
||||
import org.elasticsearch.search.fetch.FetchSearchRequest;
|
||||
import org.elasticsearch.search.fetch.FetchSearchResult;
|
||||
import org.elasticsearch.search.fetch.QueryFetchSearchResult;
|
||||
|
@ -344,8 +345,8 @@ public class TwoInstanceEmbeddedSearchTests extends AbstractNodesTests {
|
|||
InternalSearchResponse searchResponse = searchPhaseController.merge(sortedShardList, queryResults, fetchResults);
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(100l));
|
||||
|
||||
assertThat(searchResponse.facets().countFacet("test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().countFacet("all").count(), equalTo(100l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "all").count(), equalTo(100l));
|
||||
}
|
||||
|
||||
@Test public void testSimpleFacetsTwice() {
|
||||
|
|
|
@ -36,6 +36,7 @@ import org.elasticsearch.search.controller.SearchPhaseController;
|
|||
import org.elasticsearch.search.controller.ShardDoc;
|
||||
import org.elasticsearch.search.dfs.AggregatedDfs;
|
||||
import org.elasticsearch.search.dfs.DfsSearchResult;
|
||||
import org.elasticsearch.search.facets.query.QueryFacet;
|
||||
import org.elasticsearch.search.fetch.FetchSearchRequest;
|
||||
import org.elasticsearch.search.fetch.FetchSearchResult;
|
||||
import org.elasticsearch.search.fetch.QueryFetchSearchResult;
|
||||
|
@ -350,8 +351,8 @@ public class TwoInstanceUnbalancedShardsEmbeddedSearchTests extends AbstractNode
|
|||
InternalSearchResponse searchResponse = searchPhaseController.merge(sortedShardList, queryResults, fetchResults);
|
||||
assertThat(searchResponse.hits().totalHits(), equalTo(100l));
|
||||
|
||||
assertThat(searchResponse.facets().countFacet("test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().countFacet("all").count(), equalTo(100l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "test1").count(), equalTo(1l));
|
||||
assertThat(searchResponse.facets().facet(QueryFacet.class, "all").count(), equalTo(100l));
|
||||
}
|
||||
|
||||
@Test public void testSimpleFacetsTwice() {
|
||||
|
|
|
@ -21,15 +21,15 @@ package org.elasticsearch.test.integration.search.facets;
|
|||
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.search.facets.MultiCountFacet;
|
||||
import org.elasticsearch.search.facets.terms.TermsFacet;
|
||||
import org.elasticsearch.test.integration.AbstractNodesTests;
|
||||
import org.hamcrest.MatcherAssert;
|
||||
import org.testng.annotations.AfterClass;
|
||||
import org.testng.annotations.BeforeClass;
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import static org.elasticsearch.index.query.xcontent.QueryBuilders.*;
|
||||
import static org.elasticsearch.util.xcontent.XContentFactory.*;
|
||||
import static org.hamcrest.MatcherAssert.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
|
||||
/**
|
||||
|
@ -72,24 +72,25 @@ public class SimpleFacetsTests extends AbstractNodesTests {
|
|||
.field("stag", "111")
|
||||
.startArray("tag").value("zzz").value("yyy").endArray()
|
||||
.endObject()).execute().actionGet();
|
||||
|
||||
client.admin().indices().prepareRefresh().execute().actionGet();
|
||||
|
||||
SearchResponse searchResponse = client.prepareSearch()
|
||||
.setQuery(termQuery("stag", "111"))
|
||||
.addTermFacet("facet1", "stag", 10)
|
||||
.addTermFacet("facet2", "tag", 10)
|
||||
.addFacetTerms("facet1", "stag", 10)
|
||||
.addFacetTerms("facet2", "tag", 10)
|
||||
.execute().actionGet();
|
||||
|
||||
MultiCountFacet<String> facet = (MultiCountFacet<String>) searchResponse.facets().facet("facet1");
|
||||
MatcherAssert.assertThat(facet.name(), equalTo("facet1"));
|
||||
MatcherAssert.assertThat(facet.entries().size(), equalTo(1));
|
||||
MatcherAssert.assertThat(facet.entries().get(0).value(), equalTo("111"));
|
||||
MatcherAssert.assertThat(facet.entries().get(0).count(), equalTo(2));
|
||||
TermsFacet facet = searchResponse.facets().facet(TermsFacet.class, "facet1");
|
||||
assertThat(facet.name(), equalTo("facet1"));
|
||||
assertThat(facet.entries().size(), equalTo(1));
|
||||
assertThat(facet.entries().get(0).term(), equalTo("111"));
|
||||
assertThat(facet.entries().get(0).count(), equalTo(2));
|
||||
|
||||
facet = (MultiCountFacet<String>) searchResponse.facets().facet("facet2");
|
||||
MatcherAssert.assertThat(facet.name(), equalTo("facet2"));
|
||||
MatcherAssert.assertThat(facet.entries().size(), equalTo(3));
|
||||
MatcherAssert.assertThat(facet.entries().get(0).value(), equalTo("yyy"));
|
||||
MatcherAssert.assertThat(facet.entries().get(0).count(), equalTo(2));
|
||||
facet = searchResponse.facets().facet(TermsFacet.class, "facet2");
|
||||
assertThat(facet.name(), equalTo("facet2"));
|
||||
assertThat(facet.entries().size(), equalTo(3));
|
||||
assertThat(facet.entries().get(0).term(), equalTo("yyy"));
|
||||
assertThat(facet.entries().get(0).count(), equalTo(2));
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue