Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add facet aggregates that apply to other aggregates - initially multi… #29

Open
wants to merge 1 commit into
base: bw_branch_7_4
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,14 @@ public AggValueSource parseAgg(int flags) throws SyntaxError {
return vs;
}

public List<AggValueSource> parseAggValueSourceList() throws SyntaxError {
List<AggValueSource> sources = new ArrayList<>(3);
while (hasMoreArguments()) {
sources.add(parseAgg(FLAG_DEFAULT | FLAG_CONSUME_DELIMITER));
}
return sources;
}


/**
* Consume an argument delimiter (a comma) from the token stream.
Expand Down
16 changes: 16 additions & 0 deletions solr/core/src/java/org/apache/solr/search/ValueSourceParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,10 @@
import org.apache.solr.search.facet.AggValueSource;
import org.apache.solr.search.facet.AvgAgg;
import org.apache.solr.search.facet.CountAgg;
import org.apache.solr.search.facet.DivAgg;
import org.apache.solr.search.facet.HLLAgg;
import org.apache.solr.search.facet.MinMaxAgg;
import org.apache.solr.search.facet.MulAgg;
import org.apache.solr.search.facet.PercentileAgg;
import org.apache.solr.search.facet.StddevAgg;
import org.apache.solr.search.facet.SumAgg;
Expand Down Expand Up @@ -1054,6 +1056,20 @@ public ValueSource parse(FunctionQParser fp) throws SyntaxError {

addParser("agg_topdocs", new TopDocsAgg.Parser());

addParser("agg_mul", new ValueSourceParser() {
@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
return new MulAgg(fp.parseAggValueSourceList());
}
});

addParser("agg_div", new ValueSourceParser() {
@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
return new DivAgg(fp.parseAggValueSourceList());
}
});

addParser("childfield", new ChildFieldValueSourceParser());
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.solr.search.facet;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.IntFunction;
import java.util.stream.Collectors;

import org.apache.lucene.index.LeafReaderContext;
import org.apache.solr.search.DocSet;

public abstract class CombiningAggValueSource extends AggValueSource {

private final List<AggValueSource> subAggs;

public CombiningAggValueSource(String name, List<AggValueSource> subAggs) {
super(name);
this.subAggs = subAggs;
}

@Override
public FacetMerger createFacetMerger(Object prototype) {
List<Object> prototypeResult = (List<Object>)prototype;
if (prototypeResult.size() != subAggs.size()) {
throw new IllegalStateException("Aggregate merge prototype has unexpected size : " + prototypeResult.size());
}
List<FacetMerger> subMergers = new ArrayList<>(subAggs.size());
for (int pos = 0; pos < subAggs.size(); pos++) {
subMergers.add(subAggs.get(pos).createFacetMerger(prototypeResult.get(pos)));
}

return new FacetDoubleMerger() {
@Override
public void merge(Object facetResult, Context mcontext) {
List<Object> shardResult = (List<Object>)facetResult;
if (shardResult.size() != subMergers.size()) {
throw new IllegalStateException("Aggregate merge response has unexpected size : " + shardResult.size());
}
for (int pos = 0; pos < shardResult.size(); pos++) {
subMergers.get(pos).merge(shardResult.get(pos), mcontext);
}
}

@Override
protected double getDouble() {
List<Number> subValues = new ArrayList<>();
for (FacetMerger subMerger : subMergers) {
subValues.add((Number)subMerger.getMergedResult());
}
return combine(subValues);
}
};
}

protected abstract Double combine(List<Number> values);

@Override
public SlotAcc createSlotAcc(FacetContext fcontext, int numDocs, int numSlots) throws IOException {
List<SlotAcc> subAcc = new ArrayList<>(subAggs.size());
for (AggValueSource sub : subAggs) {
subAcc.add(sub.createSlotAcc(fcontext, numDocs, numSlots));
}

return new SlotAcc(fcontext) {

// cache of combined values, since compare operations may ask for these repeatedly
Double[] combinedValues = new Double[numSlots];

@Override
public int compare(int slotA, int slotB) {
try {
Double valueA = getCombinedValue(slotA);
Double valueB = getCombinedValue(slotB);
return Double.compare(valueA, valueB);
} catch (IOException ioe) {
throw new RuntimeException("Exception in aggregate comparison", ioe);
}
}

@Override
public Object getValue(int slotNum) throws IOException {
if (fcontext.isShard()) {
List<Object> lst = new ArrayList<>(subAcc.size());
for (SlotAcc acc : subAcc) {
Object accValue = acc.getValue(slotNum);
lst.add(accValue);
}
return lst;
} else {
return getCombinedValue(slotNum);
}
}

@Override
public Object getSortableValue(int slotNum) throws IOException {
return getCombinedValue(slotNum);
}

private Double getCombinedValue(int slot) throws IOException {
if (combinedValues[slot] == null) {
List<Number> subValues = new ArrayList<>();
for (SlotAcc acc : subAcc) {
subValues.add((Number)acc.getSortableValue(slot));
}
combinedValues[slot] = combine(subValues);
}
return combinedValues[slot];
}

@Override
public void setNextReader(LeafReaderContext readerContext) throws IOException {
super.setNextReader(readerContext);
for (SlotAcc acc : subAcc) {
acc.setNextReader(readerContext);
}
}

@Override
public int collect(DocSet docs, int slot, IntFunction<SlotContext> slotContext) throws IOException {
for (SlotAcc acc : subAcc) {
acc.collect(docs, slot, slotContext);
}
return docs.size();
}

@Override
protected void resetIterators() throws IOException {
for (SlotAcc acc : subAcc) {
acc.resetIterators();
}
}

@Override
public void collect(int doc, int slot, IntFunction<SlotContext> slotContext) throws IOException {
for (SlotAcc acc : subAcc) {
acc.collect(doc, slot, slotContext);
}
}

@Override
public void reset() throws IOException {
Arrays.fill(combinedValues, null);
for (SlotAcc acc : subAcc) {
acc.reset();
}
}

@Override
public void resize(Resizer resizer) {
combinedValues = resizer.resize(combinedValues, null);
for (SlotAcc acc : subAcc) {
acc.resize(resizer);
}
}
};
}

@Override
public int hashCode() {
return Objects.hash(subAggs.toArray());
}

@Override
public String description() {
String subAggsDescription = subAggs.stream()
.map(AggValueSource::description)
.collect(Collectors.joining(","));
return name() + "(" + subAggsDescription + ")";
}
}
40 changes: 40 additions & 0 deletions solr/core/src/java/org/apache/solr/search/facet/DivAgg.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.solr.search.facet;

import java.util.List;

import org.apache.solr.common.SolrException;

public class DivAgg extends CombiningAggValueSource {

public DivAgg(List<AggValueSource> subAggs) {
super("div", subAggs);
if (subAggs.size() != 2) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "div aggregate requires exactly 2 arguments");
}
}

@Override
protected Double combine(List<Number> values) {
if (values.size() != 2) {
throw new IllegalStateException("div aggregate expects 2 values but has " + values.size());
}
return values.get(0).doubleValue() / values.get(1).doubleValue();
}
}
5 changes: 5 additions & 0 deletions solr/core/src/java/org/apache/solr/search/facet/HLLAgg.java
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,11 @@ public Object getValue(int slot) throws IOException {
return getCardinality(slot);
}

@Override
public Object getSortableValue(int slot) {
return getCardinality(slot);
}

private int getCardinality(int slot) {
HLL set = sets[slot];
return set==null ? 0 : (int)set.cardinality();
Expand Down
39 changes: 39 additions & 0 deletions solr/core/src/java/org/apache/solr/search/facet/MulAgg.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.apache.solr.search.facet;

import java.util.List;

import org.apache.solr.common.SolrException;

public class MulAgg extends CombiningAggValueSource {

public MulAgg(List<AggValueSource> subAggs) {
super("mul", subAggs);
if (subAggs.size() < 2) {
throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "mul aggregate requires at least 2 arguments");
}
}

@Override
protected Double combine(List<Number> values) {
return values.stream()
.mapToDouble(Number::doubleValue)
.reduce(1.0D, (x,y) -> x * y);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -147,15 +147,20 @@ private void fillSortVals() {
public Object getValue(int slotNum) throws IOException {
if (fcontext.isShard()) {
return getShardValue(slotNum);
} else {
return getSortableValue(slotNum);
}
}

@Override
public Object getSortableValue(int slotNum) {
if (sortvals != null && percentiles.size()==1) {
// we've already calculated everything we need
return digests[slotNum] != null ? sortvals[slotNum] : null;
}
return getValueFromDigest( digests[slotNum] );
}


public Object getShardValue(int slot) throws IOException {
AVLTreeDigest digest = digests[slot];
if (digest == null) return null; // no values for this slot
Expand Down
Loading