Skip to content

Commit

Permalink
Added scoring support to percolate api
Browse files Browse the repository at this point in the history
Scoring support will allow the percolate matches to be sorted, or just assign a scores to percolate matches. Sorting by score can be very useful when millions of matching percolate queries are being returned.

The scoring support hooks in into the percolate query option and adds two new boolean options:
* `sort` - Whether to sort the matches based on the score. This will also include the score for each match. The `size` option is a required option when sorting percolate matches is enabled.
* `score` - Whether to compute the score and include it with each match. This will not sort the matches.

For both new options the `query` option needs to be specified, which is used to produce the scores. The `query` option is normally used to control which percolate queries are evaluated. In order to give meaning to these scores, the recently added `function_score` query in #3423 can be used to wrap the percolate query, this way the scores have meaning.

Closes #3506
  • Loading branch information
martijnvg committed Aug 14, 2013
1 parent 32cdddb commit 691ac8e
Show file tree
Hide file tree
Showing 8 changed files with 650 additions and 178 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,24 @@ public PercolateRequestBuilder setOnlyCount(boolean onlyCount) {
return this;
}

/**
* Limits the maximum number of percolate query matches to be returned.
*/
public PercolateRequestBuilder setSize(int size) {
sourceBuilder().setSize(size);
return this;
}

public PercolateRequestBuilder setSort(boolean sort) {
sourceBuilder().setSort(sort);
return this;
}

public PercolateRequestBuilder setScore(boolean score) {
sourceBuilder().setScore(score);
return this;
}

