package org.apache.solr.search.field;
/*
* 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.
*/
import org.apache.lucene.index.AtomicReaderContext;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.util.BytesRef;
import org.apache.solr.core.HS;
import org.apache.solr.search.QueryContext;
import java.io.IOException;
public class StrComparatorNative extends FieldComparator<BytesRef> {
protected final QueryContext qcontext;
protected final StrTopValues topValues;
protected StrLeafValues strValues;
protected final int[] ords;
protected final long[] termPointers;
protected final int[] readerGen;
protected int currentReaderGen = -1;
protected int bottomSlot = -1; // only populated if the queue is full
protected int bottomOrd;
protected boolean bottomSameReader;
protected long bottomPointer;
protected BytesRef topValue;
protected boolean topSameReader;
protected int topOrd;
/** -1 if missing values are sorted first, 1 if they are
* sorted last */
protected final int missingSortCmp;
/** Which ordinal to use for a missing value. */
protected final int missingOrd;
/** Creates this, with control over how missing values
* are sorted. Pass sortMissingLast=true to put
* missing values at the end. */
public StrComparatorNative(FieldValues fieldValues, QueryContext qcontext, int numHits, boolean missingLast) {
this.qcontext = qcontext;
this.topValues = (StrTopValues) fieldValues.getTopValues(qcontext);
ords = new int[numHits];
termPointers = new long[numHits];
readerGen = new int[numHits];
if (missingLast) {
missingSortCmp = 1;
missingOrd = (Integer.MAX_VALUE-1);
} else {
missingSortCmp = -1;
missingOrd = -1;
}
}
public StrComparatorNative(StrComparatorNative prev) {
// order the same as declared
this.qcontext = prev.qcontext;
this.topValues = prev.topValues;
this.strValues = prev.strValues;
this.ords = prev.ords;
this.termPointers = prev.termPointers;
this.readerGen = prev.readerGen;
this.currentReaderGen = prev.currentReaderGen;
this.bottomSlot = prev.bottomSlot;
this.bottomOrd = prev.bottomOrd;
this.bottomSameReader = prev.bottomSameReader; // rely on setNextReader code to change this if necessary
this.bottomPointer = prev.bottomPointer;
this.topValue = prev.topValue;
this.topSameReader = prev.topSameReader;
this.topOrd = prev.topOrd;
this.missingSortCmp = prev.missingSortCmp;
this.missingOrd = prev.missingOrd;
}
@Override
public int compare(int slot1, int slot2) {
if (readerGen[slot1] == readerGen[slot2]) {
return ords[slot1] - ords[slot2];
}
long pointer1 = termPointers[slot1];
long pointer2 = termPointers[slot2];
if (pointer1 == 0) {
if (pointer2 == 0) {
return 0;
}
return missingSortCmp;
} else if (pointer2 == 0) {
return -missingSortCmp;
}
return HS.compareLengthPrefixBytes(pointer1, pointer2);
}
@Override
public int compareBottom(int doc) {
int docOrd = strValues.ordVal(doc);
if (docOrd < 0) {
docOrd = missingOrd;
}
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = strValues.ordVal(doc);
if (ord < 0) {
ord = missingOrd;
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
@Override
public FieldComparator<BytesRef> setNextReader(AtomicReaderContext readerContext) throws IOException {
strValues = (StrLeafValues)topValues.getLeafValues(qcontext, readerContext);
currentReaderGen++;
if (topValue != null) {
// Recompute topOrd/SameReader
int ord = (int)strValues.termToOrd(topValue);
if (ord >= 0) {
topSameReader = true;
topOrd = ord;
} else {
topSameReader = false;
topOrd = -ord-2;
}
} else {
topOrd = missingOrd;
topSameReader = true;
}
if (bottomSlot != -1) {
// Recompute bottomOrd/SameReader
setBottom(bottomSlot);
}
if (missingOrd < 0) {
if (strValues instanceof StrArrLeafValues) {
LongArray arr = ((StrArrLeafValues)strValues)._getDocToOrdArray();
if (arr instanceof LongArray8) {
return new Ord8(this);
} else if (arr instanceof LongArray16) {
return new Ord16(this);
} else if (arr instanceof LongArray32) {
return new Ord32(this);
}
} else if (strValues instanceof Str0Values) {
return new Ord0(this);
}
} else {
if (strValues instanceof StrArrLeafValues) {
LongArray arr = ((StrArrLeafValues)strValues)._getDocToOrdArray();
if (arr instanceof LongArray8) {
return new Ord8M(this);
} else if (arr instanceof LongArray16) {
return new Ord16M(this);
} else if (arr instanceof LongArray32) {
return new Ord32M(this);
}
} else if (strValues instanceof Str0Values) {
return new Ord0(this);
}
}
//return new StrComparator(this);
// return new AnyOrd(this);
return this;
}
@Override
public void setBottom(final int bottom) {
bottomSlot = bottom;
bottomPointer = termPointers[bottomSlot];
if (currentReaderGen == readerGen[bottomSlot]) {
bottomOrd = ords[bottomSlot];
bottomSameReader = true;
} else {
if (bottomPointer == 0) {
// missingOrd is null for all segments
assert ords[bottomSlot] == missingOrd;
bottomOrd = missingOrd;
bottomSameReader = true;
readerGen[bottomSlot] = currentReaderGen;
} else {
final int ord = (int)strValues.termPointerToOrd(bottomPointer);
if (ord < 0) {
bottomOrd = -ord - 2;
bottomSameReader = false;
} else {
bottomOrd = ord;
// exact value match
bottomSameReader = true;
readerGen[bottomSlot] = currentReaderGen;
ords[bottomSlot] = bottomOrd;
}
}
}
}
@Override
public void setTopValue(BytesRef value) {
// null is fine: it means the last doc of the prior
// search was missing this value
topValue = value;
//System.out.println("setTopValue " + topValue);
}
@Override
public BytesRef value(int slot) {
long ptr = termPointers[slot];
if (ptr == 0) {
return null;
}
BytesRef val = new BytesRef();
HS.copyLengthPrefixBytes(ptr, val);
return val;
}
@Override
public int compareTop(int doc) {
int ord = strValues.ordVal(doc);
if (ord == -1) {
ord = missingOrd;
}
if (topSameReader) {
// ord is precisely comparable, even in the equal
// case
//System.out.println("compareTop doc=" + doc + " ord=" + ord + " ret=" + (topOrd-ord));
return topOrd - ord;
} else if (ord <= topOrd) {
// the equals case always means doc is < value
// (because we set lastOrd to the lower bound)
return 1;
} else {
return -1;
}
}
@Override
public int compareValues(BytesRef val1, BytesRef val2) {
if (val1 == null) {
if (val2 == null) {
return 0;
}
return missingSortCmp;
} else if (val2 == null) {
return -missingSortCmp;
}
return val1.compareTo(val2);
}
public static class Ord0 extends StrComparatorNative {
public Ord0(StrComparatorNative prev) {
super(prev);
}
@Override
public int compareBottom(int doc) {
int docOrd = missingOrd;
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
ords[slot] = missingOrd;
termPointers[slot] = 0;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord8 extends StrComparatorNative {
final LongArray8 longArr;
final long arr;
public Ord8(StrComparatorNative prev) {
super(prev);
longArr = (LongArray8) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getByte(arr, doc) - 1;
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getByte(arr, doc) - 1;
if (ord < 0) {
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord8M extends StrComparatorNative {
final LongArray8 longArr;
final long arr;
public Ord8M(StrComparatorNative prev) {
super(prev);
longArr = (LongArray8) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getByte(arr, doc) - 1;
if (docOrd < 0) {
docOrd = missingOrd;
}
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getByte(arr, doc) - 1;
if (ord < 0) {
ord = missingOrd;
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord16 extends StrComparatorNative {
final LongArray16 longArr;
final long arr;
public Ord16(StrComparatorNative prev) {
super(prev);
longArr = (LongArray16) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getShort(arr, doc) - 1;
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getShort(arr, doc) - 1;
if (ord < 0) {
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord16M extends StrComparatorNative {
final LongArray16 longArr;
final long arr;
public Ord16M(StrComparatorNative prev) {
super(prev);
longArr = (LongArray16) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getShort(arr, doc) - 1;
if (docOrd < 0) {
docOrd = missingOrd;
}
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getShort(arr, doc) - 1;
if (ord < 0) {
ord = missingOrd;
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord32 extends StrComparatorNative {
final LongArray32 longArr;
final long arr;
public Ord32(StrComparatorNative prev) {
super(prev);
longArr = (LongArray32) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getInt(arr, doc) - 1;
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getInt(arr, doc) - 1;
if (ord < 0) {
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class Ord32M extends StrComparatorNative {
final LongArray32 longArr;
final long arr;
public Ord32M(StrComparatorNative prev) {
super(prev);
longArr = (LongArray32) ((StrArrLeafValues)strValues)._getDocToOrdArray();
arr = longArr.getNativeArray();
}
@Override
public int compareBottom(int doc) {
int docOrd = HS.getInt(arr, doc) - 1;
if (docOrd < 0) {
docOrd = missingOrd;
}
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = HS.getInt(arr, doc) - 1;
if (ord < 0) {
ord = missingOrd;
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
public static class AnyOrd extends StrComparatorNative {
public AnyOrd(StrComparatorNative prev) {
super(prev);
}
@Override
public int compareBottom(int doc) {
int docOrd = strValues.ordVal(doc);
if (docOrd < 0) {
docOrd = missingOrd;
}
if (bottomSameReader) {
// ord is precisely comparable, even in the equal case
return bottomOrd - docOrd;
} else if (bottomOrd >= docOrd) {
// the equals case always means bottom is > doc
// (because we set bottomOrd to the lower bound in
// setBottom):
return 1;
} else {
return -1;
}
}
@Override
public void copy(int slot, int doc) {
int ord = strValues.ordVal(doc);
if (ord < 0) {
ord = missingOrd;
termPointers[slot] = 0;
} else {
termPointers[slot] = strValues.ordToTermPointer(ord);
}
ords[slot] = ord;
readerGen[slot] = currentReaderGen;
}
}
}