org.elasticsearch.search.controller.ShardFieldDocSortedHitQueue Maven / Gradle / Ivy
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch 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.controller;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.FieldDoc;
import org.apache.lucene.search.SortField;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.PriorityQueue;
import org.elasticsearch.ElasticsearchIllegalStateException;
import java.io.IOException;
/**
*
*/
// LUCENE TRACK, Had to copy over in order ot improve same order tie break to take shards into account
public class ShardFieldDocSortedHitQueue extends PriorityQueue {
volatile SortField[] fields = null;
// used in the case where the fields are sorted by locale
// based strings
//volatile Collator[] collators = null;
FieldComparator[] comparators = null;
/**
* Creates a hit queue sorted by the given list of fields.
*
* @param fields Fieldable names, in priority order (highest priority first).
* @param size The number of hits to retain. Must be greater than zero.
*/
public ShardFieldDocSortedHitQueue(SortField[] fields, int size) {
super(size);
setFields(fields);
}
/**
* Allows redefinition of sort fields if they are null
.
* This is to handle the case using ParallelMultiSearcher where the
* original list contains AUTO and we don't know the actual sort
* type until the values come back. The fields can only be set once.
* This method should be synchronized external like all other PQ methods.
*
* @param fields
*/
public void setFields(SortField[] fields) {
this.fields = fields;
//this.collators = hasCollators(fields);
try {
comparators = new FieldComparator[fields.length];
for (int fieldIDX = 0; fieldIDX < fields.length; fieldIDX++) {
comparators[fieldIDX] = fields[fieldIDX].getComparator(1, fieldIDX);
}
} catch (IOException e) {
throw new ElasticsearchIllegalStateException("failed to get comparator", e);
}
}
/**
* Returns the fields being used to sort.
*/
SortField[] getFields() {
return fields;
}
/**
* Returns whether a
is less relevant than b
.
*
* @param docA ScoreDoc
* @param docB ScoreDoc
* @return true
if document a
should be sorted after document b
.
*/
@SuppressWarnings("unchecked")
@Override
protected final boolean lessThan(final FieldDoc docA, final FieldDoc docB) {
final int n = fields.length;
int c = 0;
for (int i = 0; i < n && c == 0; ++i) {
final SortField.Type type = fields[i].getType();
if (type == SortField.Type.STRING) {
final BytesRef s1 = (BytesRef) docA.fields[i];
final BytesRef s2 = (BytesRef) docB.fields[i];
// null values need to be sorted first, because of how FieldCache.getStringIndex()
// works - in that routine, any documents without a value in the given field are
// put first. If both are null, the next SortField is used
if (s1 == null) {
c = (s2 == null) ? 0 : -1;
} else if (s2 == null) {
c = 1;
} else { //if (fields[i].getLocale() == null) {
c = s1.compareTo(s2);
}
// } else {
// c = collators[i].compare(s1, s2);
// }
} else {
c = comparators[i].compareValues(docA.fields[i], docB.fields[i]);
}
// reverse sort
if (fields[i].getReverse()) {
c = -c;
}
}
// avoid random sort order that could lead to duplicates (bug #31241):
if (c == 0) {
// CHANGE: Add shard base tie breaking
c = docA.shardIndex - docB.shardIndex;
if (c == 0) {
return docA.doc > docB.doc;
}
}
return c > 0;
}
}