public PercolateRequestBuilder setSource(PercolateSourceBuilder source) {
sourceBuilder = source;
return this;
Expand Down Expand Up @@ -160,14 +178,6 @@ public PercolateRequestBuilder setPercolateFilter(FilterBuilder filterBuilder) {
return this;
}

/**
* Limits the maximum number of percolate query matches to be returned.
*/
public PercolateRequestBuilder setSize(int size) {
sourceBuilder().setSize(size);
return this;
}

private PercolateSourceBuilder sourceBuilder() {
if (sourceBuilder == null) {
sourceBuilder = new PercolateSourceBuilder();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentBuilderString;
import org.elasticsearch.rest.action.support.RestActions;

import java.io.IOException;
import java.util.Arrays;
Expand All @@ -46,23 +47,30 @@ public class PercolateResponse extends BroadcastOperationResponse implements Ite
private Match[] matches;
private long count;

public PercolateResponse(int totalShards, int successfulShards, int failedShards, List<ShardOperationFailedException> shardFailures, Match[] matches, long count, long tookInMillis) {
private boolean hasScores;

public PercolateResponse(int totalShards, int successfulShards, int failedShards, List<ShardOperationFailedException> shardFailures,
Match[] matches, long count, long tookInMillis, boolean hasScores) {
super(totalShards, successfulShards, failedShards, shardFailures);
this.tookInMillis = tookInMillis;
this.matches = matches;
this.count = count;
this.hasScores = hasScores;
}

public PercolateResponse(int totalShards, int successfulShards, int failedShards, List<ShardOperationFailedException> shardFailures, long count, long tookInMillis) {
super(totalShards, successfulShards, failedShards, shardFailures);
this.tookInMillis = tookInMillis;
this.matches = EMPTY;
this.count = count;
this.hasScores = false;
}

public PercolateResponse(int totalShards, int successfulShards, int failedShards, List<ShardOperationFailedException> shardFailures, long tookInMillis) {
super(totalShards, successfulShards, failedShards, shardFailures);
this.tookInMillis = tookInMillis;
this.matches = EMPTY;
this.hasScores = false;
}

PercolateResponse() {
Expand Down Expand Up @@ -104,23 +112,7 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.startObject();

builder.field(Fields.TOOK, tookInMillis);
builder.startObject(Fields._SHARDS);
builder.field(Fields.TOTAL, getTotalShards());
builder.field(Fields.SUCCESSFUL, getSuccessfulShards());
builder.field(Fields.FAILED, getFailedShards());
if (getShardFailures().length > 0) {
builder.startArray(Fields.FAILURES);
for (ShardOperationFailedException shardFailure : getShardFailures()) {
builder.startObject();
builder.field(Fields.INDEX, shardFailure.index());
builder.field(Fields.SHARD, shardFailure.shardId());
builder.field(Fields.STATUS, shardFailure.status().getStatus());
builder.field(Fields.REASON, shardFailure.reason());
builder.endObject();
}
builder.endArray();
}
builder.endObject();
RestActions.buildBroadcastShardsHeader(builder, this);

builder.field(Fields.TOTAL, count);
if (matches.length != 0) {
Expand All @@ -135,6 +127,9 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
builder.startObject();
builder.field(Fields._INDEX, match.getIndex());
builder.field(Fields._ID, match.getId());
if (hasScores) {
builder.field(Fields._SCORE, match.getScore());
}
builder.endObject();
}
}
Expand All @@ -156,6 +151,7 @@ public void readFrom(StreamInput in) throws IOException {
matches[i] = new Match();
matches[i].readFrom(in);
}
hasScores = in.readBoolean();
}

@Override
Expand All @@ -167,64 +163,70 @@ public void writeTo(StreamOutput out) throws IOException {
for (Match match : matches) {
match.writeTo(out);
}
out.writeBoolean(hasScores);
}

public static class Match implements Streamable {

private Text id;
private Text index;
private Text id;
private float score;

public Match(Text id, Text index) {
public Match(Text index, Text id, float score) {
this.id = id;
this.score = score;
this.index = index;
}

Match() {
}

public Text index() {
return index;
}

public Text id() {
return id;
}

public Text index() {
return index;
public float score() {
return score;
}

public Text getIndex() {
return index();
}

public Text getId() {
return id;
return id();
}

public Text getIndex() {
return index;
public float getScore() {
return score();
}

@Override
public void readFrom(StreamInput in) throws IOException {
id = in.readText();
index = in.readText();
score = in.readFloat();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
out.writeText(id);
out.writeText(index);
out.writeFloat(score);
}
}

static final class Fields {
static final XContentBuilderString _SHARDS = new XContentBuilderString("_shards");
static final XContentBuilderString TOTAL = new XContentBuilderString("total");
static final XContentBuilderString SUCCESSFUL = new XContentBuilderString("successful");
static final XContentBuilderString FAILED = new XContentBuilderString("failed");
static final XContentBuilderString FAILURES = new XContentBuilderString("failures");
static final XContentBuilderString STATUS = new XContentBuilderString("status");
static final XContentBuilderString INDEX = new XContentBuilderString("index");
static final XContentBuilderString SHARD = new XContentBuilderString("shard");
static final XContentBuilderString REASON = new XContentBuilderString("reason");
static final XContentBuilderString TOOK = new XContentBuilderString("took");
static final XContentBuilderString TOTAL = new XContentBuilderString("total");
static final XContentBuilderString MATCHES = new XContentBuilderString("matches");
static final XContentBuilderString _INDEX = new XContentBuilderString("_index");
static final XContentBuilderString _ID = new XContentBuilderString("_id");
static final XContentBuilderString _SCORE = new XContentBuilderString("_score");
}

}
Original file line number Diff line number Diff line change
@@ -1,3 +1,22 @@
/*
* 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.action.percolate;

import org.elasticsearch.action.support.broadcast.BroadcastShardOperationResponse;
Expand All @@ -14,40 +33,69 @@
public class PercolateShardResponse extends BroadcastShardOperationResponse {

private long count;
private float[] scores;
private Text[] matches;

// Request fields:
private boolean limit;
private int requestedSize;
private boolean sort;
private boolean score;

public PercolateShardResponse() {
}

public PercolateShardResponse(Text[] matches, long count, float[] scores, PercolatorService.PercolateContext context, String index, int shardId) {
super(index, shardId);
this.matches = matches;
this.count = count;
this.scores = scores;
this.limit = context.limit;
this.requestedSize = context.size;
this.sort = context.sort;
this.score = context.score;
}

public PercolateShardResponse(Text[] matches, long count, PercolatorService.PercolateContext context, String index, int shardId) {
super(index, shardId);
this.matches = matches;
this.scores = new float[0];
this.count = count;
this.limit = context.limit;
this.requestedSize = context.size;
this.sort = context.sort;
this.score = context.score;
}

public PercolateShardResponse(long count, PercolatorService.PercolateContext context, String index, int shardId) {
super(index, shardId);
this.count = count;
this.matches = StringText.EMPTY_ARRAY;
this.scores = new float[0];
this.limit = context.limit;
this.requestedSize = context.size;
this.sort = context.sort;
this.score = context.score;
}

public PercolateShardResponse(String index, int shardId) {
public PercolateShardResponse(PercolatorService.PercolateContext context, String index, int shardId) {
super(index, shardId);
this.matches = StringText.EMPTY_ARRAY;
this.scores = new float[0];
this.limit = context.limit;
this.requestedSize = context.size;
this.sort = context.sort;
this.score = context.score;
}

public Text[] matches() {
return matches;
}

public float[] scores() {
return scores;
}

public long count() {
return count;
}
Expand All @@ -60,23 +108,41 @@ public int requestedSize() {
return requestedSize;
}

public boolean sort() {
return sort;
}

public boolean score() {
return score;
}

@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
count = in.readVLong();
matches = in.readTextArray();
scores = new float[in.readVInt()];
for (int i = 0; i < scores.length; i++) {
scores[i] = in.readFloat();
}

limit = in.readBoolean();
requestedSize = in.readVInt();
sort = in.readBoolean();
}

@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVLong(count);
out.writeTextArray(matches);
out.writeVLong(scores.length);
for (float score : scores) {
out.writeFloat(score);
}

out.writeBoolean(limit);
out.writeVLong(requestedSize);
out.writeBoolean(sort);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ public class PercolateSourceBuilder implements ToXContent {
private QueryBuilder queryBuilder;
private FilterBuilder filterBuilder;
private Integer size;
private Boolean sort;
private Boolean score;

public DocBuilder percolateDocument() {
if (docBuilder == null) {
Expand Down Expand Up @@ -79,6 +81,16 @@ public PercolateSourceBuilder setSize(int size) {
return this;
}

public PercolateSourceBuilder setSort(boolean sort) {
this.sort = sort;
return this;
}

public PercolateSourceBuilder setScore(boolean score) {
this.score = score;
return this;
}

public BytesReference buildAsBytes(XContentType contentType) throws SearchSourceBuilderException {
try {
XContentBuilder builder = XContentFactory.contentBuilder(contentType);
Expand Down Expand Up @@ -106,6 +118,12 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
if (size != null) {
builder.field("size", size);
}
if (sort != null) {
builder.field("sort", sort);
}
if (score != null) {
builder.field("score", score);
}
builder.endObject();
return builder;
}
Expand Down
Loading

0 comments on commit 691ac8e

Please sign in to comment.