Permalink
Browse files

Date Histogram Facet: Improve value field case performance, fix wrong…

… total computation with multi valued fields by introducing total_count, add min/max stats, closes #831.
  • Loading branch information...
1 parent 8d1e9db commit 90a339ad5e4a61e750d0342be6326de46f45bedc @kimchy kimchy committed Apr 4, 2011
@@ -51,18 +51,39 @@
TIME((byte) 0, "time", new Comparator<Entry>() {
@Override public int compare(Entry o1, Entry o2) {
+ // push nulls to the end
+ if (o1 == null) {
+ return 1;
+ }
+ if (o2 == null) {
+ return -1;
+ }
return (o1.time() < o2.time() ? -1 : (o1.time() == o2.time() ? 0 : 1));
}
}),
COUNT((byte) 1, "count", new Comparator<Entry>() {
@Override public int compare(Entry o1, Entry o2) {
+ // push nulls to the end
+ if (o1 == null) {
+ return 1;
+ }
+ if (o2 == null) {
+ return -1;
+ }
return (o1.count() < o2.count() ? -1 : (o1.count() == o2.count() ? 0 : 1));
}
}),
TOTAL((byte) 2, "total", new Comparator<Entry>() {
@Override public int compare(Entry o1, Entry o2) {
+ // push nulls to the end
+ if (o1 == null) {
+ return 1;
+ }
+ if (o2 == null) {
+ return -1;
+ }
return (o1.total() < o2.total() ? -1 : (o1.total() == o2.total() ? 0 : 1));
}
});
@@ -137,6 +158,16 @@ public static ComparatorType fromString(String type) {
long getCount();
/**
+ * The total count of values aggregated to compute the total.
+ */
+ long totalCount();
+
+ /**
+ * The total count of values aggregated to compute the total.
+ */
+ long getTotalCount();
+
+ /**
* The sum / total of the value field that fall within this key "interval".
*/
double total();
@@ -155,5 +186,25 @@ public static ComparatorType fromString(String type) {
* The mean of this facet interval.
*/
double getMean();
+
+ /**
+ * The minimum value.
+ */
+ double min();
+
+ /**
+ * The minimum value.
+ */
+ double getMin();
+
+ /**
+ * The maximum value.
+ */
+ double max();
+
+ /**
+ * The maximum value.
+ */
+ double getMax();
}
}
@@ -1,279 +0,0 @@
-/*
- * 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.datehistogram;
-
-import org.elasticsearch.common.io.stream.StreamInput;
-import org.elasticsearch.common.io.stream.StreamOutput;
-import org.elasticsearch.common.trove.iterator.TLongDoubleIterator;
-import org.elasticsearch.common.trove.iterator.TLongLongIterator;
-import org.elasticsearch.common.trove.map.hash.TLongDoubleHashMap;
-import org.elasticsearch.common.trove.map.hash.TLongLongHashMap;
-import org.elasticsearch.common.xcontent.XContentBuilder;
-import org.elasticsearch.common.xcontent.XContentBuilderString;
-import org.elasticsearch.search.facet.Facet;
-import org.elasticsearch.search.facet.histogram.HistogramFacet;
-
-import java.io.IOException;
-import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * @author kimchy (shay.banon)
- */
-public class InternalCountAndTotalDateHistogramFacet extends InternalDateHistogramFacet {
-
- private static final String STREAM_TYPE = "ctdHistogram";
-
- public static void registerStreams() {
- Streams.registerStream(STREAM, STREAM_TYPE);
- }
-
- static Stream STREAM = new Stream() {
- @Override public Facet readFacet(String type, StreamInput in) throws IOException {
- return readHistogramFacet(in);
- }
- };
-
- @Override public String streamType() {
- return STREAM_TYPE;
- }
-
-
- /**
- * A histogram entry representing a single entry within the result of a histogram facet.
- */
- public class CountAndTotalEntry implements Entry {
- private final long time;
- private final long count;
- private final double total;
-
- public CountAndTotalEntry(long time, long count, double total) {
- this.time = time;
- this.count = count;
- this.total = total;
- }
-
- public long time() {
- return time;
- }
-
- public long getTime() {
- return time();
- }
-
- public long count() {
- return count;
- }
-
- public long getCount() {
- return count();
- }
-
- public double total() {
- return total;
- }
-
- public double getTotal() {
- return total();
- }
-
- public double mean() {
- return total / count;
- }
-
- public double getMean() {
- return mean();
- }
- }
-
- private String name;
-
- private ComparatorType comparatorType;
-
- TLongLongHashMap counts;
-
- TLongDoubleHashMap totals;
-
- CountAndTotalEntry[] entries = null;
-
- private InternalCountAndTotalDateHistogramFacet() {
- }
-
- public InternalCountAndTotalDateHistogramFacet(String name, ComparatorType comparatorType, TLongLongHashMap counts, TLongDoubleHashMap totals) {
- this.name = name;
- this.comparatorType = comparatorType;
- this.counts = counts;
- this.totals = totals;
- }
-
- @Override public String name() {
- return this.name;
- }
-
- @Override public String getName() {
- return name();
- }
-
- @Override public String type() {
- return TYPE;
- }
-
- @Override public String getType() {
- return type();
- }
-
- @Override public List<CountAndTotalEntry> entries() {
- return Arrays.asList(computeEntries());
- }
-
- @Override public List<CountAndTotalEntry> getEntries() {
- return entries();
- }
-
- @Override public Iterator<Entry> iterator() {
- return (Iterator) entries().iterator();
- }
-
- private CountAndTotalEntry[] computeEntries() {
- if (entries != null) {
- return entries;
- }
- entries = new CountAndTotalEntry[counts.size()];
- int i = 0;
- for (TLongLongIterator it = counts.iterator(); it.hasNext();) {
- it.advance();
- entries[i++] = new CountAndTotalEntry(it.key(), it.value(), totals.get(it.key()));
- }
- Arrays.sort(entries, comparatorType.comparator());
- return entries;
- }
-
- @Override public Facet reduce(String name, List<Facet> facets) {
- if (facets.size() == 1) {
- return facets.get(0);
- }
- TLongLongHashMap counts = null;
- TLongDoubleHashMap totals = null;
-
- InternalCountAndTotalDateHistogramFacet firstHistoFacet = (InternalCountAndTotalDateHistogramFacet) facets.get(0);
- for (Facet facet : facets) {
- InternalCountAndTotalDateHistogramFacet histoFacet = (InternalCountAndTotalDateHistogramFacet) facet;
- if (!histoFacet.counts.isEmpty()) {
- if (counts == null) {
- counts = histoFacet.counts;
- } else {
- for (TLongLongIterator it = histoFacet.counts.iterator(); it.hasNext();) {
- it.advance();
- counts.adjustOrPutValue(it.key(), it.value(), it.value());
- }
- }
- }
-
- if (!histoFacet.totals.isEmpty()) {
- if (totals == null) {
- totals = histoFacet.totals;
- } else {
- for (TLongDoubleIterator it = histoFacet.totals.iterator(); it.hasNext();) {
- it.advance();
- totals.adjustOrPutValue(it.key(), it.value(), it.value());
- }
- }
- }
- }
- if (counts == null) {
- counts = InternalCountAndTotalDateHistogramFacet.EMPTY_LONG_LONG_MAP;
- }
- if (totals == null) {
- totals = InternalCountAndTotalDateHistogramFacet.EMPTY_LONG_DOUBLE_MAP;
- }
- firstHistoFacet.counts = counts;
- firstHistoFacet.totals = totals;
-
- return firstHistoFacet;
- }
-
- static final class Fields {
- static final XContentBuilderString _TYPE = new XContentBuilderString("_type");
- static final XContentBuilderString ENTRIES = new XContentBuilderString("entries");
- static final XContentBuilderString TIME = new XContentBuilderString("time");
- static final XContentBuilderString COUNT = new XContentBuilderString("count");
- static final XContentBuilderString TOTAL = new XContentBuilderString("total");
- static final XContentBuilderString MEAN = new XContentBuilderString("mean");
- }
-
- @Override public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
- builder.startObject(name);
- builder.field(Fields._TYPE, HistogramFacet.TYPE);
- builder.startArray(Fields.ENTRIES);
- for (Entry entry : computeEntries()) {
- builder.startObject();
- builder.field(Fields.TIME, entry.time());
- builder.field(Fields.COUNT, entry.count());
- builder.field(Fields.TOTAL, entry.total());
- builder.field(Fields.MEAN, entry.mean());
- builder.endObject();
- }
- builder.endArray();
- builder.endObject();
- return builder;
- }
-
- public static InternalCountAndTotalDateHistogramFacet readHistogramFacet(StreamInput in) throws IOException {
- InternalCountAndTotalDateHistogramFacet facet = new InternalCountAndTotalDateHistogramFacet();
- facet.readFrom(in);
- return facet;
- }
-
- @Override public void readFrom(StreamInput in) throws IOException {
- name = in.readUTF();
- comparatorType = ComparatorType.fromId(in.readByte());
-
- int size = in.readVInt();
- if (size == 0) {
- counts = EMPTY_LONG_LONG_MAP;
- totals = EMPTY_LONG_DOUBLE_MAP;
- } else {
- counts = new TLongLongHashMap(size);
- totals = new TLongDoubleHashMap(size);
- for (int i = 0; i < size; i++) {
- long key = in.readLong();
- counts.put(key, in.readVLong());
- totals.put(key, in.readDouble());
- }
- }
- }
-
- @Override public void writeTo(StreamOutput out) throws IOException {
- out.writeUTF(name);
- out.writeByte(comparatorType.id());
- // optimize the write, since we know we have the same buckets as keys
- out.writeVInt(counts.size());
- for (TLongLongIterator it = counts.iterator(); it.hasNext();) {
- it.advance();
- out.writeLong(it.key());
- out.writeVLong(it.value());
- out.writeDouble(totals.get(it.key()));
- }
- }
-
- static final TLongLongHashMap EMPTY_LONG_LONG_MAP = new TLongLongHashMap();
- static final TLongDoubleHashMap EMPTY_LONG_DOUBLE_MAP = new TLongDoubleHashMap();
-}
Oops, something went wrong.

0 comments on commit 90a339a

Please sign in to comment.