terms facet on an IP field returns terms as numbers, not IPs, closes #678.
This commit is contained in:
parent
0e595532f7
commit
b26d86293f
|
@ -25,6 +25,7 @@ import org.elasticsearch.search.facet.terms.bytes.InternalByteTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.doubles.InternalDoubleTermsFacet;
|
import org.elasticsearch.search.facet.terms.doubles.InternalDoubleTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.floats.InternalFloatTermsFacet;
|
import org.elasticsearch.search.facet.terms.floats.InternalFloatTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.ints.InternalIntTermsFacet;
|
import org.elasticsearch.search.facet.terms.ints.InternalIntTermsFacet;
|
||||||
|
import org.elasticsearch.search.facet.terms.ip.InternalIpTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.longs.InternalLongTermsFacet;
|
import org.elasticsearch.search.facet.terms.longs.InternalLongTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.shorts.InternalShortTermsFacet;
|
import org.elasticsearch.search.facet.terms.shorts.InternalShortTermsFacet;
|
||||||
import org.elasticsearch.search.facet.terms.strings.InternalStringTermsFacet;
|
import org.elasticsearch.search.facet.terms.strings.InternalStringTermsFacet;
|
||||||
|
@ -44,6 +45,7 @@ public abstract class InternalTermsFacet implements TermsFacet, InternalFacet {
|
||||||
InternalFloatTermsFacet.registerStream();
|
InternalFloatTermsFacet.registerStream();
|
||||||
InternalShortTermsFacet.registerStream();
|
InternalShortTermsFacet.registerStream();
|
||||||
InternalByteTermsFacet.registerStream();
|
InternalByteTermsFacet.registerStream();
|
||||||
|
InternalIpTermsFacet.registerStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract Facet reduce(String name, List<Facet> facets);
|
public abstract Facet reduce(String name, List<Facet> facets);
|
||||||
|
|
|
@ -28,6 +28,7 @@ import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.field.data.FieldDataType;
|
import org.elasticsearch.index.field.data.FieldDataType;
|
||||||
import org.elasticsearch.index.mapper.FieldMapper;
|
import org.elasticsearch.index.mapper.FieldMapper;
|
||||||
|
import org.elasticsearch.index.mapper.xcontent.ip.IpFieldMapper;
|
||||||
import org.elasticsearch.search.facet.Facet;
|
import org.elasticsearch.search.facet.Facet;
|
||||||
import org.elasticsearch.search.facet.FacetCollector;
|
import org.elasticsearch.search.facet.FacetCollector;
|
||||||
import org.elasticsearch.search.facet.FacetProcessor;
|
import org.elasticsearch.search.facet.FacetProcessor;
|
||||||
|
@ -36,6 +37,7 @@ import org.elasticsearch.search.facet.terms.doubles.TermsDoubleFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.floats.TermsFloatFacetCollector;
|
import org.elasticsearch.search.facet.terms.floats.TermsFloatFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.index.IndexNameFacetCollector;
|
import org.elasticsearch.search.facet.terms.index.IndexNameFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.ints.TermsIntFacetCollector;
|
import org.elasticsearch.search.facet.terms.ints.TermsIntFacetCollector;
|
||||||
|
import org.elasticsearch.search.facet.terms.ip.TermsIpFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.longs.TermsLongFacetCollector;
|
import org.elasticsearch.search.facet.terms.longs.TermsLongFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.shorts.TermsShortFacetCollector;
|
import org.elasticsearch.search.facet.terms.shorts.TermsShortFacetCollector;
|
||||||
import org.elasticsearch.search.facet.terms.strings.FieldsTermsStringFacetCollector;
|
import org.elasticsearch.search.facet.terms.strings.FieldsTermsStringFacetCollector;
|
||||||
|
@ -139,7 +141,9 @@ public class TermsFacetProcessor extends AbstractComponent implements FacetProce
|
||||||
|
|
||||||
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(field);
|
FieldMapper fieldMapper = context.mapperService().smartNameFieldMapper(field);
|
||||||
if (fieldMapper != null) {
|
if (fieldMapper != null) {
|
||||||
if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.LONG) {
|
if (fieldMapper instanceof IpFieldMapper) {
|
||||||
|
return new TermsIpFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params);
|
||||||
|
} else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.LONG) {
|
||||||
return new TermsLongFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params);
|
return new TermsLongFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params);
|
||||||
} else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.DOUBLE) {
|
} else if (fieldMapper.fieldDataType() == FieldDataType.DefaultTypes.DOUBLE) {
|
||||||
return new TermsDoubleFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params);
|
return new TermsDoubleFacetCollector(facetName, field, size, comparatorType, allTerms, context, scriptLang, script, params);
|
||||||
|
|
|
@ -0,0 +1,262 @@
|
||||||
|
/*
|
||||||
|
* 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.terms.ip;
|
||||||
|
|
||||||
|
import org.elasticsearch.common.collect.BoundedTreeSet;
|
||||||
|
import org.elasticsearch.common.collect.ImmutableList;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.common.thread.ThreadLocals;
|
||||||
|
import org.elasticsearch.common.trove.iterator.TLongIntIterator;
|
||||||
|
import org.elasticsearch.common.trove.map.hash.TLongIntHashMap;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilder;
|
||||||
|
import org.elasticsearch.common.xcontent.XContentBuilderString;
|
||||||
|
import org.elasticsearch.index.mapper.xcontent.ip.IpFieldMapper;
|
||||||
|
import org.elasticsearch.search.facet.Facet;
|
||||||
|
import org.elasticsearch.search.facet.terms.InternalTermsFacet;
|
||||||
|
import org.elasticsearch.search.facet.terms.TermsFacet;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public class InternalIpTermsFacet extends InternalTermsFacet {
|
||||||
|
|
||||||
|
private static final String STREAM_TYPE = "ipTerms";
|
||||||
|
|
||||||
|
public static void registerStream() {
|
||||||
|
Streams.registerStream(STREAM, STREAM_TYPE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static Stream STREAM = new Stream() {
|
||||||
|
@Override public Facet readFacet(String type, StreamInput in) throws IOException {
|
||||||
|
return readTermsFacet(in);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
@Override public String streamType() {
|
||||||
|
return STREAM_TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LongEntry implements Entry {
|
||||||
|
|
||||||
|
long term;
|
||||||
|
int count;
|
||||||
|
|
||||||
|
public LongEntry(long term, int count) {
|
||||||
|
this.term = term;
|
||||||
|
this.count = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String term() {
|
||||||
|
return IpFieldMapper.longToIp(term);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTerm() {
|
||||||
|
return term();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Number termAsNumber() {
|
||||||
|
return term;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Number getTermAsNumber() {
|
||||||
|
return termAsNumber();
|
||||||
|
}
|
||||||
|
|
||||||
|
public int count() {
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int getCount() {
|
||||||
|
return count();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public int compareTo(Entry o) {
|
||||||
|
long anotherVal = ((LongEntry) o).term;
|
||||||
|
if (term < anotherVal) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (term == anotherVal) {
|
||||||
|
int i = count - o.count();
|
||||||
|
if (i == 0) {
|
||||||
|
i = System.identityHashCode(this) - System.identityHashCode(o);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
int requiredSize;
|
||||||
|
|
||||||
|
long missing;
|
||||||
|
|
||||||
|
Collection<LongEntry> entries = ImmutableList.of();
|
||||||
|
|
||||||
|
ComparatorType comparatorType;
|
||||||
|
|
||||||
|
InternalIpTermsFacet() {
|
||||||
|
}
|
||||||
|
|
||||||
|
public InternalIpTermsFacet(String name, ComparatorType comparatorType, int requiredSize, Collection<LongEntry> entries, long missing) {
|
||||||
|
this.name = name;
|
||||||
|
this.comparatorType = comparatorType;
|
||||||
|
this.requiredSize = requiredSize;
|
||||||
|
this.entries = entries;
|
||||||
|
this.missing = missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String name() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String type() {
|
||||||
|
return TYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public String getType() {
|
||||||
|
return type();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public List<LongEntry> entries() {
|
||||||
|
if (!(entries instanceof List)) {
|
||||||
|
entries = ImmutableList.copyOf(entries);
|
||||||
|
}
|
||||||
|
return (List<LongEntry>) entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public List<LongEntry> getEntries() {
|
||||||
|
return entries();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings({"unchecked"}) @Override public Iterator<Entry> iterator() {
|
||||||
|
return (Iterator) entries.iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public long missingCount() {
|
||||||
|
return this.missing;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public long getMissingCount() {
|
||||||
|
return missingCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ThreadLocal<ThreadLocals.CleanableValue<TLongIntHashMap>> aggregateCache = new ThreadLocal<ThreadLocals.CleanableValue<TLongIntHashMap>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<TLongIntHashMap> initialValue() {
|
||||||
|
return new ThreadLocals.CleanableValue<TLongIntHashMap>(new TLongIntHashMap());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@Override public Facet reduce(String name, List<Facet> facets) {
|
||||||
|
if (facets.size() == 1) {
|
||||||
|
return facets.get(0);
|
||||||
|
}
|
||||||
|
InternalIpTermsFacet first = (InternalIpTermsFacet) facets.get(0);
|
||||||
|
TLongIntHashMap aggregated = aggregateCache.get().get();
|
||||||
|
aggregated.clear();
|
||||||
|
long missing = 0;
|
||||||
|
|
||||||
|
for (Facet facet : facets) {
|
||||||
|
InternalIpTermsFacet mFacet = (InternalIpTermsFacet) facet;
|
||||||
|
missing += mFacet.missingCount();
|
||||||
|
for (LongEntry entry : mFacet.entries) {
|
||||||
|
aggregated.adjustOrPutValue(entry.term, entry.count(), entry.count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BoundedTreeSet<LongEntry> ordered = new BoundedTreeSet<LongEntry>(first.comparatorType.comparator(), first.requiredSize);
|
||||||
|
for (TLongIntIterator it = aggregated.iterator(); it.hasNext();) {
|
||||||
|
it.advance();
|
||||||
|
ordered.add(new LongEntry(it.key(), it.value()));
|
||||||
|
}
|
||||||
|
first.entries = ordered;
|
||||||
|
first.missing = missing;
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static final class Fields {
|
||||||
|
static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
|
||||||
|
static final XContentBuilderString MISSING = new XContentBuilderString("missing");
|
||||||
|
static final XContentBuilderString TERMS = new XContentBuilderString("terms");
|
||||||
|
static final XContentBuilderString TERM = new XContentBuilderString("term");
|
||||||
|
static final XContentBuilderString COUNT = new XContentBuilderString("count");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
|
||||||
|
builder.startObject(name);
|
||||||
|
builder.field(Fields._TYPE, TermsFacet.TYPE);
|
||||||
|
builder.field(Fields.MISSING, missing);
|
||||||
|
builder.startArray(Fields.TERMS);
|
||||||
|
for (LongEntry entry : entries) {
|
||||||
|
builder.startObject();
|
||||||
|
builder.field(Fields.TERM, entry.term()); // displayed as string
|
||||||
|
builder.field(Fields.COUNT, entry.count());
|
||||||
|
builder.endObject();
|
||||||
|
}
|
||||||
|
builder.endArray();
|
||||||
|
builder.endObject();
|
||||||
|
return builder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static InternalIpTermsFacet readTermsFacet(StreamInput in) throws IOException {
|
||||||
|
InternalIpTermsFacet facet = new InternalIpTermsFacet();
|
||||||
|
facet.readFrom(in);
|
||||||
|
return facet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void readFrom(StreamInput in) throws IOException {
|
||||||
|
name = in.readUTF();
|
||||||
|
comparatorType = ComparatorType.fromId(in.readByte());
|
||||||
|
requiredSize = in.readVInt();
|
||||||
|
missing = in.readVLong();
|
||||||
|
|
||||||
|
int size = in.readVInt();
|
||||||
|
entries = new ArrayList<LongEntry>(size);
|
||||||
|
for (int i = 0; i < size; i++) {
|
||||||
|
entries.add(new LongEntry(in.readLong(), in.readVInt()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void writeTo(StreamOutput out) throws IOException {
|
||||||
|
out.writeUTF(name);
|
||||||
|
out.writeByte(comparatorType.id());
|
||||||
|
out.writeVInt(requiredSize);
|
||||||
|
out.writeVLong(missing);
|
||||||
|
|
||||||
|
out.writeVInt(entries.size());
|
||||||
|
for (LongEntry entry : entries) {
|
||||||
|
out.writeLong(entry.term);
|
||||||
|
out.writeVInt(entry.count());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,236 @@
|
||||||
|
/*
|
||||||
|
* 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.terms.ip;
|
||||||
|
|
||||||
|
import org.apache.lucene.index.IndexReader;
|
||||||
|
import org.apache.lucene.search.Scorer;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
|
import org.elasticsearch.common.collect.BoundedTreeSet;
|
||||||
|
import org.elasticsearch.common.collect.ImmutableList;
|
||||||
|
import org.elasticsearch.common.thread.ThreadLocals;
|
||||||
|
import org.elasticsearch.common.trove.iterator.TLongIntIterator;
|
||||||
|
import org.elasticsearch.common.trove.map.hash.TLongIntHashMap;
|
||||||
|
import org.elasticsearch.index.cache.field.data.FieldDataCache;
|
||||||
|
import org.elasticsearch.index.field.data.FieldDataType;
|
||||||
|
import org.elasticsearch.index.field.data.longs.LongFieldData;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
|
import org.elasticsearch.script.SearchScript;
|
||||||
|
import org.elasticsearch.search.facet.AbstractFacetCollector;
|
||||||
|
import org.elasticsearch.search.facet.Facet;
|
||||||
|
import org.elasticsearch.search.facet.FacetPhaseExecutionException;
|
||||||
|
import org.elasticsearch.search.facet.terms.TermsFacet;
|
||||||
|
import org.elasticsearch.search.internal.SearchContext;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayDeque;
|
||||||
|
import java.util.Deque;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author kimchy (shay.banon)
|
||||||
|
*/
|
||||||
|
public class TermsIpFacetCollector extends AbstractFacetCollector {
|
||||||
|
|
||||||
|
static ThreadLocal<ThreadLocals.CleanableValue<Deque<TLongIntHashMap>>> cache = new ThreadLocal<ThreadLocals.CleanableValue<Deque<TLongIntHashMap>>>() {
|
||||||
|
@Override protected ThreadLocals.CleanableValue<Deque<TLongIntHashMap>> initialValue() {
|
||||||
|
return new ThreadLocals.CleanableValue<Deque<TLongIntHashMap>>(new ArrayDeque<TLongIntHashMap>());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
private final FieldDataCache fieldDataCache;
|
||||||
|
|
||||||
|
private final String indexFieldName;
|
||||||
|
|
||||||
|
private final TermsFacet.ComparatorType comparatorType;
|
||||||
|
|
||||||
|
private final int size;
|
||||||
|
|
||||||
|
private final int numberOfShards;
|
||||||
|
|
||||||
|
private final FieldDataType fieldDataType;
|
||||||
|
|
||||||
|
private LongFieldData fieldData;
|
||||||
|
|
||||||
|
private final StaticAggregatorValueProc aggregator;
|
||||||
|
|
||||||
|
private final SearchScript script;
|
||||||
|
|
||||||
|
public TermsIpFacetCollector(String facetName, String fieldName, int size, TermsFacet.ComparatorType comparatorType, boolean allTerms, SearchContext context,
|
||||||
|
String scriptLang, String script, Map<String, Object> params) {
|
||||||
|
super(facetName);
|
||||||
|
this.fieldDataCache = context.fieldDataCache();
|
||||||
|
this.size = size;
|
||||||
|
this.comparatorType = comparatorType;
|
||||||
|
this.numberOfShards = context.numberOfShards();
|
||||||
|
|
||||||
|
MapperService.SmartNameFieldMappers smartMappers = context.mapperService().smartName(fieldName);
|
||||||
|
if (smartMappers == null || !smartMappers.hasMapper()) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("Field [" + fieldName + "] doesn't have a type, can't run terms long facet collector on it");
|
||||||
|
} else {
|
||||||
|
// add type filter if there is exact doc mapper associated with it
|
||||||
|
if (smartMappers.hasDocMapper()) {
|
||||||
|
setFilter(context.filterCache().cache(smartMappers.docMapper().typeFilter()));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smartMappers.mapper().fieldDataType() != FieldDataType.DefaultTypes.LONG) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("Field [" + fieldName + "] is not of long type, can't run terms long facet collector on it");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.indexFieldName = smartMappers.mapper().names().indexName();
|
||||||
|
this.fieldDataType = smartMappers.mapper().fieldDataType();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (script != null) {
|
||||||
|
this.script = context.scriptService().search(context.lookup(), scriptLang, script, params);
|
||||||
|
} else {
|
||||||
|
this.script = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.script == null) {
|
||||||
|
aggregator = new StaticAggregatorValueProc(popFacets());
|
||||||
|
} else {
|
||||||
|
aggregator = new AggregatorValueProc(popFacets(), this.script);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allTerms) {
|
||||||
|
try {
|
||||||
|
for (IndexReader reader : context.searcher().subReaders()) {
|
||||||
|
LongFieldData fieldData = (LongFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName);
|
||||||
|
fieldData.forEachValue(aggregator);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new FacetPhaseExecutionException(facetName, "failed to load all terms", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void setScorer(Scorer scorer) throws IOException {
|
||||||
|
if (script != null) {
|
||||||
|
script.setScorer(scorer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void doSetNextReader(IndexReader reader, int docBase) throws IOException {
|
||||||
|
fieldData = (LongFieldData) fieldDataCache.cache(fieldDataType, reader, indexFieldName);
|
||||||
|
if (script != null) {
|
||||||
|
script.setNextReader(reader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override protected void doCollect(int doc) throws IOException {
|
||||||
|
fieldData.forEachValueInDoc(doc, aggregator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public Facet facet() {
|
||||||
|
TLongIntHashMap facets = aggregator.facets();
|
||||||
|
if (facets.isEmpty()) {
|
||||||
|
pushFacets(facets);
|
||||||
|
return new InternalIpTermsFacet(facetName, comparatorType, size, ImmutableList.<InternalIpTermsFacet.LongEntry>of(), aggregator.missing());
|
||||||
|
} else {
|
||||||
|
// we need to fetch facets of "size * numberOfShards" because of problems in how they are distributed across shards
|
||||||
|
BoundedTreeSet<InternalIpTermsFacet.LongEntry> ordered = new BoundedTreeSet<InternalIpTermsFacet.LongEntry>(comparatorType.comparator(), size * numberOfShards);
|
||||||
|
for (TLongIntIterator it = facets.iterator(); it.hasNext();) {
|
||||||
|
it.advance();
|
||||||
|
ordered.add(new InternalIpTermsFacet.LongEntry(it.key(), it.value()));
|
||||||
|
}
|
||||||
|
pushFacets(facets);
|
||||||
|
return new InternalIpTermsFacet(facetName, comparatorType, size, ordered, aggregator.missing());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static TLongIntHashMap popFacets() {
|
||||||
|
Deque<TLongIntHashMap> deque = cache.get().get();
|
||||||
|
if (deque.isEmpty()) {
|
||||||
|
deque.add(new TLongIntHashMap());
|
||||||
|
}
|
||||||
|
TLongIntHashMap facets = deque.pollFirst();
|
||||||
|
facets.clear();
|
||||||
|
return facets;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void pushFacets(TLongIntHashMap facets) {
|
||||||
|
facets.clear();
|
||||||
|
Deque<TLongIntHashMap> deque = cache.get().get();
|
||||||
|
if (deque != null) {
|
||||||
|
deque.add(facets);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class AggregatorValueProc extends StaticAggregatorValueProc {
|
||||||
|
|
||||||
|
private final SearchScript script;
|
||||||
|
|
||||||
|
public AggregatorValueProc(TLongIntHashMap facets, SearchScript script) {
|
||||||
|
super(facets);
|
||||||
|
this.script = script;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onValue(int docId, long value) {
|
||||||
|
if (script != null) {
|
||||||
|
script.setNextDocId(docId);
|
||||||
|
script.setNextVar("term", value);
|
||||||
|
Object scriptValue = script.run();
|
||||||
|
if (scriptValue == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (scriptValue instanceof Boolean) {
|
||||||
|
if (!((Boolean) scriptValue)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
value = ((Number) scriptValue).longValue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.onValue(docId, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class StaticAggregatorValueProc implements LongFieldData.ValueInDocProc, LongFieldData.ValueProc {
|
||||||
|
|
||||||
|
private final TLongIntHashMap facets;
|
||||||
|
|
||||||
|
private int missing;
|
||||||
|
|
||||||
|
public StaticAggregatorValueProc(TLongIntHashMap facets) {
|
||||||
|
this.facets = facets;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onValue(long value) {
|
||||||
|
facets.putIfAbsent(value, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onValue(int docId, long value) {
|
||||||
|
facets.adjustOrPutValue(value, 1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void onMissing(int docId) {
|
||||||
|
missing++;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final TLongIntHashMap facets() {
|
||||||
|
return facets;
|
||||||
|
}
|
||||||
|
|
||||||
|
public final int missing() {
|
||||||
|
return this.missing;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue