-
Notifications
You must be signed in to change notification settings - Fork 20
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #93 from Paul-Blanchaert/querqy_decorations_with_aggs
Querqy decorations with aggs
- Loading branch information
Showing
12 changed files
with
926 additions
and
24 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
83 changes: 83 additions & 0 deletions
83
src/main/java/querqy/elasticsearch/aggregation/DecoratedQuery.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
package querqy.elasticsearch.aggregation; | ||
|
||
import org.apache.lucene.index.IndexReader; | ||
import org.apache.lucene.search.IndexSearcher; | ||
import org.apache.lucene.search.Query; | ||
import org.apache.lucene.search.ScoreMode; | ||
import org.apache.lucene.search.Weight; | ||
|
||
import java.io.IOException; | ||
import java.util.Objects; | ||
import java.util.Set; | ||
|
||
public class DecoratedQuery<T extends Query> extends Query { | ||
|
||
final private T query; | ||
final private Set<Object> decorations; | ||
|
||
public DecoratedQuery(final T query, final Set<Object> decorations) { | ||
this.query = Objects.requireNonNull(query); | ||
this.decorations = Objects.requireNonNull(decorations); | ||
} | ||
|
||
public T getQuery() { | ||
return query; | ||
} | ||
|
||
public Set<Object> getDecorations() { | ||
return decorations; | ||
} | ||
|
||
@Override | ||
public Weight createWeight(final IndexSearcher searcher, final ScoreMode scoreMode, final float boost) throws IOException { | ||
return query.createWeight(searcher, scoreMode, boost); | ||
} | ||
|
||
@Override | ||
public Query rewrite(final IndexReader reader) throws IOException { | ||
return query.rewrite(reader); | ||
} | ||
|
||
@Override | ||
public String toString(final String field) { | ||
return query.toString(field); | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object object) { | ||
if (!sameClassAs(object)) return false; | ||
final DecoratedQuery<?> other = castObject(object); | ||
return isEqualQueriesAndDecorations(other); | ||
} | ||
|
||
private boolean isEqualQueriesAndDecorations(final DecoratedQuery<?> other) { | ||
final Query otherQuery = other.getQuery(); | ||
final Set<Object> otherDecorations = other.getDecorations(); | ||
return getQuery().equals(otherQuery) && getDecorations().equals(otherDecorations); | ||
} | ||
|
||
private DecoratedQuery<?> castObject(final Object object) { | ||
return getClass().cast(object); | ||
} | ||
|
||
private int computeHashCode() { | ||
int hashCode = Objects.hash(query, decorations); | ||
if (hashCode == 0) { | ||
hashCode = 1; | ||
} | ||
return hashCode; | ||
} | ||
|
||
// cached hash code is ok since boolean queries are immutable | ||
private int hashCode; | ||
|
||
@Override | ||
public int hashCode() { | ||
// no need for synchronization, in the worst case we would just compute the hash several times. | ||
if (hashCode == 0) { | ||
hashCode = computeHashCode(); | ||
} | ||
return hashCode; | ||
} | ||
|
||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/querqy/elasticsearch/aggregation/DecorationAggregation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package querqy.elasticsearch.aggregation; | ||
|
||
import org.elasticsearch.search.aggregations.Aggregation; | ||
|
||
/** | ||
* A {@code DecorationAggregation} aggregation. Defines a single bucket the holds all the querqy info in the search context. | ||
*/ | ||
public interface DecorationAggregation extends Aggregation { | ||
|
||
/** | ||
* The result of the aggregation. The type of the object depends on the aggregation that was run. | ||
*/ | ||
Object aggregation(); | ||
|
||
} |
110 changes: 110 additions & 0 deletions
110
src/main/java/querqy/elasticsearch/aggregation/InternalDecorationAggregation.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,110 @@ | ||
package querqy.elasticsearch.aggregation; | ||
|
||
import org.elasticsearch.Version; | ||
import org.elasticsearch.common.io.stream.StreamInput; | ||
import org.elasticsearch.common.io.stream.StreamOutput; | ||
import org.elasticsearch.search.aggregations.InternalAggregation; | ||
import org.elasticsearch.search.aggregations.metrics.ScriptedMetric; | ||
import org.elasticsearch.xcontent.XContentBuilder; | ||
|
||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
import static java.util.Collections.singletonList; | ||
|
||
public class InternalDecorationAggregation extends InternalAggregation implements ScriptedMetric { | ||
|
||
private final List<Object> aggregations; | ||
|
||
InternalDecorationAggregation(final String name, final List<Object> aggregations, final Map<String, Object> metadata) { | ||
super(name, metadata); | ||
this.aggregations = aggregations; | ||
} | ||
|
||
public InternalDecorationAggregation(final StreamInput in) throws IOException { | ||
super(in); | ||
aggregations = in.readList(StreamInput::readGenericValue); | ||
} | ||
|
||
@Override | ||
protected void doWriteTo(final StreamOutput out) throws IOException { | ||
out.writeCollection(aggregations, StreamOutput::writeGenericValue); | ||
} | ||
|
||
@Override | ||
public String getWriteableName() { | ||
return QuerqyDecorationAggregationBuilder.NAME; | ||
} | ||
|
||
@Override | ||
public Object aggregation() { | ||
if (aggregations.size() != 1) { | ||
throw new IllegalStateException("aggregation was not reduced"); | ||
} | ||
return aggregations.get(0); | ||
} | ||
|
||
List<Object> aggregationsList() { | ||
return aggregations; | ||
} | ||
|
||
@Override | ||
public InternalAggregation reduce(final List<InternalAggregation> aggregations, final ReduceContext reduceContext) { | ||
final List<Object> aggregationObjects = new ArrayList<>(); | ||
for (final InternalAggregation aggregation : aggregations) { | ||
final InternalDecorationAggregation mapReduceAggregation = (InternalDecorationAggregation) aggregation; | ||
aggregationObjects.addAll(mapReduceAggregation.aggregations); | ||
} | ||
final InternalDecorationAggregation firstAggregation = ((InternalDecorationAggregation) aggregations.get(0)); | ||
final List<Object> aggregation; | ||
if (reduceContext.isFinalReduce()) { | ||
aggregation = Collections.singletonList(aggregationObjects); | ||
} else { | ||
// if we are not an final reduce we have to maintain all the aggs from all the incoming one | ||
// until we hit the final reduce phase. | ||
aggregation = aggregationObjects; | ||
} | ||
return new InternalDecorationAggregation(firstAggregation.getName(), aggregation, getMetadata()); | ||
} | ||
|
||
@Override | ||
protected boolean mustReduceOnSingleInternalAgg() { | ||
return true; | ||
} | ||
|
||
@Override | ||
public Object getProperty(final List<String> path) { | ||
if (path.isEmpty()) { | ||
return this; | ||
} else if (path.size() == 1 && "value".equals(path.get(0))) { | ||
return aggregation(); | ||
} else { | ||
throw new IllegalArgumentException("path not supported for [" + getName() + "]: " + path); | ||
} | ||
} | ||
|
||
@Override | ||
public XContentBuilder doXContentBody(final XContentBuilder builder, final Params params) throws IOException { | ||
return builder.field(CommonFields.VALUE.getPreferredName(), aggregation()); | ||
} | ||
|
||
@Override | ||
public boolean equals(final Object obj) { | ||
if (this == obj) return true; | ||
if (obj == null || getClass() != obj.getClass()) return false; | ||
if (!super.equals(obj)) return false; | ||
|
||
final InternalDecorationAggregation other = (InternalDecorationAggregation) obj; | ||
return Objects.equals(aggregations, other.aggregations); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(super.hashCode(), aggregations); | ||
} | ||
|
||
} |
Oops, something went wrong.