add sort values as part of the response per search hit

This commit is contained in:
kimchy 2010-08-08 18:21:17 +03:00
parent 7cb2010dda
commit 37af7f5aef
4 changed files with 123 additions and 0 deletions

View File

@ -134,6 +134,16 @@ public interface SearchHit extends Streamable, ToXContent, Iterable<SearchHitFie
*/
Map<String, HighlightField> getHighlightFields();
/**
* An array of the sort values used.
*/
Object[] sortValues();
/**
* An array of the sort values used.
*/
Object[] getSortValues();
/**
* The shard of the search hit.
*/

View File

@ -171,6 +171,21 @@ public class SearchPhaseController {
}
public InternalSearchResponse merge(ShardDoc[] sortedDocs, Map<SearchShardTarget, ? extends QuerySearchResultProvider> queryResults, Map<SearchShardTarget, ? extends FetchSearchResultProvider> fetchResults) {
boolean sorted = false;
int sortScoreIndex = -1;
QuerySearchResult querySearchResult = Iterables.get(queryResults.values(), 0).queryResult();
if (querySearchResult.topDocs() instanceof TopFieldDocs) {
sorted = true;
TopFieldDocs fieldDocs = (TopFieldDocs) querySearchResult.queryResult().topDocs();
for (int i = 0; i < fieldDocs.fields.length; i++) {
if (fieldDocs.fields[i].getType() == SortField.SCORE) {
sortScoreIndex = i;
}
}
}
// merge facets
InternalFacets facets = null;
if (!queryResults.isEmpty()) {
@ -223,6 +238,15 @@ public class SearchPhaseController {
InternalSearchHit searchHit = fetchResult.hits().internalHits()[index];
searchHit.score(shardDoc.score());
searchHit.shard(fetchResult.shardTarget());
if (sorted) {
FieldDoc fieldDoc = (FieldDoc) shardDoc;
searchHit.sortValues(fieldDoc.fields);
if (sortScoreIndex != -1) {
searchHit.score(((Number) fieldDoc.fields[sortScoreIndex]).floatValue());
}
}
hits.add(searchHit);
}
}

View File

@ -49,6 +49,8 @@ import static org.elasticsearch.search.internal.InternalSearchHitField.*;
*/
public class InternalSearchHit implements SearchHit {
private static final Object[] EMPTY_SORT_VALUES = new Object[0];
private transient int docId;
private float score = Float.NEGATIVE_INFINITY;
@ -63,6 +65,8 @@ public class InternalSearchHit implements SearchHit {
private Map<String, HighlightField> highlightFields = ImmutableMap.of();
private Object[] sortValues = EMPTY_SORT_VALUES;
private Explanation explanation;
@Nullable private SearchShardTarget shard;
@ -195,6 +199,18 @@ public class InternalSearchHit implements SearchHit {
this.highlightFields = highlightFields;
}
public void sortValues(Object[] sortValues) {
this.sortValues = sortValues;
}
@Override public Object[] sortValues() {
return sortValues;
}
@Override public Object[] getSortValues() {
return sortValues();
}
@Override public Explanation explanation() {
return explanation;
}
@ -274,6 +290,13 @@ public class InternalSearchHit implements SearchHit {
}
builder.endObject();
}
if (sortValues != null && sortValues.length > 0) {
builder.startArray("sort_values");
for (Object sortValue : sortValues) {
builder.value(sortValue);
}
builder.endArray();
}
if (explanation() != null) {
builder.field("_explanation");
buildExplanation(builder, explanation());
@ -391,6 +414,31 @@ public class InternalSearchHit implements SearchHit {
highlightFields = builder.build();
}
size = in.readVInt();
if (size > 0) {
sortValues = new Object[size];
for (int i = 0; i < sortValues.length; i++) {
byte type = in.readByte();
if (type == 0) {
sortValues[i] = null;
} else if (type == 1) {
sortValues[i] = in.readUTF();
} else if (type == 2) {
sortValues[i] = in.readInt();
} else if (type == 3) {
sortValues[i] = in.readLong();
} else if (type == 4) {
sortValues[i] = in.readFloat();
} else if (type == 5) {
sortValues[i] = in.readDouble();
} else if (type == 6) {
sortValues[i] = in.readByte();
} else {
throw new IOException("Can't match type [" + type + "]");
}
}
}
if (shardLookupMap != null) {
int lookupId = in.readVInt();
if (lookupId > 0) {
@ -439,6 +487,41 @@ public class InternalSearchHit implements SearchHit {
highlightField.writeTo(out);
}
}
if (sortValues.length == 0) {
out.writeVInt(0);
} else {
out.writeVInt(sortValues.length);
for (Object sortValue : sortValues) {
if (sortValue == null) {
out.writeByte((byte) 0);
} else {
Class type = sortValue.getClass();
if (type == String.class) {
out.writeByte((byte) 1);
out.writeUTF((String) sortValue);
} else if (type == Integer.class) {
out.writeByte((byte) 2);
out.writeInt((Integer) sortValue);
} else if (type == Long.class) {
out.writeByte((byte) 3);
out.writeLong((Long) sortValue);
} else if (type == Float.class) {
out.writeByte((byte) 4);
out.writeFloat((Float) sortValue);
} else if (type == Double.class) {
out.writeByte((byte) 5);
out.writeDouble((Double) sortValue);
} else if (type == Byte.class) {
out.writeByte((byte) 6);
out.writeByte((Byte) sortValue);
} else {
throw new IOException("Can't handle sort field value of type [" + type + "]");
}
}
}
}
if (shardLookupMap == null) {
if (shard == null) {
out.writeBoolean(false);

View File

@ -88,7 +88,9 @@ public class SimpleSortTests extends AbstractNodesTests {
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
assertThat((String) searchResponse.hits().getAt(0).field("id").value(), equalTo("1"));
assertThat(searchResponse.hits().getAt(0).sortValues()[0].toString(), equalTo("aaa"));
assertThat((String) searchResponse.hits().getAt(1).field("id").value(), equalTo("2"));
assertThat(searchResponse.hits().getAt(1).sortValues()[0].toString(), equalTo("bbb"));
searchResponse = client.prepareSearch()
.setQuery(matchAllQuery())
@ -128,7 +130,9 @@ public class SimpleSortTests extends AbstractNodesTests {
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
assertThat((String) searchResponse.hits().getAt(0).field("id").value(), equalTo("1"));
assertThat(((Number) searchResponse.hits().getAt(0).sortValues()[0]).longValue(), equalTo(100l));
assertThat((String) searchResponse.hits().getAt(1).field("id").value(), equalTo("2"));
assertThat(((Number) searchResponse.hits().getAt(1).sortValues()[0]).longValue(), equalTo(200l));
searchResponse = client.prepareSearch()
.setQuery(matchAllQuery())
@ -148,7 +152,9 @@ public class SimpleSortTests extends AbstractNodesTests {
assertThat(searchResponse.hits().getTotalHits(), equalTo(2l));
assertThat((String) searchResponse.hits().getAt(0).field("id").value(), equalTo("2"));
assertThat(((Number) searchResponse.hits().getAt(0).sortValues()[0]).longValue(), equalTo(200l));
assertThat((String) searchResponse.hits().getAt(1).field("id").value(), equalTo("1"));
assertThat(((Number) searchResponse.hits().getAt(1).sortValues()[0]).longValue(), equalTo(100l));
searchResponse = client.prepareSearch()
.setQuery(matchAllQuery())